[ViewerState] Bezier Spline custom workflow study

   3104   7   4
User Avatar
Member
6 posts
Joined: Jan. 2016
Offline


As an exercise of advanced custom tool, I started to write a bezier spline editing HDA, to reproduce the workflow I have in e.g. Inkscape. I implemented this using the new python ViewerStates available since H17, which are great, but I need a bit of help to make thing clean regarding the following points:

1. Display-only geometry. How to use geometry for display only, not as object data? For instance, I generate geometry in the subnetwork to visualize the tangents, but I don't want them to be listed in geometry spreadsheet. I may need to manually call some render line function, but I don't see where/how.

2. Custom handles. I use the curvepoint handle, but I would like to set per control point shape and color. And curvepoint does not trigger onHandleToState when moving points around, etc. Is it possible to build its own handle? It might be solved by the previous question, but is there an “official” way to do so?

3. Multiple tools. I have different ways of interacting with my spline: adding points, moving points, selecting points, etc. Should I implement them in a single viewer state, using button parameters to switch tool, or is it more idiomatic to write several viewer states? The current implementation uses the former.

4. When a click triggers onMouseEvent, how to detect that it hit a handle? I would like to have behavior such as “add a point at the click position unless it was a click on the translate handle”.

5. Handle activation. How to deactivate (hide) a handle in onStateToHandle? For translate node, I went for the hacky “tx = 99999.9”. For the curvepoint handle, I tried to set the pointlist parameter to an empty string but it “breaks” it, namely when I switch the value back to a non empty string, the handle remains invisible unless I deselect-reselect the node.

6. Selection. Should I rely on houdini's selection mechanism to select the points I want my handle to move around, or should I implement my own selection process?

You can find a HDA in attachements.
The main script of the module: https://gist.github.com/eliemichel/7bd59adc6d134b602d59861406fb5933 [gist.github.com]

Attachments:
bezierspline-wip001.png (40.0 KB)
bezierspline-wip002.png (170.0 KB)
eliemichel_bezierspline_v001.hda (15.4 KB)

User Avatar
Member
5 posts
Joined: Dec. 2016
Offline
Hi, I'm interested too on how to draw simple line in state mode display only, that is not a sop geometry.
Let's say (pseudo code) onMouseEvent click 1 draw line vertex 0 and on second click vertex 1?
The documentation seems detailed, but it's kinda convoluted a bit.
Edited by TheBlues - April 29, 2019 06:06:14
User Avatar
Staff
397 posts
Joined: Feb. 2018
Offline
TheBlues
Hi, I'm interested too on how to draw simple line in state mode display only, that is not a sop geometry.
Let's say (pseudo code) onMouseEvent click 1 draw line vertex 0 and on second click vertex 1?
The documentation seems detailed, but it's kinda convoluted a bit.

You can use hou.Drawable along with hou.SopVerbs, the resulting geometry will not be part of the scene.

        # Measure Line 1
        self.guide_geo1 = hou.Geometry()
        line_verb = hou.sopNodeTypeCategory().nodeVerb("line")

        line_verb.setParms({
            "origin": self.startpos,
            "dir": hou.Vector3(0,1,0),
            "dist": 1
        })

        line_verb.execute(self.guide_geo1, [])

        self.drawable1 = hou.Drawable(self.scene_viewer, self.guide_geo1, "guide_1")
        self.drawable1.enable(True)
        self.drawable1.show(True)

        # Measure Line 2
        self.guide_geo2 = hou.Geometry()
        line_verb = hou.sopNodeTypeCategory().nodeVerb("line")

        line_verb.setParms({
            "origin": self.startpos,
            "dir": hou.Vector3(0,1,0),
            "dist": 1
        })

        line_verb.execute(self.guide_geo2, [])

        self.drawable2 = hou.Drawable(self.scene_viewer, self.guide_geo2, "guide_2")
        self.drawable2.enable(True)
        self.drawable2.show(True)
Edited by mabelzile - April 29, 2019 10:09:25
User Avatar
Staff
397 posts
Joined: Feb. 2018
Offline
eliemichel
1. Display-only geometry. How to use geometry for display only, not as object data? For instance, I generate geometry in the subnetwork to visualize the tangents, but I don't want them to be listed in geometry spreadsheet. I may need to manually call some render line function, but I don't see where/how.

2. Custom handles. I use the curvepoint handle, but I would like to set per control point shape and color. And curvepoint does not trigger onHandleToState when moving points around, etc. Is it possible to build its own handle? It might be solved by the previous question, but is there an “official” way to do so?

3. Multiple tools. I have different ways of interacting with my spline: adding points, moving points, selecting points, etc. Should I implement them in a single viewer state, using button parameters to switch tool, or is it more idiomatic to write several viewer states? The current implementation uses the former.

4. When a click triggers onMouseEvent, how to detect that it hit a handle? I would like to have behavior such as “add a point at the click position unless it was a click on the translate handle”.

5. Handle activation. How to deactivate (hide) a handle in onStateToHandle? For translate node, I went for the hacky “tx = 99999.9”. For the curvepoint handle, I tried to set the pointlist parameter to an empty string but it “breaks” it, namely when I switch the value back to a non empty string, the handle remains invisible unless I deselect-reselect the node.

6. Selection. Should I rely on houdini's selection mechanism to select the points I want my handle to move around, or should I implement my own selection process?

#1 There is no line API in the `HOM`, you need to use `hou.Drawable` and `houSopVerbs` for creating guide geometries that won't show up as scene elements (see post above). If you want to draw the curve while holding the mouse you could probably do it by multiplying the `start` and `end` drawable transform with the line length in your `mouse event` handler. But this is mostly a hack. I think the right way would be to create (or update) the line verb in the `mouse event` handler with different parameters and set the drawable with the new geo. Something I could look into.

#2 We don't have custom handles yet (it's in the plan though), I'll have to look at the `curvepoint` issue.

#3 Unfortunately, multiple states are not available yet (also planned). In the meanwhile you need to implement your tools in one single state and use a hotkey, popupmenu or key events (H17.5) to activate individual tool.

#4 state events are processed only if the handle hasn't consumed the event. If the handle is under the mouse, then it gets the mouse event first (if the handle is enabled of course). If it doesn't processed it, then it falls through to the state. Most handles don't actually consume a click, but a press and drag. This is why you can still select a geometry though a handle in Houdini. I think you should just assume that if the state mouse handler gets the event it means the handler hasn't consumed it and the state should just process it.

#5 You can use the `hou.Handle` object to show/hide/trigger an handle. This object is available in H17.5.

#6 You could probably just use the Houdini selection by holding ‘S’ and get the selected elements via the `onResume` handler. Or you can register your own python state selector and implement the `OnSelection` callback. Once you have a selector registered, the user can either use the Houdini selection with ‘S’ or the python state selector. In both case, the `OnSelection` callback is called with the selected element(s).
Edited by mabelzile - April 29, 2019 20:31:17
User Avatar
Member
6 posts
Joined: Jan. 2016
Offline
Hi _mab_, thanks for all these answers.

The hou.Drawable is definitely what I was missing. I have been able to link it to a SOP geometry so this solves #1. The only drawback is that the guide geo is not cooked while the handle is moved, because the Viewer State object does not recieve any event.

Anyway given the limitations raised in the other points, I think that I am going to implement my handles from scratch using drawables and viewer state's event handlers.
Edited by eliemichel - May 4, 2019 06:40:32

Attachments:
bezierspline-wip003.png (152.7 KB)

User Avatar
Member
192 posts
Joined: April 2015
Offline
Hi eliemichel,

I see you wrote your Viewer State in Python Module of the hda, is there a reason for this?
Is this different than writing it in ‘Interactive > Viewer State'?
User Avatar
Staff
397 posts
Joined: Feb. 2018
Offline
OdFotan
Hi eliemichel,

I see you wrote your Viewer State in Python Module of the hda, is there a reason for this?
Is this different than writing it in ‘Interactive > Viewer State'?

Unless your existing viewer state predates the new way of writing viewer states introduced in H18, you should definitely use the `Interactive|Viewer State` module for writing python states. The module takes care of updating the viewer state when new changes are applied and, it also provides a code generator to create your state in no time.
User Avatar
Member
4 posts
Joined: Feb. 2006
Offline
Hi, I am quite new to Houdini, but have been missing proper bezier curve drawing tools terribly.
I had planned to start a project exactly like this one, but then found that you had already begun something. Have you done any more on it? Or should I start my own tool?
  • Quick Links