Incremental rotation with a "+=" counter?

   2685   13   1
User Avatar
Member
41 posts
Joined: May 2021
Offline
I'm preparing to dive into a pretty complicated while loop in Python, (yes it HAS to be a while loop) with multiple conditions etc. etc.... How would someone rotate an object by let's say X axis in small increments (precision of let's say 0.01), clockwise and counter clockwise?
User Avatar
Member
377 posts
Joined: April 2017
Offline
If you have to do this in Python, you could handle the rotation with SOP verbs. This lets you create "nodes" as Python, set their properties, and execute them, without actually creating nodes.

The following script could be placed in a Python SOP... it's grabbing a reference to the geometry and also creating an output geometry, executing the SOP verb on the geometry and writing the result to the output, in a loop.

node = hou.pwd()
geo = node.geometry()
outgeo = node.geometry()

for x in range(0, 10):
    xformverb = hou.sopNodeTypeCategory().nodeVerb("xform")
    xformverb.setParms({"r": hou.Vector3(0, 10, 0)})
    xformverb.execute(outgeo, [geo])
    geo = outgeo
Edited by toadstorm - Sept. 21, 2021 13:26:39
MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
41 posts
Joined: May 2021
Offline
Thank you for your time... but I'm looking for solution in the object level... (as far as I know SOP is shortcut for "Surface operators" do correct me if I'm wrong) I'm not trying to manipulate geometry per-Se (vertices or polygons)... In my while loop I'm comparing two world space rotations vectors, extracted out of worldTransform Matrix... I guess some pseudo code would look like this:

Counter = 0.01
Object A = hou.(bla bla)
Object B = hou. (bla bla)
Object A X rotation = hou.parm(bla bla)
Object B X rotation = hou.parm(bla bla)
Vector A = Object A X axis worldspace rotation vector (extracted out of worldTransform)
Vector B = Object B X axis worldspace rotation vector (extracted out of worldTransform)


While Vector A and Vector B are not equal

Rotate (increase value)object A X axis by Counter value with +=

If Object A X rotation >= of some value

Rotate (decrease value) object A X axis by Counter value with -=

(until there is a match in vector values)

I guess something like this... Is this even the right approach?
User Avatar
Member
377 posts
Joined: April 2017
Offline
So you're trying to incrementally blend the rotations of two objects? I could probably give you better advice if I knew what your goal was.

OBJ level is annoying but this is probably easier than you think. What you want to do instead of thinking about vectors is think in terms of orientations. You can extract the transform matrices of your objects, convert them to quaternions, slerp the quaternions together with a bias (your increment), then convert back to a transform matrix and set your values.

import hou

objA = hou.node("/obj/nodeA")
objB = hou.node("/obj/nodeB")

# get world space transforms of objects
xformA = objA.worldTransform()
xformB = objB.worldTransform()

# convert to quaternions
qA = hou.Quaternion(xformA)
qB = hou.Quaternion(xformB)
# create an output quaternion to store the result
qOut = hou.Quaternion(xformA)

# you can compare two quaternions using the dot product, just like vectors.
# if dot(q1,q2) is close to 1, they're almost identical.
# if they're not identical enough, slowly increase the bias when interpolating
# from A to B until we're finally basically at B.

threshold = 0.99
increment = 0.01
bias = 0.01
while qB.dot(qOut) < threshold:
    qOut = qA.slerp(qB, bias)
    bias += increment

# set output rotations based on this quaternion.
rOut = qOut.extractEulerRotates()
objA.parm("rx").set(rOut[0])
objA.parm("ry").set(rOut[1])
objA.parm("rz").set(rOut[2])
Edited by toadstorm - Sept. 21, 2021 14:58:30
MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
41 posts
Joined: May 2021
Offline
Wow... thanks A LOT... Can this be applied to a null who acts as a controller (parent)of IK goal in reverse foot rig setup? Sorry I didn't mention it's about rigging... This should be applied to each one of controllers in the reverse foot setup hierarchy (from toes to heel or vice versa)... so the bones under the control of IK chains align with FK bones/controllers... huh... Isn't this a bit of a overkill? Somehow feels like this is a level above measly Euler... I was thinking more in a way of grabbing current local rotation value (parm) directly and increasing/decreasing it until two vectors in world space are aligned... But if this is the way (as Mando would said)... who am I to disagree...
User Avatar
Member
377 posts
Joined: April 2017
Offline
If you're just trying to do an IK/FK switch, I'm not sure I understand why you'd need to do an iterative loop at all. Why not just match the transforms from the start? You can use hou.ObjNode.worldTransform() to get the world transform of one object, then hou.ObjNode.setWorldTransform() to set another object to that same exact transform.
MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
41 posts
Joined: May 2021
Offline
Because .worldTransform output matrix, imho, carries around too much "baggage" again, imho, (and it has a tendency to overwrite pre-transforms of children controllers/bones)... And I just need rotations... not position, or scale... expressed anyhow... other parts of the rig are responsible for positions... Is there maybe a way to copy/paste/overwrite parts of one matrix to another? Again thanks a lot!
User Avatar
Member
377 posts
Joined: April 2017
Offline
You could probably just overwrite the matrix, then set t and s back to their original values after the fact. Or use hou.Matrix4.extractRotationMatrix3() to get just the rotations, then convert that to a Matrix4 and translate + prescale that new matrix to match your original translation and scale.
MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
41 posts
Joined: May 2021
Offline
Some example of that? Once I tried to use hou.hmath.buildTransform() with extracted parts of two matrices, but the results were not what I expected... probably my fault...
User Avatar
Member
377 posts
Joined: April 2017
Offline
import hou

def match_xforms(sources, dests):
    with hou.undos.group("Matching transforms"):
        for x in range(0, len(sources)):
            source_obj = hou.node(sources[x])
            dest_obj = hou.node(dests[x])
            source_xform = source_obj.worldTransform()
            dest_xform = dest_obj.worldTransform()
            
            # get rotation from source, translate and scale from dest.
            source_rot = source_xform.extractRotationMatrix3()
            orig_t = dest_xform.extractTranslates()
            orig_s = dest_xform.extractScales()
            
            # create an output transform that's just the rotation.
            # by avoiding euler angles we don't have to worry about 
            # rotation order.
            out_xform = hou.Matrix4(source_rot)
            dest_obj.setWorldTransform(out_xform)
            
            # set translate and scale directly.
            dest_obj.parm("tx").set(orig_t[0])
            dest_obj.parm("ty").set(orig_t[1])
            dest_obj.parm("tz").set(orig_t[2])
            dest_obj.parm("sx").set(orig_s[0])
            dest_obj.parm("sy").set(orig_s[1])
            dest_obj.parm("sz").set(orig_s[2])
        
sources = ["/obj/sourceA", "/obj/sourceB", "/obj/sourceC"]
dests = ["/obj/destA", "/obj/destB", "/obj/destC"]
match_xforms(sources, dests)

The script is in the Python Source Editor... you can scramble the transforms of the objects and then run the script to give it a try.

Attachments:
match_rotations_toadstorm.hip (705.4 KB)

MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
41 posts
Joined: May 2021
Offline
Wow... Again I can't thank you enough... If I can annoy you for just a little bit? Just a few clarifications? I'm adding some comments just to know what's going on...

1. for x in range(0, len(sources)):

#You are looping over the full lenght (size)of an array of objects?

2. source_obj = hou.node(sources x)

# Is X an element of the array?

3. dest_obj.parm("tx").set(orig_t 0)

# What does 0 stands for? If I had to guess, I would say first element (or field) of the translation Matrix responsible for X position in world space coordinates?

Sorry for delayed reply... stupid survivor mode daily job... and the time zone difference is huge...Sorry for deletion of square brackets... somehow this text editor deletes them and everything inside of them when I submit reply...
Edited by kriegmesser74 - Sept. 23, 2021 12:48:55
User Avatar
Member
377 posts
Joined: April 2017
Offline
I'm looping over a list of objects... presumably you want to match rotations between two pairs of objects. You could just rewrite the function to apply a single source object's orientation to a destination object if you wanted, and then do any required looping elsewhere.

X is the array element. for x in range(a, b)is a generator that will give you a range of numbers that you can iterate over. Sorry, I thought you were more familiar with Python. By iterating over a numbered range like this it's easier to grab matching pairs from the source and destination object arrays.

orig_t[0]is the 0th index of the vector orig_t, meaning the x position. The extractTranslates() function returns a hou.Vector3 object, with its components corresponding to tx,ty,tz.
MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
User Avatar
Member
41 posts
Joined: May 2021
Offline
Pure gold... So I guessed the first two huh? ... And the third one is a Vector3 not Matrix... it didn't even cross my mind... wasn't paying attention... yes... clever... really clever... Now I know how to patch Matrices... Examples like this should be in the help file...Now I get some idea why my experiment with hmath.buildTransform() didn't work at the time... I didn't add all the ingredients... I added just two that I thought were important... what a moron...

Old Maya MEL guy here, forgive me my ignorance, everything looks familiar but it's very different...Thanks a lot!
User Avatar
Member
377 posts
Joined: April 2017
Offline
I'm a reformed MEL scripter myself. You'll be much happier with Python (and Houdini).

The only reason it's worth doing the work to extract the rotation matrix and then re-apply the old translations and scales is because it avoids the issue of rotation order and all that other fun stuff that comes with eulers. If you know that your rotation orders between your source and destination transforms are always the same and the parents of these transforms are identical, you can probably just grab the r parameters from the source objects and set the destination r parameters to the same values, and save yourself some trouble. I just wasn't exactly sure what cases your tool needed to cover, and you'd mentioned matrices, so I figured you were needing that level of flexibility.
Edited by toadstorm - Sept. 23, 2021 13:42:41
MOPs (Motion Operators for Houdini): http://www.motionoperators.com [www.motionoperators.com]
  • Quick Links