Jump to content

Python Question


few_a_fx

Recommended Posts

Hey everyone,

First ignore the last post. Figured out the problem. So my question for today is how can I create a geo node with a grid node inside it and connected to a popnet node? I know how to create each one separately but not connected.

Any suggestions?

Link to comment
Share on other sites

either like this

geo = hou.node("/obj").createNode("geo", "Grid_OBJ")
geo.node("file1").destroy()
grid = geo.createNode("grid", "Grid_SOP")
popnet = grid.createOutputNode("popnet", "Popnet_SOP")
popnet.setDisplayFlag(1)

or if you already have them created but not connected then

popnet.setFirstInput(grid)

or if you want to connect other than first input

popnet.setInput(1,grid)

Link to comment
Share on other sites

So far, I have both the check box on/off and create button working. Have hit a small problem, I've been attempting to figure it out for a while now (maybe 2 hrs, stopped counting). Trying to make a button add a sop object(whatever obj is selected)to the soppath on the collision node. And then I have a wx.ComboBox, which has all the behaviors for the collision in it. Would like to be able to pick one of the behaviors (i.e. die, bounce,etc,) and have it applied to the collision node. Not asking for the exact code, but any tips or examples would be great.

Link to comment
Share on other sites

not sure where exactly you have the problem, but here are few guidelines

hou.selectedNodes()

will give you list of selected nodes

hou.selectedNodes()[0].path()

will give you absolute path to first selected node and you can use it in collision POP

so if colPop is your collision pop then you can set it by

soppath = hou.selectedNodes()[0].path()
colPop.parm("soppath").set(soppath)

if your combobox contains values: 'die', 'bounce', 'stop', 'stick', 'slide', 'continue'

you can get current value and set in collision POP by something like

value = youComboBox.GetValue()
colPop.parm("behavior").set(value)

Link to comment
Share on other sites

Thanks again anim. I'll try the combobox first. I thought it would be something like that, I must have had a typo or I might have left out .set(value). For the colPop, I figured out how to set individual sop nodes to the soppath, I'm trying to figure out how to make it so you can select a random obj and then click a button on the tool and add it to the soppath. Is that what is going on with this line of code.

soppath = hou.selectedNodes()[0].path()
colPop.parm("soppath").set(soppath)

. Thanks for your tips and suggestions.

Link to comment
Share on other sites

yes, but it may be more useful if you use

hou.ui.selectNode() - look in help for usage

or selectObjects() from toolutils.sceneViewer()

that way the user can be asked to select node(s) when you press the button instead of presuming that something is selected when he press it

and hou.ui.selectNode() can return relative path to your collision POP if you specify it in options

Link to comment
Share on other sites

So your suggestions anim should work, but I have no idea what I'm doing wrong. I've tried various ways to type this code out and keep getting it wrong. If you, or anybody , can show/tell me what's wrong with the code that would be great. Trying to add SelectBehavior(combobox).


    def SelectBehavior(self, event):
           value = self.collide_op.GetValue()
           collide = hou.node('/obj/Rain_System/RAIN_EMITTER/COLLIDE_WITH')
           behave = collide.parm("behavior")
           self.collide_op.GetValue()
           behave.set(value)

Any tips or explanations of what I'm doing wrong would extremely helpful. Still new to python, and slowly learning.

Thanks

--Jason

Edited by few_a_fx
Link to comment
Share on other sites

Ok. So I figured out the add soppath button last night. Still stuck on this comboBox/behavior selection. I've tried this code

def Selectbehavior(self, event):
           value = self.collide_op.GetValue()
           collide = hou.node('/obj/Rain_System/RAIN_EMITTER/COLLIDE_WITH')
           behave = collide.parm("behavior")
           self.collide_op.GetValue()
           behave.set(value)

This is my latest attempt:

            options = [0, 1, 2, 3, 4]
            colPop = hou.node('/obj/Rain_System/RAIN_EMITTER/COLLIDE_WITH')

            if self.collide_op.GetValue():
                colPop.setParms({"behavior": options})

Have tried everything I could think of, but still stuck. Any suggestions?

Link to comment
Share on other sites

It's hard to tell without seeing your ui code

i am not sure with GetValue() I have told you, I don't use wx, maybe it is GetStringSelection() or GetSelection() or other method you need to use to get current value of the combo box

you may want to print it as soon as you get it from comboBox to make sure it contains the right data

what error are you getting?

Link to comment
Share on other sites

Apparentlly I tried everything but that command anim. ( .GetCurrentSelection() ). Had to use that and re-word a couple of lines. Now its working. Hopefully I'll be able to figure oue the sliders and text box with this info. Thanks again for all your help and tips. Hopefully my next post will be the script for the finished tool.

Edited by few_a_fx
Link to comment
Share on other sites

Control for amplitude is working, but at the same time I keep getting an error. Error reads "Cannot set a numeric parm to a non-numeric value' on line 215". Here is the code for the event.

def enterText(self, event):
        try:
            text = self.x_value
            text1 = self.y_value
            text2 = self.z_value
            entered = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_DirCtrl')
            val = text.GetValue()
            val1 = text1.GetValue()
            val2 = text2.GetValue()
            entered.parm("ampx").set(val)
            entered.parm("ampy").set(val1)
            entered.parm("ampz").set(val2)
        except:
            exc_log()

I think it might be the .GetValue command. Trying out different ones right now. Not having any luck. The tool does work, if I change the amplitude on x axis it changes inside the force node. Just not sure why I'm getting the error message. Here is the rest of the code needed to make it work.


import sys, threading, wx
if __name__ != "__main__":
    import hou
    import toolutils 

def exc_log():
    print "Exception: '%s' on line %d" % (sys.exc_value, sys.exc_traceback.tb_lineno)

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFxTool(None, -1, 'Rain System Tool')
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

# Creates the Window
class MyFxTool(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size (450, 320),
                          style = wx.CAPTION | wx.SYSTEM_MENU | wx.CLOSE_BOX | wx.STAY_ON_TOP)
        self.sizer= wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.sizer)
        self.panel= MyFxToolPanel(self)
        self.sizer.Add(self.panel, 1, flag= wx.EXPAND)
        self.Layout()
# Creates the Layout
class MyFxToolPanel(wx.Panel):
    def __init__(self, parent):
        super(MyFxToolPanel, self).__init__(parent)
        self.sizer= wx.BoxSizer(wx.VERTICAL)
        self._add_flex_grid()
        self.SetSizer(self.sizer)

    def _add_flex_grid(self):
        self.flex_grid_sizer= wx.FlexGridSizer(cols= 2, vgap= 10, hgap= 70)
        self.sizer.Add(self.flex_grid_sizer, 1, border= 20, flag= wx.ALL|wx.EXPAND)
        self._add_static_text("Rain System Tool")
        self.start_button= self._add_button("Make It Rain")
        self._add_static_text("Amount of Rain")
        self.amount_slider, self.amount_slider_display= self._addAmount_slider()
        self._add_static_text("Rain Speed")
        self.r_speed_slider, self.r_speed_slider_display= self._addSpeed_slider()
        self._add_static_text("Amplitude")
        self._add_wdirection()
        self._add_static_text("Turbulance")
        self.turb_slider, self.turb_slider_display= self._addTurb_slider()
        self._add_static_text("Life")
        self.life_slider, self.life_slider_display= self._addLife_slider()
        self._add_static_text("Collisions")
        self._add_colisions()
        self._add_static_text("Bounce")
        self.bounce_slider, self.bounce_slider_display= self._addBounce_slider()
    def _add_wdirection(self):
        wdirection_sizer= wx.BoxSizer(wx.HORIZONTAL)
        self.flex_grid_sizer.Add(wdirection_sizer, flag= wx.ALIGN_CENTER_VERTICAL)
        self.x_value= self._add_letter_value("X:", wdirection_sizer)
        wdirection_sizer.AddSpacer(20,0)
        self.y_value= self._add_letter_value("Y:", wdirection_sizer)
        wdirection_sizer.AddSpacer(20,0)
        self.z_value= self._add_letter_value("Z:", wdirection_sizer)
        self.x_value.Bind(wx.EVT_TEXT, self.enterText)
        self.y_value.Bind(wx.EVT_TEXT, self.enterText)
        self.z_value.Bind(wx.EVT_TEXT, self.enterText)


    def _add_letter_value(self, letter_text, sizer):
        x= wx.StaticText(self, label= letter_text)
        sizer.Add(x, flag= wx.ALIGN_CENTER_VERTICAL)
        text_ctrl= wx.TextCtrl(self, size= (40, -1))
        sizer.Add(text_ctrl, border= 2,
            flag= wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
        return text_ctrl

    def enterText(self, event):
        try:
            text = self.x_value
            text1 = self.y_value
            text2 = self.z_value
            entered = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_DirCtrl')
            val = text.IsModified()
            val1 = text1.IsModified()
            val2 = text2.IsModified()
            entered.parm("ampx").set(val)
            entered.parm("ampy").set(val1)
            entered.parm("ampz").set(val2)
        except:
            exc_log()

class AppThread(threading.Thread):
    def run(self):
        app = MyApp(0)
        app.MainLoop()


if __name__ == "__main__":

Link to comment
Share on other sites

FX Tool finally done. Took a while to figure out sliders, but got that done. Still have the error from the previous post, but the tool works. Thanks once again to anim for all your help and tips. Will post the code for anyone who wants it just let me know. will have a demo video on my website and blog soon.

Link to comment
Share on other sites

The error message indicates that you are trying to set a parameter that expects an integer or float with text (a string). You need to ensure your data is a number and cast it to one of those data types in order to set the parameter.

Link to comment
Share on other sites

One thing I remember from using custom GUI toolkits is that most of them tend to use their own string class to represent strings. Houdini can set numeric parameters using number values as normal Python strings like the following, but other custom string types tend not to work unless you manually cast them.

myparm.set("55")

A better, and necessary approach for using other string types is:

val = somecustomstringtype
myparm.set(float(val))

Edited by graham
Link to comment
Share on other sites

One thing I remember from using custom GUI toolkits is that most of them tend to use their own string class to represent strings. Houdini can set numeric parameters using number values as normal Python strings like the following, but other custom string types tend not to work unless you manually cast them.

myparm.set("55")

A better, and necessary approach for using other string types is:

val = somecustomstringtype
myparm.set(float(val))

For this do I need to define float, or just type the correct string? Still a little confused. Reading the wxPython page to see if I can find it. Will let you know if I find it; hopefully before the next reply to this post.

Link to comment
Share on other sites

So while trying to fix this problem and an issue with the GUI, I some how managed to mess up my fx tool. It no longer works properly. The make popnet button works and the collision options work. All the sliders no longer "work", however the GUI for the sliders works now. The numbers/labels for it change as you scroll, but they don't change the houdini parameters they're suppose to. And I'm still having the problem with the previous problem with the text box. I want them to recognize both numeric numbers and hscript expressions. Here's the code. I've been trying to fix this for over a week, and somehow keep making it worst, so any help, tips or suggestions would be much appreciated. Thanks.

import sys, threading, wx
if __name__ != "__main__":
    import hou
    import toolutils 

def exc_log():
    print "Exception: '%s' on line %d" % (sys.exc_value, sys.exc_traceback.tb_lineno)

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFxTool(None, -1, 'Rain System Tool')
        frame.Show(True)
        self.SetTopWindow(frame)
        return True


# Creates the Window
class MyFxTool(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size (450, 320),
                          style = wx.CAPTION | wx.SYSTEM_MENU | wx.CLOSE_BOX | wx.STAY_ON_TOP)
        self.sizer= wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.sizer)
        self.panel= MyFxToolPanel(self)
        self.sizer.Add(self.panel, 1, flag= wx.EXPAND)
        self.Layout()


# Creates the Layout
class MyFxToolPanel(wx.Panel):
    def __init__(self, parent):
        super(MyFxToolPanel, self).__init__(parent)
        self.sizer= wx.BoxSizer(wx.VERTICAL)
        self._add_flex_grid()
        self.SetSizer(self.sizer)

    def _add_flex_grid(self):
        self.flex_grid_sizer= wx.FlexGridSizer(cols= 2, vgap= 10, hgap= 70)
        self.sizer.Add(self.flex_grid_sizer, 1, border= 20, flag= wx.ALL|wx.EXPAND)
        self._add_static_text("Rain System Tool")
        self.start_button= self._add_button("Make It Rain")
        self._add_static_text("Amount of Rain")
        self.amount_slider= self._addAmount_slider()
        self._add_static_text("Rain Speed")
        self.r_speed_slider= self._addSpeed_slider()
        self._add_static_text("Direction")
        self._add_wdirection()
        self._add_static_text("Turbulance")
        self.turb_slider= self._addTurb_slider()
        self._add_static_text("Life")
        self.life_slider= self._addLife_slider()
        self._add_static_text("Collisions")
        self._add_colisions()
        self._add_static_text("Bounce")
        self.bounce_slider= self._addBounce_slider()

###########################################################################   
####################### PARAMETER CONTROLS ################################
###########################################################################

    def _add_static_text(self, label_text):
        static_text= wx.StaticText(self, label= label_text,
        style= wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
        self.flex_grid_sizer.Add(static_text, flag= wx.ALIGN_CENTER_VERTICAL)

    def _add_button(self, label_text):
        button= wx.Button(self, label= label_text)
        button.Bind(wx.EVT_BUTTON, self.OnClickAdd)
        self.flex_grid_sizer.Add(button, flag= wx.ALIGN_CENTER_VERTICAL)
        return button

    def _addAmount_slider(self):
        slider= SliderAndStaticText(self)
        self.flex_grid_sizer.Add(slider, flag= wx.ALIGN_CENTER_VERTICAL)
        return slider.slider

    def _on_amount_slider(self, event):
        print event.GetPosition()
        event.Skip()

    def _addSpeed_slider(self):
        slider= SliderAndStaticText(self)
        self.flex_grid_sizer.Add(slider, flag= wx.ALIGN_CENTER_VERTICAL)
        return slider.slider

    def _addTurb_slider(self):
        slider= SliderAndStaticText(self)
        self.flex_grid_sizer.Add(slider, flag= wx.ALIGN_CENTER_VERTICAL)
        return slider.slider


    def _addLife_slider(self):
        slider= SliderAndStaticText(self)
        self.flex_grid_sizer.Add(slider, flag= wx.ALIGN_CENTER_VERTICAL)
        return slider.slider

    def _add_wdirection(self):
        wdirection_sizer= wx.BoxSizer(wx.HORIZONTAL)
        self.flex_grid_sizer.Add(wdirection_sizer, flag= wx.ALIGN_CENTER_VERTICAL)
        self.x_value= self._add_letter_value("X:", wdirection_sizer)
        wdirection_sizer.AddSpacer(20,0)
        self.y_value= self._add_letter_value("Y:", wdirection_sizer)
        wdirection_sizer.AddSpacer(20,0)
        self.z_value= self._add_letter_value("Z:", wdirection_sizer)
        self.x_value.Bind(wx.EVT_TEXT, self.enterText)
        self.y_value.Bind(wx.EVT_TEXT, self.enterText)
        self.z_value.Bind(wx.EVT_TEXT, self.enterText)


    def _add_letter_value(self, letter_text, sizer):
        x= wx.StaticText(self, label= letter_text)
        sizer.Add(x, flag= wx.ALIGN_CENTER_VERTICAL)
        text_ctrl= wx.TextCtrl(self, size= (40, -1))
        sizer.Add(text_ctrl, border= 2,
            flag= wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
        return text_ctrl



    def _add_colisions(self):
        colisions_sizer= wx.BoxSizer(wx.HORIZONTAL)
        self.flex_grid_sizer.Add(colisions_sizer, flag= wx.ALIGN_CENTER_VERTICAL)
        self.collide_on= wx.CheckBox(self, label= "On/Off")
        colisions_sizer.Add(self.collide_on, 0, flag= wx.ALIGN_CENTER_VERTICAL)
        self.collide_on.Bind(wx.EVT_CHECKBOX, self.CheckOn)
        self.collide_button= wx.Button(self, label= "Collide With")
        colisions_sizer.Add(self.collide_button, 0, border= 10,
            flag= wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
        self.collide_button.Bind(wx.EVT_BUTTON, self.AddCollision)
        options = ['Die', 'Bounce', 'Stop', 'Stick', 'Slide','Continue']
        self.collide_op = wx.ComboBox(self, value= "", choices = options, id=5)
        self.collide_op.Bind(wx.EVT_COMBOBOX, self.SelectBehavior)
        colisions_sizer.Add(self.collide_op, 0, border= 10,
            flag= wx.LEFT|wx.ALIGN_CENTER_VERTICAL)

    def _addBounce_slider(self):
        slider= SliderAndStaticText(self)
        self.flex_grid_sizer.Add(slider, flag= wx.ALIGN_CENTER_VERTICAL)
        return slider.slider

###########################################################################   
####################### PARAMETER EVENTS ##################################
###########################################################################


    #Allow you to create the acual rain system.
    #create both SOP and PO nodes.
    def OnClickAdd(self, event):
        geo = hou.node("/obj").createNode("geo", "Rain_System", run_init_scripts = False)
        grid = geo.createNode("grid", "EMIT_FROM")
        grid.setParms({"ty":10})
        popnet = grid.createOutputNode("popnet", "RAIN_EMITTER")
        popnet.setDisplayFlag(1)
        source = popnet.createNode("source", "RAIN_ORIGIN")
        defaultGeo = source.parm("usecontextgeo")
        defaultGeo.set("first")
        birthPlace = source.parm("emittype")
        birthPlace.set("surfacerandom")
        gravity = source.createOutputNode("force", "RAIN_DirCtrl")
        defaultRainDir = gravity.parm("forcey")
        defaultRainDir.set(-4)
        rSpeed = gravity.createOutputNode("drag", "RAIN_Spd_Ctrl")
        defaultRainSpd = rSpeed.parm("scale")
        defaultRainSpd.set(2)
        rSpeed.setRenderFlag(1)
        collide = rSpeed.createOutputNode("collision", "COLLIDE_WITH")

    # Next 3 functions are to create a collision.
    # Once checked render flag(display) switches from drag to collision node.
    def CheckOn(self, event):
        collide = hou.node('/obj/Rain_System/RAIN_EMITTER/COLLIDE_WITH')
        rSpeed = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_Spd_Ctrl')
        if self.collide_on.GetValue():
            collide.setRenderFlag(1)
        else: rSpeed.setRenderFlag(1)

    # Allows the user to select a target for the "soppath" on the collision node once the button is clicked
    def AddCollision(self, event):
        try:
            target = hou.node('/obj/Rain_System/RAIN_EMITTER/COLLIDE_WITH')
            viewer = toolutils.sceneViewer()
            hitMe = viewer.selectObjects(quick_select = True)[-1].path()
            target.parm("soppath").set(hitMe)
        except:
            exc_log()


    # Allows user to switch behaviors for the collision.
    def SelectBehavior(self, event):
        try:
            op = self.collide_op
            colPop = hou.node('/obj/Rain_System/RAIN_EMITTER/COLLIDE_WITH')
            value = op.GetCurrentSelection()
            colPop.parm("behavior").set(value)

        except:
            exc_log()
    # Allows user to change the direction of the particle. Default is already set at -4.
    # Also effects the speed, if drag is low.
    def enterText(self, event):
        try:
            text = self.x_value
            text1 = self.y_value
            text2 = self.z_value
            entered = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_DirCtrl')
            val = text.GetValue()
            val1 = text1.GetValue()
            val2 = text2.GetValue()
            entered.parm("forcex").set(val)
            entered.parm("forcey").set(val1)
            entered.parm("forcez").set(val2)
        except:
            exc_log()



    # Allow the user to adjust ALL sliders

class SliderAndStaticText(wx.BoxSizer):
    def __init__(self, parent):
        super(SliderAndStaticText, self).__init__(wx.HORIZONTAL)
        self.slider= wx.Slider(parent, value= 10, minValue= 1, maxValue= 200)
        self.slider.Bind(wx.EVT_SCROLL, self._on_evt_scroll)
        self.Add(self.slider, flag= wx.ALIGN_CENTER_VERTICAL)
        self.slider_display= wx.StaticText(parent, label= "10")
        self.Add(self.slider_display, flag= wx.ALIGN_CENTER_VERTICAL)

    def _on_evt_scroll(self, event):
        self.slider_display.SetLabel("%s" % (event.GetPosition()))

    def sliderUpdate1(self, event):
        try:
            slider1 = self.slider
            slider2 = self.slider1
            slider3 = self.slider2
            slider4 = self.slider3
            slider5 = self.slider4
            emitHere = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_ORIGIN')
            emitHere2 = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_Spd_Ctrl')
            emitHere3 = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_DirCtrl')
            emitHere4 = hou.node('/obj/Rain_System/RAIN_EMITTER/RAIN_ORIGIN')
            emitHere5 = hou.node('/obj/Rain_System/RAIN_EMITTER/COLLIDE_WITH')
            val = slider1.GetValue()
            val1 = slider2.GetValue()
            val2 = slider3.GetValue()
            val3 = slider4.GetValue()
            val4 = slider5.GetValue()
            emitHere.parm("constantrate").set(val)
            emitHere2.parm("scale").set(val1)
            emitHere3.parm("turb").set(val2)
            emitHere4.parm("life").set(val3)
            emitHere5.parm("bounce").set(val4)

        except:
            exc_log()



class AppThread(threading.Thread):
    def run(self):
        app = MyApp(0)
        app.MainLoop()


if __name__ == "__main__":
    AppThread().start()

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...