okay. i’m gonna eventually make a bloggopost about this but i’ve learned a few things about getting these shitty ass python state handles to work in the correct local space i want
the two main things i found are: * use `cache_previous_parms` to compute *deltas* and then add the delta value to the modified parm in onHandleToState rather than trying to set absolute values for parms in most cases * use `pivot_comp_t[xyz]` and `pivot_comp_r[xyz]` to establish the actual pivot for your handle so that you can properly transform in local space, especially if you are using a control that only exposes specific rotation axes
so as an example in onStateToHandle, where you need to basically set up the handle’s transform based on what’s going on under the hood / in the parameters window:
“`python elif handle == self._handles[“GUIDE_COLUMN”].name(): # set position of handle pivot = self._skeletonCache.point(1).attribValue(“P”) parms[“pivot_comp_tx”] = pivot[0] parms[“pivot_comp_ty”] = pivot[1] parms[“pivot_comp_tz”] = pivot[2] # set rotation prerot = self._skeletonCache.point(2).attribValue(“transform”) prerot_m = hou.Matrix3(prerot) prerot = prerot_m.extractRotates(rotate_order=”xyz”) parms[“xyz_order”] = “xyz” parms[“pivot_comp_rx”] = prerot[0] parms[“pivot_comp_ry”] = prerot[1] parms[“pivot_comp_rz”] = prerot[2] “`
the skeletonCache is a frozen reference to the skeleton geometry that’s being transformed that exists as a member of the state class, that’s so i can have a frame of reference for how the handles need to be oriented. the cache is updated onEndHandleToState
the equivalent code in onHandleToState: “`python elif handle == self._handles[“GUIDE_COLUMN”].name(): # rotate only # self.log(prev_parms) prevrot = hou.Vector3(prev_parms[“rx”], prev_parms[“ry”], prev_parms[“rz”]) rot = hou.Vector3(parms[“rx”], parms[“ry”], parms[“rz”]) delta = rot – prevrot current = node.evalParm(“crane_yaw”) self.log(“rot: {}”.format(rot)) self.log(“prev: {}”.format(prevrot)) # self.log(“delta: {}”.format(delta)) node.parm(“crane_yaw”).set(current + delta[2]) “`
so this way as long as the starting orientation is correct, as long as the user is dragging a handle it’s just computing the difference between prev and current, adding that to the handle, and then basically forgetting about it and resetting the handle’s position and orientation onStateToHandle, the next time the handle is activated
oh and in OnHandleToState i’m making sure that this shit only runs if `ui_event.reason() == hou.uiEventReason.Active`, because the prev_parms dict is always zero when you first activate the handle, which would make my delta calculation all fucked up when the user first grabs the handle (meaning `ui_event.reason()` == `hou.uiEventReason.Start`)
i knew it was going to be a lot of boilerplate but this amount of it feels pretty insane. dunno if there’s an easier way i’m missing but this at least works