Modify Geometry from a shelf tool script?

   1785   13   1
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
I'm trying to write a script where I select a point in the viewport then and do some stuff that will eventually modify the geometry. But, here the geo is read-only! what could be a solution to this problem, cause it really must be that I modify the geo that already exists. Any tips will be greatly appreciated! Below is very simplified version of what I'm trying to do; of course, it works great in a Python SOP but I want to make it work in a shelf tool script. So, essentially what I want to do is select a kinefx joint/point in the viewport and use info from that point to add another point into the rig.
import hou
import stateutils
from kinefx import rigapi

scene_viewer = stateutils.findSceneViewer()
geo = scene_viewer.currentGeometrySelection().nodes()[0].geometry()
trans = hou.Matrix4().setToIdentity()
parent_pnt = scene_viewer.currentGeometrySelection().selections()[0].points(geo)[0]
pnt = rigapi.GeoSkeleton(geo).createPoint(name='point_2', transform=trans, parent=parent_pnt)
Edited by traileverse - 2023年8月4日 21:39:49
hou.f*ckatdskmaya().forever()
User Avatar
Member
8556 posts
Joined: 7月 2007
Offline
the geo has to live somewhere, you can't modify geo that other SOP node owns

if you look at how SideFX builds such tools they are

- either as a viewport script that spawns a corresponding node that can do appropriate action within it's interface
- or you can spawn a node with Geometry Data Parm like Stash SOP or custom one and stash resulting geo on there
- or as a Vewer State belonging to the node

what you are describing sounds like a Skeleton SOP's viewer state
or your shelf tool can spawn new Skeleton SOP and stash the modified geo in it's "stash" data parm, which will not only store the modification but also user will gain ability to further modify it using Skeleton SOP's viewer state
but you can as well just use Stash SOP if you want to use only your shelf tools
Edited by tamte - 2023年8月5日 00:18:44
Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
tamte
the geo has to live somewhere, you can't modify geo that other SOP node owns

if you look at how SideFX builds such tools they are

- either as a viewport script that spawns a corresponding node that can do appropriate action within it's interface
- or you can spawn a node with Geometry Data Parm like Stash SOP or custom one and stash resulting geo on there
- or as a Vewer State belonging to the node

what you are describing sounds like a Skeleton SOP's viewer state
or your shelf tool can spawn new Skeleton SOP and stash the modified geo in it's "stash" data parm, which will not only store the modification but also user will gain ability to further modify it using Skeleton SOP's viewer state
but you can as well just use Stash SOP if you want to use only your shelf tools

This is very helpful tamte, so what I want is a tool that allows me to do animatable pivots without littering the scene with helper nodes; so essentially I was thinking to have two shelve scripts, when the user clicks the first one they can move a newly created helper joint to where they want the new pivot location and then the second script would take care setting the new pivot point. During animation a user might need to do this often, so I wouldn’t want the graph littered with nodes to do it. How would you tackle this?
hou.f*ckatdskmaya().forever()
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
@tamte looking over a few ways to get this done, think I finally have it. I checked if the stash SOP can be used as a verb and I got true, so now I'm wondering how do I set stashinput button param in python SOP verb?
hou.f*ckatdskmaya().forever()
User Avatar
Member
6 posts
Joined: 8月 2023
Offline
Here's a basic outline of how you could structure your script to achieve your goal:

def create_point_on_selected():
    selected_nodes = hou.selectedNodes()
    if len(selected_nodes) > 0:
        selected_geo = selected_nodes[0].geometry()
        selected_points = selected_geo.globPoints('*')
        
        if len(selected_points) > 0:
            parent_point = selected_points[0]
            trans = hou.Matrix4().setToIdentity()
            
            new_point = rigapi.GeoSkeleton(selected_geo).createPoint(name='point_2', transform=trans, parent=parent_point)
            new_point.setPosition([0, 1, 0])  # Modify position as needed
            
            hou.ui.displayMessage("New point created and modified.")
        else:
            hou.ui.displayMessage("No points selected in the geometry.")
    else:
        hou.ui.displayMessage("No nodes selected.")
create_point_on_selected()
The above script assumes that you've created a shelf tool that executes the script when clicked. The create_point_on_selected function checks for selected nodes, selects the first point, and creates a new point using the rigapi library. Remember to adjust the script according to your specific requirements and the structure of your rig.

Tell me if this is working for you.
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
DyktaT
Here's a basic outline of how you could structure your script to achieve your goal:

def create_point_on_selected():
    selected_nodes = hou.selectedNodes()
    if len(selected_nodes) > 0:
        selected_geo = selected_nodes[0].geometry()
        selected_points = selected_geo.globPoints('*')
        
        if len(selected_points) > 0:
            parent_point = selected_points[0]
            trans = hou.Matrix4().setToIdentity()
            
            new_point = rigapi.GeoSkeleton(selected_geo).createPoint(name='point_2', transform=trans, parent=parent_point)
            new_point.setPosition([0, 1, 0])  # Modify position as needed
            
            hou.ui.displayMessage("New point created and modified.")
        else:
            hou.ui.displayMessage("No points selected in the geometry.")
    else:
        hou.ui.displayMessage("No nodes selected.")
create_point_on_selected()
The above script assumes that you've created a shelf tool that executes the script when clicked. The create_point_on_selected function checks for selected nodes, selects the first point, and creates a new point using the rigapi library. Remember to adjust the script according to your specific requirements and the structure of your rig.

Tell me if this is working for you.

thanks for taking the time to put this together @DyktaT, my problems at the moment though are more UI based. One issue I'm having now that I didn't realize before is that when I'm in the viewer state of a rigpose SOP and select a joint, Houdini doesn't recognize it as a point selection, so any ideas for how to turn the rigpose state selections into actual point selections would be very helpful. Is there a way to get either a hou.Selection or hou.Point object from a joint selection made via rigpose viewer state?
hou.f*ckatdskmaya().forever()
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
I tried stashing the geo, but this still gave me an error the geometry is read-only! My understanding of modifying geo from shelf tool is still fuzzy. What's the next move I can try here?

import hou
import stateutils
from kinefx import rigapi, stateutils as kstateutils

scene_viewer = stateutils.findSceneViewer()

node_to_stash = hou.selectedNodes()[0]
geo = hou.selectedNodes()[0].geometry()
parent_pnt = scene_viewer.currentGeometrySelection().selections()[0].points(geo)[0]
pnt_pos_mat = hou.hmath.buildTranslate(parent_pnt.attribValue('P'))
node = hou.node('obj/geo1').createNode('stash')
node.setInput(0, node_to_stash)
set_stash = node.parm('stashinput').pressButton()
node.setInput(0, None)
new_geo = node.geometry()
jnt_name = 'pivot_helper'
helper_jnt = rigapi.GeoSkeleton(new_geo).createPoint(name=jnt_name, transform=pnt_pos_mat, parent=parent_pnt)
hou.f*ckatdskmaya().forever()
User Avatar
Member
8556 posts
Joined: 7月 2007
Offline
Here is one example of storing geometry in Stash SOP's data parameter using Python

https://www.sidefx.com/forum/topic/74110/#post-313189 [www.sidefx.com]
Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
tamte
Here is one example of storing geometry in Stash SOP's data parameter using Python

https://www.sidefx.com/forum/topic/74110/#post-313189 [www.sidefx.com]
Nice, thank you! I have one other issue now; Is there a way to get the point or geometry from a viewport selection of a joint when using the rigpose SOP? the actual point is not selected when using the rigpose viewer state.
hou.f*ckatdskmaya().forever()
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
So, I've been trying a few things to get access to a point/joint from a rigpose viewstate selection. Absolutely no luck; the selection is coming back as a None type even though I have joints selected in the viewport. Anyone who has accomplished this, please throw an assist my way! really appreciate it.
import hou
import stateutils
import sys
from kinefx import rigapi, stateutils as kstateutils
from kinefx.ui import basestate, rigtreeutils
from kinefx__skeletonstate import state as kskelstate
import importlib.util
import sys
spec = importlib.util.spec_from_file_location("kinefx_rig_pose", "C:/Program Files/Side Effects Software/Houdini 19.5.700/packages/kinefx/viewer_states/kinefx__rig_pose.py")
foo = importlib.util.module_from_spec(spec)
sys.modules["kinefx_rig_pose"] = foo
spec.loader.exec_module(foo)

scene_viewer = stateutils.findSceneViewer()
slct_node_geo = hou.selectedNodes()[0].geometry()
#rigtree_state = basestate.KinefxViewerState(state_name = scene_viewer.currentState(), scene_viewer = scene_viewer)
#kinefx_select = kstateutils.KinefxSelection(geo=slct_node_geo, selection=rigtree_state.selection)
rig_pose_slct = foo.PoseRigState(state_name = scene_viewer.currentState(), scene_viewer = scene_viewer).active_selection()
print(scene_viewer.currentState())
print(rig_pose_slct)
hou.f*ckatdskmaya().forever()
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
Is there a way to gain access to a hou.Point or hou.GeometrySelection object via a joint/point selection made in the viewport by the rigpose SOP or in the rigtree? I've been looking through the kinefx modules but have not figured out a way to do this.
hou.f*ckatdskmaya().forever()
User Avatar
Member
311 posts
Joined: 10月 2016
Offline
Please clarify, is it not so when you use rigpose SOP and select a skeleton joint that it automatically appends it to the node groups?

If so, can't you just get the name of your point from the groups?
Interested in character concepts, modeling, rigging, and animation. Related tool dev with Py and VEX.
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
SWest
Please clarify, is it not so when you use rigpose SOP and select a skeleton joint that it automatically appends it to the node groups?

If so, can't you just get the name of your point from the groups?
yeah, that makes sense, but I only want the group of the point selected by the user in the viewport, the rigpose sop would have already beed preloaded with all the point groups in the rig. When I select a point via rigpose, it doesn’t register as a point selection.

Maybe the question is how to get the point name from the rigpose viewport selection?
Edited by traileverse - 2023年8月9日 07:50:51
hou.f*ckatdskmaya().forever()
User Avatar
Member
355 posts
Joined: 11月 2015
Offline
got some help from sidefx on this:

The selected set of joints in the rig pose state is tracked by the state itself so there is no parameter that can be referenced but there is a state command named "getSelections" that is used by the Rig Tree to access the group.
The following function should be able to get a dictionary of selections from the Rig Pose state given the hou.SceneViewer object:

def getStateSelection(scene_viewer):
kwargs = {}
scene_viewer.runStateCommand("getSelections", kwargs)

if 'ret' not in kwargs or not kwargs:
# The command did not run successfully
return {}
selections = kwargs
return selections
The returned selection is a dictionary which maps node paths in the HDA to lists of point indices in the selection on that node's geometry.

The Rig Pose viewer state is a bit of a unique case among the KINEFX viewer states since it can operate on HDAs which contain many Rig Pose nodes.
For the other viewer states that interact with the rig tree, there is a similar state command named getselection.
This command just returns a list of point indices on the input geometry that are selected. This selection can be accessed with kwargs.


It worked like a charm for my purposes!
hou.f*ckatdskmaya().forever()
  • Quick Links