Solved 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

MAXON SDK Specialist

MAXON Registered Developer

@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

MAXON SDK Specialist

MAXON Registered Developer

@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.