Re-performing Hair Edit > Convert from Spline Command?



  • Hi,

    In learning the Hair API, I'm trying to re-perform the Hair Edit > Convert from Spline Command.
    Basically, you select a spline and it gets converted to a hair object.

    My main bottleneck is the SetGuide which I believe creates guides in hair object.
    HairObject.SetGuides(guides, clone)

    The problem is the c4d.modules.hair.HairGuides doesn't have an initialize command which I need to

    1. Define the points
    2. Define the position of the guide

    Is there a way around this?

    Regards,
    Ben



  • hi,

    the set guides just define the guide, but you have to create them before.

    I've create this more generic example. From this, you should be able to create the guide from the spline.

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    
    # Main function
    def main():
        # Creates the guides
        guideCnt = 10
        segmentPerGuide = 4
        pointsPerGuide = segmentPerGuide +1
        
        guides = c4d.modules.hair.HairGuides(guideCnt, segmentPerGuide)
        if guides is None:
            raise ValueError("coudln't create the guides")
    
        x = 0
        xspace = 10
        yspace = 10
        # set the points position of the guides.
        for guideIndex in range(guideCnt):
            # space each guide
            x += xspace
            for spid in range(pointsPerGuide):
                # Calculate the vertical position of each point
                pPos = c4d.Vector (x, yspace * spid, 0 )
                # get the index of that point in the global guide array
                pIndex = guideIndex * pointsPerGuide  + spid
                # Sets the point
                guides.SetPoint( pIndex, pPos )
        
        
        # Creates the Hair Object 
        hairObj = c4d.BaseObject(c4d.Ohair)
        
        # Sets the previously created guide to this hair object.
        hairObj.SetGuides(guides, False)
        
        # Inserts the hairObject in the document
        doc.InsertObject(hairObj, None, None)
        
        # Inserts an update event in the stack
        c4d.EventAdd()
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    after looking the result you need a bit more information about the command.

    the convert spline to hair is using the function UniformToNatural to convert bezier curves.
    It also take into account any hair tag that could change the render look of the spline.

    Cheers,
    Manuel



  • @m_magalhaes

    Thanks for the response. I was able to create guides but it doesn't seem to follow the original position of the splines.
    You can see the problem here:
    https://www.dropbox.com/s/g3qw5t7ueyqnlxp/c4d283_recreate_convert_from_spline_hair.mp4?dl=0

    Some general notes

    1. Spline's position is at world zero, so there's no reason for offset.
    2. There seems to be a stray point (i.e. it doesn't follow the original spline's vector position)

    Here is the sample file:
    https://www.dropbox.com/s/uovawaui1gdz7rs/c4d283_recreate_convert_from_spline_hair.c4d?dl=0

    Here is the code so far:

    import c4d
    from c4d import gui
    
    # Main function
    def main():
        spline = doc.SearchObject("spline")
        guide_count = spline.GetSegmentCount()
    
        segment_per_guide = 9
        points_per_guide = segment_per_guide
        spline_points = spline.GetAllPoints()
        
        guides = c4d.modules.hair.HairGuides(guide_count, segment_per_guide) 
        
        for guide_index in range(guide_count):
            idx = 0
            for spid in range (points_per_guide):
                point_index = guide_index * points_per_guide  + spid
                
                if idx <= len(spline_points) - 1:
                    guides.SetPoint(point_index, spline_points[point_index])
                    idx += 1
                else:
                    guides.SetPoint(point_index[-1], spline_points[-1]) # This was made to address the stray point but it is still a stray point. lol 
    
        hair = c4d.BaseObject(c4d.Ohair)
        hair.SetGuides(guides, False)
    
        doc.InsertObject(hair, None, None)
    
        c4d.EventAdd()
    
               
        
    # Execute main()
    if __name__=='__main__':
        main()
    


  • hi,

    hair guide are exactly as spline, they have points, segment.
    My example was more generic of course and that's why there was an offset on it.
    (we try sometimes to create more generic example so we can add them on github later)

    look at the following example, it does what you are looking for.

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    
    # Main function
    def main():
        spline = op
        if spline is None:
            raise ValueError("there's no object selected")
        if not spline.IsInstanceOf(c4d.Ospline):
            raise ValueError("select a spline")
        # we can use a SplineLengthData to use the UniformToNatural function
        sld = c4d.utils.SplineLengthData()
        # Retrieves the spline matrix
        splineMg = spline.GetMg()
        
        segCount = spline.GetSegmentCount()
        # number of point in a segment is number of segment +1
        segmentPerGuide = 4
        pointsPerGuide = segmentPerGuide + 1
        # Creates the guides
        guides = c4d.modules.hair.HairGuides(segCount, segmentPerGuide)
        
        # for each segment of the spline
        for segIndex in range(segCount):
            # initialize the splineLenghtData with the current segment
            sld.Init(spline, segIndex)
            for i in range(pointsPerGuide):
                # for each point of the guide, calculate the position for that point
                pos = spline.GetSplinePoint(sld.UniformToNatural(i / float(segmentPerGuide) ), segIndex)
                # Calculates the points index on the guides points
                pointIndex = segIndex * (pointsPerGuide ) + i
                # Sets the point position in global space
                pos = splineMg * pos
                guides.SetPoint( pointIndex, pos )
                
        # Creates the Hair Object 
        hairObj = c4d.BaseObject(c4d.Ohair)
        
        # Sets the previously created guide to this hair object.
        hairObj.SetGuides(guides, False)
        
        # Inserts the hairObject in the document
        doc.InsertObject(hairObj, None, None)
        
        # Inserts an update event in the stack
        c4d.EventAdd()
    
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    Cheers,
    Manuel



  • @m_magalhaes

    Thanks! It works as expected.
    So that's what you mean by UniformToNatural. Basically, even if the segment guides are not the same as spline points, it will conform to its overall shape.


Log in to reply