Generating Hair [SOLVED]



  • On 24/03/2015 at 06:55, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R16 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hi all,

    I'm working on a c++ plugin which extracts certain types of scene data. Long story short, I have a HairObject from the scene and want the curves for each generated hair strand. For instance, with a hair object that has HAIRSTYLE_HAIR_COUNT = 1000 and HAIRSTYLE_HAIR_SEGMENTS = 3, I'd end up with 4000 points arranged into segments.

    If I force generation by setting HAIRSTYLE_GENERATE to HAIRSTYLE_GENERATE_SPLINE (through the hair object's properties panel in C4D) I get the results I want as a LineObject in the hairobject's cache. This data works fine for my purposes. However, I don't want a theoretical user of my plugin to have to do this manually. For one thing, it tends to kill C4D performance on the one large example I have here. I would like to generate this data on demand when the plugin command is launched.

    I was hoping the HairObject::GenerateHair function would do the trick, but I haven't been able to pass it any arguments that don't result in a crash. Besides which, it seems to generate a HairGuides object rather than the LineObject I would expect.

    Hope this is possible, and that someone out there has experience with this! Thanks in advance,
    - Sean



  • On 24/03/2015 at 08:30, xxxxxxxx wrote:

    Hello,

    The cache is only filled when a generator is used inside a document. So one way could be to create a virtual BaseDocument, copy that hair object and all dependencies into that document and call ExecutePasses(). This way you can do to the Hair object anything you like.

    Another way is indeed to use GenerateHair(). To use that function you have to lock the hair object. The returned HairGuides object than also contains the data for all hair strands if that data was created. This can look like this:

      
    HairObject * hair = (HairObject* )object;   
      
    hair->Lock(doc, nullptr, false, 0);                
    HairGuides * guides = hair->GenerateHair();              
    hair->Unlock();                    
      
    const Int32 pointCount = guides->GetPointCount();           
    const Int32 segPointCount = guides->GetGuidePointCount();     
      
    Vector* hairpoints = guides->GetPoints();                         
      
    BaseObject * parent = nullptr;      
      
    for(Int32 pointIndex = 0; pointIndex < pointCount; ++pointIndex)           
    {                  
      Int32 localIndex = pointIndex % segPointCount;  
      
      if(localIndex == 0)                   
      {                       
          // a new guide starts  
      }      
      
      const Vector pos = hairpoints[pointIndex];      
    }  
    

    best wishes,
    Sebastian



  • On 25/03/2015 at 06:32, xxxxxxxx wrote:

    This is perfect, thanks a lot Sebastian!

    Now I'm trying to retrieve the color and thickness information. I'm not having much luck with the hair materials. I've got the BaseTag of type HAIRMATERIAL_TAG_LINK and get the HairMaterialData pointer with GetParameter/GetLink. I don't really know where to go from here, though.

    The GetColor and GetThickness methods on the HairMaterialData are kind of daunting, and seem like overkill somehow. It seems like I should be able to call GetParameter on some object with HAIRMATERIAL_THICKNESS_ROOT/TIP and HAIRMATERIAL_COLOR_GRADIENT to get the colors.

    Could you give a little example of how to use the methods on HairMaterialData, or how to access this information through GetParameter somehow?

    Thanks again,
    - Sean



  • On 25/03/2015 at 11:21, xxxxxxxx wrote:

    Hello,

    actually, you can get the HairMaterialData object when you call GenerateHair() (the fourth parameter). Using GetParmeter() etc. you can only read the parameters; the hair color can be defined by a shader and may vary from hair to hair. So I think you have to GetThickness() and GetColor() as these functions are made to get the proper values for each hair.

    Best wishes,
    Sebastian



  • On 26/03/2015 at 05:12, xxxxxxxx wrote:

    Thanks again,

    I hadn't realized the HairMaterialData parameter was an output parameter for GenerateHairs. That might be handy. As I say, though, I have already found pointers to the correct materials by following the HAIRMATERIAL_TAG_LINK on the hair material BaseTag objects of the hair.

    I've messed around with GetThickness and GetColor and I still can't quite work them out.
    GetColor needs world coordinates of the root and the sample point on the hair, as well as the surface normal at the root and a RayHitId.
    I can't even work out how to retrieve the color on an extremely simple example. For instance, I have a few hairs on a plane object and I thought I would be able to get the color at the base of the first hair with something like:

    Vector color = hairMat->GetColor(0, 0.0, guides->GetPoints()[0], guides->GetPoints()[0], Vector(0,0,0), Vector(0,1,0), nullptr, RayHitID(), -1);
    

    This does give me a color (a light brown), but it does not appear to have any relation to either of the colors in the material property gradient (in the example I use, they are set to orange and red). Changing the t parameter to 1.0 instead of 0.0 does not seem to make a difference.

    I had hoped that GetThickness would give better results, but this method seems to return 1.0 regardless of input. For instance, I would have imagined that the following loop would give the "root" and "tip" thickness values from the material:

                  for(int i=0; i<guideCount; i++) {  
                  root = hairMat->GetThickness(i, 0.0f);  
                  tip = hairMat->GetThickness(i, 1.0f);  
                }  
    

    Instead it seems I get nothing but 1.0.

    By messing around a bit I did actually succeed in retrieving parameters from the material properties with GetParameter. I was previously put off by the fact that the HairMaterialData class does not inherit GetParameter from C4DAtom. The SDK still confuses me like this sometimes.

    So I now have more or less the values I want. However, it does seem like some of the methods in HairMaterialData would be useful to let C4D calculate some of the more complex material assignment cases for me, so any comments on the problems I describe above would be much appreciated.

    Regards,
    - Sean



  • On 26/03/2015 at 07:37, xxxxxxxx wrote:

    Hello,

    using the HairMaterialData object from GenerateHair() I have no problem with GetThickness(). Also GetColor() seems to work mostly. Since these methods are made to be used in a rendering context it can be tricky to construct the right parameters. But it seems that something like this can also work to get at least the basic color for each hair:

      
    color = materialData->GetColor(counter,guidePos,Vector(),Vector(),Vector(),Vector(),nullptr, RayHitID());  
    

    best wishes,
    Sebastian



  • On 10/10/2015 at 12:52, xxxxxxxx wrote:

    Hi,
    I'm posting my issue to this post due to don't want to open a new discussion about this.

    Atm i'm using GenerateHair() to produce hairs out of video post. But i don't have any success to get proper UV per hair strands.

    guides->GetRootUV(i) is giving ZERO for each one. But it's fine when i use in videopost. Can you help for this problem?
    
    
      
    
    
    
    Thanks!
    


  • On 12/10/2015 at 02:48, xxxxxxxx wrote:

    Hello,

    if I use GetRootUV() between Lock() and Unlock() it seems to work fine.

    Best wishes,
    Sebastian



  • On 12/10/2015 at 08:25, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Hello,

    if I use GetRootUV() between Lock() and Unlock() it seems to work fine.

    Best wishes,
    Sebastian

    😊

    Wow! You saved my life, thanks!


Log in to reply