Jump to content

Bones from multiple curves?


Recommended Posts

Is it possible to create bones from multiple curve primitives?

I am creating multiple curves with the add sop than when I run "bones from curve" button on the shelf it creates bones only for the last curve primitive.I tried to look for the python script for this command so I can modify it but couldn't find it.

Anyone have an idea how I can automate creation of the bones on multiple curves?

And one more question:

Is it possible to paint the wire capture per curve primitive if I have multiple curves?The default setup it doesn't give me a way to paint but I think this should be possible trough paint node and attribute create.The problem is that I can't get it to work.Any ideas how I can do that?

Edited by T.I.M.
Link to comment
Share on other sites

So I tried to write a shelf tool that fetch each curve primitive to separate obj,since the "bones from curve" doesn't work in SOP level. And than my idea was to loop trough each Geo and run the command "bones to curve" .But the looping just doesn't work.I thought that this is maybe related to the fact that you have to exit from currentState for the tool but I am not sure if I am doing it right since there is no documentation on this. Am I doing something wrong or this is just not possible?Maybe I have to write my own Bones to curves function...?I think this is very basic thing and SESI should make the default tool to work on multiple curve primitives.

Hope someone can help me with that.

You have to select the multiple curves in sop level before run it:

import hou
import objecttoolutils
import toolutils

def timBonesfromCurves():

  sel = hou.selectedNodes()[0]
  obj = hou.node("obj")
  geo = sel.geometry()
  prim = geo.prims()



  for j,i in enumerate(prim):
    p = obj.createNode("geo","curveFetch")
    p.setPosition((0,-j))
    p.node("file1").destroy()
    f = p.createNode("object_merge")
    f.parm("objpath1").set(sel.path())
    d = f.createOutputNode("delete")
    d.setRenderFlag(1) 
    d.setDisplayFlag(1)
    d.parm("negate").set(1)
    d.parm("pattern").set(str(j))
    p.setSelected(1)

    #This part just doesn't work in this loop:
    objecttoolutils.customStateTool(kwargs, 'bonesfromcurve')
    #pane.enterViewState()




timBonesfromCurves()

Link to comment
Share on other sites

Guest mantragora

With this:

import hou
import toolutils


def UserInput():
    sv = toolutils.sceneViewer()
    curves = sv.selectObjects('Select curves, press enter to accept', allowed_types=('geo', ))
    if curves == ():
        hou.ui.displayMessage('Curves not selected, terminating tool', severity=hou.severityType.Error)
        return None

    return curves


def BonesfromCurves_Tool(kwargs):
    curves = UserInput()
    if curves == None:
        return

    for curve in curves:
        print(curve)
        curve.setSelected(1)
        toolutils.genericStateTool(kwargs, 'bonesfromcurve')

if you select couple geo nodes that contains curve, for example 2, it will create "bonesfromcurve" only for last one in the list/loop. It print both curves, so it looks that last loop operation is translated as 'enter confirmation'. I don't know is there a way to "simulate enter" for genericStateTool() somehow.

Edited by mantragora
Link to comment
Share on other sites

Why you create object merge ? you got selected nodes so why not just loop thru them ?

I hope | understand your question. What I am doing actually in my case is that I am extracting curves from geometry by using add sop witch generates multiple curve primitives.I'm not using merge node. Than I need to create bone chain for each curve primitive.So I got the script to the point that creates multiple geo nodes for each curve primitive the problem is that the "bones from curve" command doesn't work in the loop.So my question is how I can automate the creation of "bones from curve" for each curve primitive because right now this command doesn't work in the loop.I have a lot curve primitives and will be crazy to go and apply the command one by one.

I saw in the SESI forum that someone asked how we can paint the wire capture. http://www.sidefx.com/index.php?option=com_forum&Itemid=172&page=viewtopic&t=25826&highlight=wire+capture

If there is some simple way to do that this will be great and the creation of bones will be unnecessary in my case. I just couldn't get this to work well for multiple curves.It kind of works for one curve but if you have many curves close to each other it fails. If someone can post some example on this will be really great.

Edit:Obviously I misunderstood your question.Sorry sometimes my English sucks :)

I am creating object merge because "Bones From curve" works in object level.And than I want each bone chain to follow each curve witch can't happen if I don't have them in separate object.

Edited by T.I.M.
Link to comment
Share on other sites

With this:

import hou
import toolutils


def UserInput():
    sv = toolutils.sceneViewer()
    curves = sv.selectObjects('Select curves, press enter to accept', allowed_types=('geo', ))
    if curves == ():
        hou.ui.displayMessage('Curves not selected, terminating tool', severity=hou.severityType.Error)
        return None

    return curves


def BonesfromCurves_Tool(kwargs):
    curves = UserInput()
    if curves == None:
        return

    for curve in curves:
        print(curve)
        curve.setSelected(1)
        toolutils.genericStateTool(kwargs, 'bonesfromcurve')

if you select couple geo nodes that contains curve, for example 2, it will create curve only for last one in the list/loop. It print both curves, so it looks that last loop operation is translated as 'enter confirmation'. I don't know is there a way to "simulate enter" for genericStateTool() somehow.

Thanks for your time! I will take a look now.
Link to comment
Share on other sites

if you select couple geo nodes that contains curve, for example 2, it will create curve only for last one in the list/loop. It print both curves, so it looks that last loop operation is translated as 'enter confirmation'. I don't know is there a way to "simulate enter" for genericStateTool() somehow.

Yea that is the problem I faced .And I used this command in the end of the loop to simulate the

'enter' :

import hou
import toolutils as t

pane =  t.activePane(kwargs)
pane.enterViewState()

But I am not sure if it's right way because it still doesn't work in the loop.

Edited by T.I.M.
Link to comment
Share on other sites

I feel bad that this thing left unsolved.Is there any other ideas on this matter or I have to dive deeper and write my own function for creation of the bones....(if i find enough documentation on that)?I just don't want to leave this unsolved....

I manged to do what I need it but in the hard way.

Hope someone can help.

Link to comment
Share on other sites

Guest mantragora

well, if you put your code

pane =  t.activePane(kwargs)
pane.enterViewState()

at the end of main version you will see that it will not execute properly, so definitely this is not the way to simulate "enter". I supose there should be a way to simulate it.

We need Graham's power for this ! CaptainHammy to the rescue ! He is one with python in Houdini ;)

Edited by mantragora
Link to comment
Share on other sites

  • 2 years later...

So this is probably too late for the OP, but here a solution I slapped together that doesn't require calling the "bones from curve" tool. Hope it helps someone.

#Bones From Multiple Curves Tool - By 90ender
'''
Given a node containing more than one curve, the tool loops over
each creating a bone chain that matches it's curvature and position.
The tool is still in development and currently does not take user input.
'''
#create a normal given two points
def normalFromPoints(pfrom = hou.Vector3(3,2,1), pto = hou.Vector3(10,5,2)):
    x = pto[0] - pfrom[0]
    y = pto[1] - pfrom[1]
    z = pto[2] - pfrom[2]

    return hou.Vector3(x,y,z)

# convert a normal to a euler rotation
def normalToEuler(nto = hou.Vector3(1,1,0), nfrom = hou.Vector3(0,1,0)):
    a = nto.normalized()
    b = nfrom.normalized()
    
    matrix = b.matrixToRotateTo(a)
    euler = matrix.extractRotates('srt','xyz',hou.Vector3(0,0,0))
    
    return euler

def buildBone(parent = None, pos = hou.Vector3(0,0,0), rot = hou.Vector3(0,0,0), len = 1.0, name = "chain_bone1", container = None):
    if container == None:
        container = hou.node("obj")
    
    bone = container.createNode("bone", name)
    bone.parm("length").set(len)
    bone.parmTuple("t").set(pos)
    rot[2] = 0.0
    bone.parmTuple("r").set(rot)
    
    if parent != None:
        bone.parm("keeppos").set(1)
        bone.setFirstInput(parent)
        bone.parm("keeppos").set(0)
    
    bone.moveParmTransformIntoPreTransform()
    return bone

def buildRoot(name = "chain_root", container = None, parent = None):
    if container == None:
        container = hou.node("obj")
    
    root = container.createNode("null", name)
    root.parm("keeppos").set(1)
    root.parm("use_dcolor").set(0)
    root.parm("geoscale").set(0.5)
    root.parm("controltype").set(1)
    root.parm("shadedmode").set(1)
    
    if parent != None:
        root.setFirstInput(parent)
    
    return root

#build chain of n bones along curve
#POSSIBLE TO DO: if curve has length attrib then add bones based on length.
def bonesFromCurve(curve = None, segments = 5, container = None):
    #initialize curve position and variables
    div = 1.0 / segments
    u = 0
    v = 0
    apos = curve.positionAtInterior(u,v)
    boneDir = hou.Vector3(0,0,-1)
    
    #get names
    rootName = "root1"
    boneName = "curve_bone1"
    if curve.geometry().findPrimAttrib("name") != None:
        name = curve.stringAttribValue("name")
        rootName = name + "_root1"
        boneName = name + "_bone1"
    
    #build root  
    root = buildRoot(rootName, container)
    chainpos = root.moveToGoodPosition()
    parent = root
    
    bonesLst = [root]
    
    for x in range(0, segments):
        #get bone start and end positions on curve
        u += div
        bpos = curve.positionAtInterior(u,v)
        len = apos.distanceTo(bpos)
        
        #Calculate bone rotation along curve from up vector
        n = normalFromPoints(apos, bpos)
        rot = normalToEuler(n, boneDir)
        
        #create bones here and orient and parent them
        bone = buildBone(parent, apos, rot, len, boneName, container)
        bone.moveToGoodPosition()
        parent = bone
        bonesLst.append(bone)
        
        #set next position
        apos = bpos
    
    #need to return a bone or list of bones
    return bonesLst

#TO DO: Find out how to put parameters into operation controls toolbar
#main()
selected = hou.selectedNodes()
if len(selected) < 1:
    hou.ui.displayMessage("No Nodes Selected")
else:
    #get curves from node
    child = selected[0].displayNode()
    curves = child.geometry().prims()
    
    #TO DO: check if geo is curve

    #TO DO: User input here. Check if zero
    input = 10
    
    #create subnet container
    subnet = hou.node("obj").createNode("subnet", "tree_rig1")
    subnet.moveToGoodPosition()
    geoInSubnet = []
    
    #iterate over curves
    for i in curves:
        bonesLst = bonesFromCurve(i, input, subnet) #we may need another parm for chain parents
     
    print "done!\n"
Edited by 90ender
  • Like 2
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...