From BlenderWiki

Jump to: navigation, search
Note: This is an archived version of the Blender Developer Wiki. The current and active wiki is available on wiki.blender.org.

Fracture Modifier Proposal

Ideas By:

Martin Felke, Kai Kostack, Lukas Tönne, Sergej Reich, JT Nelson, Dennis Fassbaender.

Methods:

Prefractured

The user triggers a new fracture step. Existing shards can be refractured to build up a fracture hierarchy. This is used to construct compounds in bullet and determines the way, in which the object will break apart later. You can also „flatten“ the hierarchy to let all shards break in the same level, means they will fall apart regardless of hierarchy, on collision. A compound disconnection step is triggered by the simulation. If it is performed, a new rendermesh will be created, deleting inner geometry of cells having still all of their initial neighbors. (neighborhood info is provided by voro++ in the first place) Additionally the geometry will be welded to hide unwanted cracks. This can happen in a limited area, e.g via an animated helper object, so a dynamic crack hiding can be achieved. A compound solution has advantages over constraints. Constraints „wobble“ the shards around and need high solver iterations to be solid. Many constraints slow down the simulation massively. Disadvantage is the faked, manual detection of potential disconnectable childs, that happens automatically with constraints.

Dynamic

The simulation starts with the intact object or a starting set of shards. On contact / interaction a fracture step is triggered, actually performing a new fracture of the affected shards. All fracture will happen in object space, the sim transform will be undone before. Fracture will be executed with pointbased algorithms, preferrably. This is so because randomness is more important in this case than exact predefined fracture. After fracture the sim transform will be re-applied to all shards, and local centroid offsets will be added to each shard. In dynamic case there is no need for compounds or crack hiding, because the geometry is created on demand during the simulation. If dynamic fracture starts with a starting set, this is compounded. Only if the compound child is disconnected from the compound (check via parent or for neighborhood connectedness to avoid holes) dynamic fracture will be enabled for it.

Algorithms:

Pointbased

Fracturing can happen based on a pointcloud. Those points will be passed together with the bounding box of the object to voro++, which generates raw data representing the bounding box separated into voronoi cells according to the points of the pointcloud. To obtain a fractured shape, each cell has to be intersected with the whole original geometry (speedup ? Certain faces ?) This happens usually with Carve / Boolean functionality for watertight meshes, but it is planned to have a fallback mechanism to bisect with scanfill, bisect with edgenet fill or bisect without fill, in that order. This is done to ensure bad mesh geometry (non-manifold, overlap) can be handled as well by fracture. The user can choose the start algorithm and which fallbacks he wants to try out as well.

Edgebased

Another method of fracture is based on a set of fracture edges. With this the user can control the lines of fracture in a direct way instead of just defining centroids indirectly like in the pointbased case. Edges can be obtained by direct user interaction like cutting the mesh (greasecut, knife...) or via helper meshes obtained from extruded curves or even vectorized images. There will be a similar fallback mechanism, with boolean meshes first and sectional bisect second. Sectional bisect should allow non-straight cuts by slicing the mesh and rotate bisection planes, as well as applying them to each section in a way a connected, jagged cut is done.

Volumebased

This is primarily a helper method to allow partial destruction of objects. Both of the above methods can be applied to a helper volume, which will be boolean subtracted from the intact mesh. So it looks like only a part of the object is destroyed. Boolean cutters can also be used for round cuts.

Predefined

Existing islands can be directly used as shards. Island detection can also be performed after fracture, per cell, to aggregate tiny islands (or leave them separate)

Deformation support (later)

A softbody emulator can fake limited deformation of geometry by moving nearby verts according to collision / interaction forces (forcefields...) Impact / interaction forces can be propagated over a uniform grid or an adaptive octree. Grid Cell contents will be moved accordingly to the force calculated for the cell. Denser mesh areas can maybe considered as more stable. This should all ensure neighbors deform in a matching way. (need neighborhood info from voro++ or calculate by searchradius...) The verts could be moved in a limited way e.g only as close as next neighbor maybe. Find neighbors via bmesh walkers or search radius of collision / interaction points


Implementation:

Passive Modifier

A passive, single Fracture Modifier handles storage and display of the fractured mesh, which is represented as Bmesh to allow simple editing. This is necessary for refracturing in both the prefractured and the dynamic case. Because of raw data handling simple elementwise mesh creation is necessary. The modifier or the pointcache can store a fracture history in dynamic case. Also it can store backups for prefracture steps in a FracHistory struct. A Rendermesh is a DerivedMesh without „intact“ inner geometry and with welded verts.

Core

  • Fracmesh represents a fracture container, full of shards.
  • Operators execute Fracture methods and manipulate Shards.
  • voro++ decomposes bbox to cells (by rebuilding it cell by cell from raw data)
  • intersect those with boolean or bisect to get actual shape of object to build fracmesh and shards
  • Fracmesh is initialized from Derivedmesh passed into modifier, 1 shard being the entire object.
  • A parent / group id for logical shard groups / levels can serve as compound hierarchy template for bullet (per Shard)
  • Later levels of destruction, use cells or even use simple default primitives, Limits for this can be: below a certain size or above a certain count or both, childcount, depth...
  • Can be selected from a group for variety; they simplify collision shapes.

Compounding

The compound structure is a parenting hierarchy. All cells of a level are parented to a shard in the center of mass. If there is no appropriate shard, an invisible ghost shard will be used as compound parent (ghost via collision groups) Which children will be disconnected is determined by stability thresholds for each shard, which can e.g. depend on their mass directly, and via a search radius around the contact points (centroid wise, or even vertex wise, need to find closest verts of cell regarding to impact point, check whether majority of it is affected, percentage... ?)

Compound will be „reparented“ to new child if parent element is disconnected compound dissolve calculation could be done via relative speed / searchradius / mass / thresholds... to emulate constraints

In a refracturing step a shard gets a new id after existing ones; split shards get invalid... (refs are invalid as well) because the Bmesh has changed.... The shards store refs to verts, edges faces directly of their according bmesh parts.

Additionally, to avoid having parts hanging in the air, a connectivity test via neighborhood info from voro++ or via neighborhood grid as fallback can be performed. Lone neighbors or grid cells will be disconnected from compounds automatically this way.

Automerge

  • To hide unwanted cracks dynamically (glass, smooth objects), maybe limited by animated helper object, crack growth by increasing helper object size
  • Need to find inner faces of shards who still have all their neighbors, delete those and weld the geometry as rendermesh,
  • Automerge is triggered by fractures (dyna), compound break (pre) or timebased
  • Animation of helper object maybe via image colors / gradients (to control speed) Hmm, keyframes are more flexible... but this could be taken from image directly...

Bad geometry tests

  • nonmanifold test, volume / area comparision … overlap detector (3d printing)
  • fallback methods: boolean → bisect scanfill → bisect edgenet → bisect open
  • select what should be tried if failures happen, select start algorithm
  • keep backup if method needs to be retried

Island detection

  • prior to fracture, instead of fracture (existing islands), after fracture per cell
  • to combine or split small objects, via size / count / limit with halving algorithm, faster than standard separate by loose

Misc

  • project svg or vectorized raster / curves into 3d, use mesh as boolean cutter / bisect (hard).
  • Dynamic compound dissolve via force, extend searchradius.
  • Dynafrac: force can manipulate pointcloud shape / density / size.
  • point clouds are formed by: randompoints over bbox, according to pattern maybe, helper geometry, helper particlesystem,
  • Extend MOD_boolean_utils, so no temp object is required (its for matrix only ?)
  • hmm bmesh for fracmesh (joined ?) yes,
  • UV / customdata handling with boolean and bisect

UI / Tools

  • The physics tab contains operators (for now), nodes later ?
  • It contains Presets for fracture patterns (regular, radial, random, per geometry, per particle) and object materials (solidity).
  • Settings for shard count for step, inner material.
  • Settings for dynafrac limits: global count, bounding volume size (min), per cell count (children, hierarchy depth) face / vertex count glob / loc, combine those to prevent fracturing if condition fails, select in advanced tab, make presets available.
  • Soft dynafrac limit: set an exponent to calculate threshold = impulse ^ exponent
  • Algorithm / fallback selector.
  • Object roles for helper objects can be defined: destroyer, destroyable → trigger, timebased activation (simulation part; but maybe for dynafrac).
  • Automerge distance as setting, keeping cracks visible...

Editmode

  • Temporary Handle Objects are not useful, they allow simple editing but clutter up the blend main database.
  • Would need to be generated from fracmesh (open container) and commited back (close container)
  • Active index simple solution for accessing shards, temporarily. Modifier limits display to shard with selected index, so operators can be applied on that.
  • A proper editmode would allow to select islands via 3D view, and multiselect.

Simulation integration

  • particle / dupli integration: duplis fetch collision shape from fracmesh via shard id
  • Invisible helper objects for faking certain effects („amplified“ simulation e.g) colliders, forcefields...vs. too many tool settings

Pointcache integration (Mesh)

  • FracHistory (dyna): shard maps and mesh states in modifier or pointcache / alembic
  • framemap triggers history change if no sim feedback is there
  • will be invalidated with entire cache if objects are moved
  • cache might grow big, and caching might use much cpu time as well, so keep it optional for direct sim rendering... (for very big sims)
  • caching speed slow on hdd (non SSD) so keep optional for big sims
  • cache precalculation: expected size, shards x frames pre, dyna → according to frames and limit preset

Fracture storage

  • need own mesh struct for storage; BMesh / DerivedMesh cant be easily put into DNA...
  • that struct would store raw data like coords and face indexes
  • need converter methods for those structs to build BMesh and / or DerivedMesh from raw data
  • can be very slow because save and load methods are more often called than just at storage to disk / load from disk, each undo ?
  • could use a mesh ID block for this additionally, but this adds unnecessary temporary blocks to main database and clutters it, removing such blocks is a bit nontrivial...
  • could extend mesh ID block by logical shard groupings, so all happens just in the mesh, but would require lots of changes elsewhere possibly
  • editmode could be extended to handle those shards at display (island mode button ?)
  • alternatively use alembic pointcache ?

Fracture storage possible solution

  • extend object to store a mesh container, allowing multiple mesh states like a history
  • each fracture step adds a new mesh history state with own shardmap, effectively grouping to islands
  • each fracture undo step removes a mesh history state, "repairs" the fractured shard again
  • a reset operator restores the base mesh and purges the history
  • the object.data must transparently store one of the history states, mostly the last one, or even always
  • the object is an existing ID block
  • the mesh is an existing ID block
  • each mesh state contains a mesh and a shardmap, aka FracMesh
  • this saves the modifier, if meshes are swapped intelligently; first mesh state and last (fracture on and off operator)
  • saves conversions to derivedmesh
  • solves the writefile / readfile storage problem
  • but DNA structs for object need to be updated, as well as storage functions
  • hmm this is like a modifier stack on its own... but "hidden"
  • one temporary bmesh still needed for fracturing itself, to be constructed from raw data, converted to mesh and deleted again

Link to sourcecode repository

https://github.com/scorpion81/blender-fracture