Rendering deformed Spline with Hair material



  • Hi,

    I've always rendered my splines with Hair materials. After adding some custom modifiers, I simply cannot render anything anymore. Again, let's dive into old forum topics and start making tests to try and learn how things work.

    At first I learned that the relationship between GetContour() and GetVirtualObjects() has always been a hot topic, not mentioned anywhere in the docs. I discovered that by sending nullptr to GetVirtualObjects(), it will eventually try GetContour(). Because I have OBJECT_GENERATOR and OBJECT_ISSPLINE defined, to generate either a poly or a spline, based on parameters chosen by the user.

    About spline and deformers, here's what I discovered...

    • SplineObject returned by GetContour(): OK (rendered by Hair material)
    • SplineObject returned by GetVirtualObjects(): NOK (cannot be rendered by Hair material)
    • SplineObject returned by GetContour() + C4D Deformer (Twist): NOK
    • SplineObject returned by GetVirtualObjects() + C4D Deformer (Twist): NOK
    • SplineObject returned by GetContour() + custom Deformer: NOK
    • SplineObject returned by GetVirtualObjects() + custom Deformer: NOK
    • Native spline object (Circle) + C4D Deformer (Twist): NOK
    • Native spline object (Circle) + custom Deformer: NOK
    • C4D Hair + C4D Deformer (Twist): Can render, but not deformed
    • C4D Hair with the Deformers flag enabled + C4D Deformer (Twist): OK!!

    So... looks like the Hair material does not render modified splines. Why? Is that a limitation or a bug?

    But the C4D native hair has a Deformers flag that enables rendering of the deformed splines. How can it do it? I need that too!

    EDIT: Some curious findings about C4D Hair object...

    • When it has a deformer inside, instead of not rendering at all, it renders undeformed splines.
    • There's an option in the Hair object (Generate, Type) that when set to Spline, will not render hair (deformed or not).
    • There's actually nothing in the Hair Object cache looking at c4dsdk's Active Object Properties, unless we set it to Generate Splines. If it's not caching splines, then what?


  • Hi Roger,

    sorry come coming with a little bit of delay here, but actually the question was not that easy to address.

    The "Deformers" flag enabled in the Advanced tab of Cinema Hair actually execute something like:

    • create a dummy spline for each hair based on the hair definition
    • deform the dummy spline by applying the modifier stack found under the hair object
    • use the deformed spline data to overwrite the hair primitive

    What is important to note is that in the end what is actually rendered is still an hair primitive and not the deformed spline.
    As additional note the hairs are not represented in the scene as real geometry that's why you can't find any evidence in the Active Object Dialog since the hair renderer is not handling with 3D data but delivers a representation of hair in 2.5D space where geometry is not needed.
    Finally the primitives which can be currently rendered are those satisfying the following expression (obj is the object being evaluated by the hair renderer)

    obj->GetType() == HAIR_STYLE_OBJECT_ID || 
    obj->IsInstanceOf(Opolygon) || 
    obj->IsInstanceOf(Ospline) || 
    obj->IsInstanceOf(Oline)) || 
    obj->IsInstanceOf(Oparticle) || 
    obj->GetType() == ID_TP_PARTICLEGEOMETRY
    

    That said since I see no reason to deny deformed splines to be rendered by the hair renderer, I'm going to file a bug report on this regard.

    Best, Riccardo



  • Hi Riccardo,

    Thanks for the explanation.

    While a deformed spline primitive like the Circle will not render, if I make it editable, turning it into an Ospline, it will finally render. Both have a line object in the deform cache, so I don't understand what object is being checked.

    I really need to render custom deformed splines, if that's a bug I hope we can have it fixed soon. I tested back to R16 and the same happens. The hair solution you mentioned sounds like too much work just to render line objects that C4D is expected to render.



  • @rsodre said in Rendering deformed Spline with Hair material:

    While a deformed spline primitive like the Circle will not render, if I make it editable, turning it into an Ospline, it will finally render. Both have a line object in the deform cache, so I don't understand what object is being checked.

    Hi Roger, you've totally tackled the issue, both their caches contain LineObject but not their generator: the first (the circle primitive) returns fail when checking IsInstanceOf(Oline) and on IsInstanceOf(Ospline) the other instead return true on IsInstanceOf(Ospline).

    I'll let you know about the bug being fixed, but actually it's priority might be assessed as low.

    Best, Riccardo



  • But should a spline primitive like Circle return true on IsInstanceOf(Ospline)? Or is it returning false the expected behaviour?

    Is there a way to make my custom generator return true to IsInstanceOf(Ospline)?



  • Hi roger,

    it's pretty straightforward to test your question by using the Python console:
    creating a circle and executing op.IsInstanceOf(c4d.Ospline): returns false
    creating a circle and executing op.GetRealSpline().IsInstanceOf(c4d.Ospline): returns true

    Is there a way to make my custom generator return true to IsInstanceOf(Ospline)?

    Yes, just implement NodeData::IsInstanceOf()

    Best, Riccardo



  • @r_gigante said in Rendering deformed Spline with Hair material:

    it's pretty straightforward to test your question by using the Python console:
    creating a circle and executing op.IsInstanceOf(c4d.Ospline): returns false

    Sure, I did that and got to that conclusion, I'm asking if that's expected behaviour, because it seems wrong to me. Just like an Ocube and every other polygon primitive are instance of Obase, I would expect that Ocircle and other spline primitives would be instance of Ospline.



  • Hi roger, thanks for following up.

    With regard to your last objection I confirm this is the right and intended behavior.
    Let me reformulate your example: given a Cube primitive, being it a generator, it indeed returns true to both IsInstanceOf(Ocube) and IsInstanceOf(Obase) - the generator is any case inheriting from BaseObject - but it will return false to IsInstanceOf(Opolygon) cause we're check if the actual generator, and not its cache, is allowed, for instance, to cast in a PolygonObject.
    Using the same parallelism given an Arc primitive, being it a generator, it indeed returns true to both IsInstanceOf(Oarc) and IsInstanceOf(Obase) but it will return false to IsInstanceOf(Ospline) cause also in this case is the cache allowed to be cast in a SplineObject not the generator itself.

    Hope this help to get a better understanding on the whole topic.

    Best, Riccardo



  • @r_gigante Yes, it's clear now. Thanks!



  • Hey @r_gigante ,

    Got back to this issue, I'm trying what I think is the fastest and easier path first, to create a new pure spline in the end of my modifier chain. But still no luck...

    I am sure the new spline is not being marked as dependence and is not being touched. Even though there's no deformers inside it, it has a deform cache. If I put the spline outside of my object, it will render, but I can still see it's got a deform cache. So maybe that's not the problem.

    The same does not happen for polygons, any polygon that I include inside the object or modifiers are rendered (of course, they are not touched), unlike the splines.

    Looks like the determinant factor to render the spline is the presence of OBJECT_INPUT on my generator (modifiers and end spline are inside it). Just removing this from the object register makes my spline render.
    What exactly is it doing to the children?
    Can I still create and use dependence lists if I remove it?



  • @r_gigante said in Rendering deformed Spline with Hair material:

    What is important to note is that in the end what is actually rendered is still an hair primitive and not the deformed spline.
    As additional note the hairs are not represented in the scene as real geometry that's why you can't find any evidence in the Active Object Dialog since the hair renderer is not handling with 3D data but delivers a representation of hair in 2.5D space where geometry is not needed.

    @r_gigante , when you say it draws in 2.5D space, do you mean the Hair Render post?

    At this moment, I'm interested in how to efficiently draw thousands of strands in the viewport. I suspect the LineStripBegin/End are not very efficient in this case. When Cinema 4D draws guides and hair in the viewport, does it use the same ObjectData::Draw() method we use?
    Can I use a VidePostData::GlDraw() to draw to the viewport instead?



  • Hi Roger thanks for following up and happy new year!

    I'm going to punctually get back to you:

    @rsodre said in Rendering deformed Spline with Hair material:

    @r_gigante , when you say it draws in 2.5D space, do you mean the Hair Render post?

    Exactly

    When Cinema 4D draws guides and hair in the viewport, does it use the same ObjectData::Draw() method we use?

    With regard to guides/hair, the hair library found in Cinema 4D indeed uses BaseDraw::LineStripBegin() / BaseDraw::LineStrip() / BaseDraw::LineStripEnd() methods to represent them in viewport.

    Can I use a VidePostData::GlDraw() to draw to the viewport instead?

    Not actually, if the strands are meant to appear in viewport.
    An example on how to use VideoPostData::GlDraw() is available here

    Best, Riccardo



  • @r_gigante said in Rendering deformed Spline with Hair material:

    With regard to guides/hair, the hair library found in Cinema 4D indeed uses BaseDraw::LineStripBegin() / BaseDraw::LineStrip() / BaseDraw::LineStripEnd() methods to represent them in viewport.

    I find this odd, because the my performance is very poor compared to the native C4D hair, using the same amount of strands. Using the undocumented vertex buffers made my drawing operations up to 3 times faster. With that I have some new display issues, but I think is a different topic to discuss...



  • Hi Roger, thanks for your follow-up.

    In order to be of any further help, would you consider to show the part of your code where you're using the BaseDraw::Line* methods?

    With regard to

    Using the undocumented vertex buffers made my drawing operations up to 3 times faster.

    I guess you're referring to use the VideoPostData::GlDraw(). Not being a static method how are you making use of it to display your strands in viewport? Am I missing something hereabout the context?

    Last but not least, please consider opening a new thread, since the discussion about strand representation in viewport is going to be off-topic.

    Best, Riccardo



  • @r_gigante I mean GlProgramFactory and GlVertexBuffer.
    My issues are explained here.



  • Hi Roger, sorry for coming late here.

    Unfortunately, with regard to the two highlighted classes, I can spend any further information rather than what's already included in c4d_gl.h

    If there are no further question, I'd consider, and then mark, this thread as solved.

    Best, Riccardo



  • Hi Riccardo,

    Since there's an open bug report regarding the main issue, shouldn't we keep it open until bug is investigated?


Log in to reply