Jump to content

Voronoi - dynamic - location based fracture (WIP)


johner

Recommended Posts

So there is another test. I know that particle peaces are to much big but Im working on it. There I need glue RBD GLUE OBJECT with static objects. Little problem there dissapear. Why on some fractured stonec flipping texture. In this case I use concrete shader. Fractured object has REST sop, so where is problem? thanks a lot.... BC

test_RBD_02.mov

Link to comment
Share on other sites

  • 5 weeks later...

A quick update on this. A bit of research informed me I don't actually want a Voronoi decomposition, I want the Delaunay tetrahedralization (naturally), which is the dual of the Voronoi decomposition. If you have this tetrahedralization, then a given Voronoi cell point will share edges with only those other points that are adjacent Voronoi cells, which is exactly the information the Fracture SOP needs to do the proper amount of clipping.

...

This is obviously a little more complicated in 3D. CGAL has an implementation of Delaunay tetrahedralization, as well as Python bindings, so I wrote a quick Python SOP to generate the tetrahedralization with CGAL, sort the incident vertices for each Voronoi cell point by distance, and store the results in the nearest, numnearest attributes. This worked nicely, speeding things up by 50-75% (actually less than I expected), and more importantly, generating artifact free results, since the Fracture SOP was always doing the proper amount of clipping. As a reference point, the Python SOP using CGAL takes less than 2 seconds to execute on 2000 input points, which is plenty sufficient performance.

Now, obviously I don't want to introduce a dependency on CGAL into this asset.

Hi johner,

I work in the CGAL project. Just out of curiosity, what is the motivation for not creating a dependency on CGAL. Are the licenses incompatible?

Is the open source license we have chosen too restrictive? If this feature was essential Houdini could escape from an open source obligation,

buy the Voronoi diagram, and distribute binaries of the plugin without that users need to install CGAL.

best regards,

andreas

Link to comment
Share on other sites

Hi johner,

I work in the CGAL project. Just out of curiosity, what is the motivation for not creating a dependency on CGAL. Are the licenses incompatible?

Is the open source license we have chosen too restrictive? If this feature was essential Houdini could escape from an open source obligation,

buy the Voronoi diagram, and distribute binaries of the plugin without that users need to install CGAL.

best regards,

andreas

I just started trying to compile CGAL in windows for this purpose itself :-D , Tho I'm still having trouble getting it to compile, damn boost.

Link to comment
Share on other sites

Hi johner,

I work in the CGAL project. Just out of curiosity, what is the motivation for not creating a dependency on CGAL. Are the licenses incompatible?

Is the open source license we have chosen too restrictive? If this feature was essential Houdini could escape from an open source obligation,

buy the Voronoi diagram, and distribute binaries of the plugin without that users need to install CGAL.

best regards,

andreas

Hi Andreas,

Thanks for checking in and for the information. My desire to avoid a dependency on CGAL is really just a question of distribution, not licensing. There's not much code in the asset/plugin being described here, but the Python code that is there is open for anyone's use.

The problem is that if you implement a Houdini node in C++, distributing binaries of it becomes tricky as Houdini supports many different operating systems and SideFX makes daily builds available. For this reason, most people in the community who develop such tools make the source available and it's often up to the user to compile it for their particular platform. Any code that has external dependencies becomes that much more complicated to compile, as you can see from the message after yours in the forum here.

Another option for developing new nodes in Houdini is to use Python, as every installation of Houdini comes with an embedded Python interpreter. If you can write the code using the Python standard libraries and the Houdini Python interface, then your tool is pretty much guaranteed to run everywhere without any compilation or version conflicts.

In this case, I could get away with a slower, less robust, pure Python implementation of Delaunay tetrahedralization because my needs for it were very specific: jittering the points on input to get them to "general position" was acceptable, and it turns out the tetrahedralization is not the bottleneck as you increase the number of input points to the fracture operation, cutting the geometry is. While it might make sense in the future to make a C++ Tetrahedralization node that is very fast and robust using something like CGAL, in this particular case it I didn't want to introduce a dependency on a large library, no matter its quality, for a specific problem that could be solved in Python with no dependencies.

But let me say while you're here, I've gotten a lot of great use from CGAL in the past, and it was extremely helpful to me in the development of this tool for both testing and as a reference implementation, so many thanks!

  • Like 1
Link to comment
Share on other sites

Quick favor to ask: I'm in the process of finally putting together an official release of this thing to put on the Exchange, and the most recent daily Houdini builds seem to break some of the dynamic fracturing. As of 10.0.359, none of the secondary pieces seem to fracture on my machine (64-bit Linux, gcc 4.1), but it works fine under 10.0.295. Before I spend too much time tracking this down, could someone with a recent build confirm the same problem?

To test, just load up the dynamic_fracture_examples.hip file that comes with the latest release and run the "basic_dynamic_fracture" DOPNet. Attached is what frame 45 or so should look like. The two big pieces that break off after the initial fracture have fractured again here. With 359 those secondary pieces don't fracture. If anyone has a version earlier than 359 that has the same problem, I'd be interested to know that as well.

Thanks!

post-2001-125004362292_thumb.png

Link to comment
Share on other sites

Hey there. First off, I am still pretty new to houdini so I could be doing this the complete wrong way. I wanted to fracture something twice. The first time would be to divide an object into two large groups. I would use one part of the object as a static RBD object and the other group would be fractured again and made an RBD glue object. I am trying to simulate the breaking of the side of cliff. I figured it would be best to ask this question here since I am using the otl. I also thought of using a dynamic location based fracture and a dummy object to essentially crush the portion I wanted to break. If someone could take a look at my file and maybe rework it or let me know what I can do to make this work, I would really really appreciate it. Thanks in advance :)

By the way, thanks for creating this Johner! The shatter tool is terrible! Also, this inspired me to read a bit about Delaunay triangulation and start to understand the Voronoi algorithm. I still have no clue what half of anything means, and the "dual graph" really frightens me. Maybe someday I'll understand it!

double_fracture.hip

Link to comment
Share on other sites

Hey there. First off, I am still pretty new to houdini so I could be doing this the complete wrong way. I wanted to fracture something twice. The first time would be to divide an object into two large groups. I would use one part of the object as a static RBD object and the other group would be fractured again and made an RBD glue object. I am trying to simulate the breaking of the side of cliff. I figured it would be best to ask this question here since I am using the otl. I also thought of using a dynamic location based fracture and a dummy object to essentially crush the portion I wanted to break. If someone could take a look at my file and maybe rework it or let me know what I can do to make this work, I would really really appreciate it. Thanks in advance :)

By the way, thanks for creating this Johner! The shatter tool is terrible! Also, this inspired me to read a bit about Delaunay triangulation and start to understand the Voronoi algorithm. I still have no clue what half of anything means, and the "dual graph" really frightens me. Maybe someday I'll understand it!

Hi Jason,

Sorry it took me a few days to get to this; I'm out of town currently.

Well, in a case like this you could probably just get away with one fracture operation and some carefully placed points, but you certainly should be able to fracture pieces multiple times. The problem with your network is actually due to what could be considered a bug in the Fracture SOP, namely that it always tries to create "outside" and "inside" groups, and if you send a fractured piece back through the Fracture SOP, those groups already exist and one of the Group SOPs within the OTL throws an error. That error is not visible at the top-level, unfortunately, so it just sort of fails silently. I should probably fix the OTL to delete any "inside" and "outside" groups on the incoming geo, or make creating those groups an option or something.

The fix at the moment is to just use another Group SOP before the second Fracture SOP to delete or rename the "inside" and "outside" groups to something else. Then there's no internal error and the Fracture SOP should work. Also it's probably worth using different "group prefix" settings in the Fracture SOP so the first set of fractures are called "piece_base_2" or whatever and the second is "piece_cliff_4", etc.

I modified your file with these fixes and put a simple DOPnet in there that just pulls in the base as a Static Object and cliff pieces as a Fractured Object. You can do it with Glue objects or even give it a try with the dynamic fracturing, although for a choreographed break like this, pre-fracturing is usually the way to go.

Good luck.

double_fracture_renamed.hipnc

Link to comment
Share on other sites

First off, John, I'd like to say... I love you.. :P

It's fast, simple, and your examples provide clear insight to your methods. Also, I love the links you provided throughout the thread to help people understand how you arose at your solutions.

I have some other questions relating to the shading of these surfaces. (This might be a topic for another thread)

If I have Connect Inside Edges on and Cusp Interior Edges off, I will get a closed surface (no faceted faces). If I render this, I get shading artifacts at the edges. I'm wondering if there's a solution using creaseweights that would allow these surfaces to shade smoothly over creases. The reason I ask is because I would like to add true displacements to my surfaces and I can't do that with faceted faces.

Maybe we can add creaseweights to the edges on the exterior pieces? I'll see if I can whip up an example of what I mean.

Link to comment
Share on other sites

Ahhh... Mantra 9 and vertex normals.

Check out the attached example to see seamless displacement by attrib transferring vertex normals from a faceted geometry to a non-faceted geometry.

The attrib transfer is happening in a foreach loop, to provide more accurate results. This might be slow to add to the fracture otl, but would it be worth adding it and making it a toggle? I would think so! ;)

post-2072-125116073775_thumb.jpg

post-2072-125116073857_thumb.jpg

fracture_vertex_normals.hip

Link to comment
Share on other sites

If I have Connect Inside Edges on and Cusp Interior Edges off, I will get a closed surface (no faceted faces). If I render this, I get shading artifacts at the edges. I'm wondering if there's a solution using creaseweights that would allow these surfaces to shade smoothly over creases. The reason I ask is because I would like to add true displacements to my surfaces and I can't do that with faceted faces.

Hi Francisco,

Thanks for the kind words (and the love :) ). Your post is a good kick in my pants to address rendering the output of the Fracture SOP, which I've been meaning to do for a while. As you obviously know, rendering polygons with true displacement has its challenges, especially when trying to maintain somewhat sharp corners.

You are correct that turning on "Connect Inside Edges" and off "Cusp Interior Edges" will give you a completely closed, non-faceted surface. If you then leave "Automatically Compute Normals" on at the object level, Houdini will compute smooth normals over the entire object and you can use the standard displacement shaders and get true displacement without cracking. Your example with these settings looks like this:

smooth_displaced.png

The problem is you lose any sharp corners and it generally doesn't look so great. Your solution of using Vertex Normals is better, but if you render close up, it looks like this:

vertex_N_cracking.png

As you can see you've got cracking going on here, because the points at the edges are still being displaced in their normal directions and away from each other. So you really need to displace along a direction that will be the same for the points along the edges whether the polys are faceted or not, then compute a new normal that takes into account the faceted nature of the geometry.

Fortunately that's very doable in Houdini / Mantra. One way is to use a low-frequency noise vector based on rest position as the direction for the displacement, then use calculateNormal to compute a new normal for shading, taking the displaced position, the original "smooth" normal computed by Houdini, and geometric normal into account. All of which is easier than it sounds: just plug the displaced P into a ShadingNormal VOP and output the new N from the displacement shader.

I slightly modified the displacement part of the stock Concrete shader in this way and rendered a quick fractured sphere falling on the ground. Below are the two frames right before and right after the initial hit, without motion blur (animation here):

no_scale_displace.png

So you get true displacement along the fracture lines and in the interior, without cracking. I had to up the shading rate and the z-importance to get enough micropolys to render with minimal artifacts, since calculateNormal uses derivatives to compute the new normals, and the more micropolys the better for that.

I think another interesting thing to do in the context of fracture is to add a "scale" attribute to the points that controls the overall displacement scale in the shader, then set it close to zero at the exterior surface and a higher value on the interior points. So you'll get more displacement the deeper inside the surface you go as the value is interpolated across the polygon. The same sim above rendered this way looks like this (apologies for the gross/purely-for-visualization colors - the displacement is more obvious in the animation here):

scaled_displace.png

You can also bricker the "inside" polygons or something to add interior points to make the interpolation occur nearer the surface, although in both these cases you have to be careful to avoid artifacts where the interior surface is displaced outside the exterior. A smarter choice of displacement vector might improve this; I need to explore this more (and I'm *very* open to suggestions from the shader people out there).

You're absolutely correct that I should add some functionality to the Fracture SOP to make rendering the output easier. Making this example made me realize that a few more point groups would be really useful, such as all inside points on the edge with the exterior, all outside points on the edge, etc. Here I've created the attributes with a ForEach SOP just to experiment and be able to switch the rendering easily, but I think it should really be done inside the Fracture SOP.

Anyway, this is just a first test of this stuff, and I'd be interested in hearing if people have thoughts on ways to improve it. I'd like to figure out the most useful groups/attributes to add to the output geometry to make rendering displacement easier, then provide a couple of examples with the release. One of the obvious shortcomings of this type of fracture is the planar cuts and interior surfaces, so anything that can help overcome that at render time would be useful, I think.

render_tests.hip

Link to comment
Share on other sites

Good observations! The transferring normal attribs method, though not accurate and has artifacts, can still work for objects in the MG and BG. I definitely agree that this is not the best solution.

If we had more control over vertices (vertex groups, vertex normals, etc), I'd imagine that we'd be able to pass the shader customized vertex normals per point. We'd probably still get some of that stretching at the corners, but there may be other possiblities (just brainstorming out loud). Unfortunately, we don't have access to this in SOPs.

Another idea would be to bevel the interior faces to minimize the amount of displacement artifacts. A procedural way to do this wouldn't be feasible, since we don't have access to edge prims!

My last thought would be to apply creaseweights to the vertices, since Mantra 9+ supports the creaseweight attribute. I'm curious to run a few simple tests, unless someone can show me that it's not the right approach.

Anyways, keep 'em coming! Just thought I'd share some ideas.

Link to comment
Share on other sites

I think another interesting thing to do in the context of fracture is to add a "scale" attribute to the points that controls the overall displacement scale in the shader, then set it close to zero at the exterior surface and a higher value on the interior points. So you'll get more displacement the deeper inside the surface you go as the value is interpolated across the polygon.

I've been thinking more about ways of adding detail to the fractured surfaces at the geometry level, and realized that (smacks head), of course you can use the same scale attribute as a parameter to a Vex SOP instead and use it to add noise and detail to the geometry itself, after doing a Bricker of just the "inside" polys after the fracture operation (so each pair of incident faces will be split at coincident points). So it could be a post-process and could be fine-tuned after the fracture operation.

Simon's trick from early on in the thread of deforming the geo before fracturing and then snapping back to the interpolated rest positions can add variation along the fracture line itself, so combined you could (optionally) get geometry out of the Fracture SOP that looks much less like it was cut with a planar Clip operation.

Anyway, attached is a quick example frame and flipbook here. The "scale" parameter is being visualized in the viewport with a white-red ramp.

I need to experiment some more, but it's encouraging...

post-2001-125126521154_thumb.png

Link to comment
Share on other sites

I've been thinking more about ways of adding detail to the fractured surfaces at the geometry level, and realized that (smacks head), of course you can use the same scale attribute as a parameter to a Vex SOP instead and use it to add noise and detail to the geometry itself, after doing a Bricker of just the "inside" polys after the fracture operation (so each pair of incident faces will be split at coincident points). So it could be a post-process and could be fine-tuned after the fracture operation.

OK, I made a first pass at adding interior detail with noise to the Fracture SOP. It's not quite ready to be released, but the results are encouraging. The basic algorithm is fairly straightforward and all a post-process after the main fracture:

1) Bricker the interior surface polygons to add detail.

2) Ray SOP (set to MinDistance) the interior points to the original surface of the geometry, giving the "depth" of each interior point within the original geometry.

3) AttribPromote to get maxdepth for normalization purposes.

4) Normalize each point's depth to 0-1 and run it through a user-customizable ramp to map depth from surface to a scale factor for the noise about to be applied.

5) Optionally visualize that noise scale.

6) Add noise to all the points - as long as depth 0 is mapped to noisescale 0 only the interior points will be displaced.

Attached is a screenshot (of a piece of a fractured sphere if it's not clear), and I finally figured out how to do a screencast to show a possible workflow. There's one pause in that screencast while the RBD sim runs, but that's it. So, more testing and such before a release, but initial results with concave geometry and such are good. This doesn't address the fact that all the surface cuts are still planar, of course, but it's a start. Also, the planar surface cuts seem a little less noticeable when there's noise on the interior.

Edit: quick concave object test here.

post-2001-125134192345_thumb.png

Edited by johner
Link to comment
Share on other sites

Hey Johner,

Great work on this otl man, I've been playing around with it for the past few days and it is awesome!

I have a couple of questions, What it the best method to get the simulated fractured geo (from a dynamic fracture sim) back from DOP's into SOP's? or is your intention to render direct from DOP's.

Again, great work!

Chris

Link to comment
Share on other sites

2) Ray SOP (set to MinDistance) the interior points to the original surface of the geometry, giving the "depth" of each interior point within the original geometry.

3) AttribPromote to get maxdepth for normalization purposes.

Or (smacking head harder), use an SDF for the depth calculation, since that's exactly what they're defined to do!

Benefits:

-only has to be calculated once for static geometry

-volumesample faster than Ray SOP

-don't need AttributePromote to find maxdepth, use -volumemin

-consistent reporting of maxdepth for entire geometry when working with individual pieces (like in screencast)

-possibly add option to bias displacement away from surface using volumegradient

-allows smooth clamping of interior displacement to surface, stopping interior/surface interpenetrations

-possibly add optional 3rd input to Fracture SOP for pre-calc'd SDF, allows reuse of collision SDF in dynamic fracturing

-....

Drawbacks:

-have to expose one or two of the IsoOffset controls to the Fracture SOP controls

-feel stupid for not having thought of it immediately

Hey Johner,

Great work on this otl man, I've been playing around with it for the past few days and it is awesome!

I have a couple of questions, What it the best method to get the simulated fractured geo (from a dynamic fracture sim) back from DOP's into SOP's? or is your intention to render direct from DOP's.

Again, great work!

Chris

Thanks! You can just use a DOPImport SOP, with the ObjectMask set to the names of the dynamic objects (say "obj_*" in the basic_fracture_example referenced above) and the Import Style set to "Fetch Geometry from DOP Network"

I would display the Geo through the DOPNet and use a Geometry object purely for rendering (i.e put it's Display flag on a Null SOP, but it's Render flag on the DopImport SOP or its output)

Edited by johner
Link to comment
Share on other sites

wow John, that interior detail stuff looks great, great idea.

I got a question, is that the final geo for DOPs?, or is still the "low res" geo the one you pass to DOPs?

actually it could be a good idea to have both options.

anyway, great project man, keep it up

Thank you

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...