few_a_fx Posted March 12, 2011 Share Posted March 12, 2011 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? Quote Link to comment Share on other sites More sharing options...
anim Posted March 12, 2011 Share Posted March 12, 2011 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) Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 13, 2011 Author Share Posted March 13, 2011 Thanks for your help. Will keep you updated on the tool when I'm finished. Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 15, 2011 Author Share Posted March 15, 2011 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. Quote Link to comment Share on other sites More sharing options...
anim Posted March 15, 2011 Share Posted March 15, 2011 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) Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 15, 2011 Author Share Posted March 15, 2011 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. Quote Link to comment Share on other sites More sharing options...
anim Posted March 15, 2011 Share Posted March 15, 2011 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 Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 15, 2011 Author Share Posted March 15, 2011 (edited) 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 March 16, 2011 by few_a_fx Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 16, 2011 Author Share Posted March 16, 2011 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? Quote Link to comment Share on other sites More sharing options...
anim Posted March 16, 2011 Share Posted March 16, 2011 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? Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 16, 2011 Author Share Posted March 16, 2011 (edited) 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 March 16, 2011 by few_a_fx Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 18, 2011 Author Share Posted March 18, 2011 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__": Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 18, 2011 Author Share Posted March 18, 2011 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. Quote Link to comment Share on other sites More sharing options...
graham Posted March 18, 2011 Share Posted March 18, 2011 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. Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 18, 2011 Author Share Posted March 18, 2011 How would you "ensure your data is a number and cast it to one of those data types in order to set the parameter?" Quote Link to comment Share on other sites More sharing options...
graham Posted March 18, 2011 Share Posted March 18, 2011 (edited) 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 March 18, 2011 by graham Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 21, 2011 Author Share Posted March 21, 2011 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. Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 28, 2011 Author Share Posted March 28, 2011 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() Quote Link to comment Share on other sites More sharing options...
few_a_fx Posted March 30, 2011 Author Share Posted March 30, 2011 Got it working again. Still have those minor problems. So I saved a copy just in case I screw up the code again. Hoping to have 1 of the 2 problems fixed today. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.