Jump to content


  • Content count

  • Donations

    0.00 CAD 
  • Joined

  • Last visited

Community Reputation

2 Neutral

About Alain2131

  • Rank

Personal Information

  • Name
  • Location
  1. how about "total_cooks" mean

    "Total Cook" mean how many times the specified node has needed to cook, meaning process, its input/geometry. For instance, a static box will have only one cook done, regardless of if you scrub the timeline. But if you place a transform node after that box, and put an animated value inside it, the transform node will be cooked (computed, processed, etc.) when the time changes, since it needs to rebuild the geometry at the new emplacement. Also, if you make an Attribute Wrangle (or anything that changes the geometry or any attribute) and you make a change in the Wrangle node, it will be cooked. See "total_cook" to have the example in video. Nota Bene : This is what I understand of it, but I might be wrong. Please correct me if I am.
  2. Extract rotation from packed geometry to a bone (Python)

    I'm not done yet ! Always to make the user's life easier, I'm trying to make the fix automated ! Easier said than done... As of now, I've got a much faster result (15 seconds for 103 pieces for 240 frames), and the user just need to connect the input to the HDA (or input the path to the object) and press Bake ! And it's working perfectly !... For the translation. For the rotation... It's, er, an approximate. The term isn't correct, as I don't throw a guess and have a rotation as a result, it's just the rotation before the needed computation. I just have no idea how to do the said calculation. Yet. If you don't have constraints, and it's just your object blowing up or getting smashed up, you probably won't notice the problem. But if you do have constraints, you'll end up with something like that ↓ Not wildly incorrect, just... Okay, that's incorrect. I'm working on that. EDIT3 : If you've scaled your packed objects before using the tool, it won't work. So for now, forget the scale. Will try to fix that eventually. EDIT4 : With further testing, I noticed that the tool gets all mixed up in certain situations. This has to do with the name attribute and how it's been created. Will fix that eventually. The scene is included below (the cylinder example from above) If you try the classic pighead falling on the ground, you won't notice the problem. I've made an HDA out of it, it's easier to use now. Let me know if it works for you ! P.S. If anybody could here me figure out that rotation problem, I'd be super grateful, it's been a few hours trying to decipher inverse transforms (which I never used and am not sure when to use them), multiplying matrices or making them and whatnot. Cheers ! packed_anim_baker_1.hip Packed_Anim_Baker.hda EDIT : P.P.S. If you want me to make an apprentice version, just ask for it here Although it would not be very useful, as this would mainly be used to be exported over FBX, which is a FX feature... Eh P.P.P.S. Oh ! Also, if someone could give me pointers as to how to have correct exported gizmos so that in Maya, the gizmos are following the objects, that'd be nice too Alright, well, thinking about it, that's not possible, because that would mean that there is some kind of animation on the geometry, with a kind of inverse animation on the gizmo to make the geometry static while the gizmo moves. That's, as far as I know, not possible. And the whole idea is not really useful anyway. EDIT 2 : P.P.P.P.S (this is getting ridiculous) I must say that with the manual fix, the current version of the tool doesn't work properly. It still have some weird rotation. I can fix that (it adds 2 seconds to the whole process though. Not very bad, just slightly annoying.) And, on the down side, the fix actually make the simulation look a bit different. That's weird, and kinda bad. So if you were planning on using the tool with the manual fix, expect the simulation to look a bit different. But if you still want that, you can ask for a version of the tool that works properly with the fix, if you can live with the slightly changed simulation.
  3. Extract rotation from packed geometry to a bone (Python)

    Phew, that was harder than expected ! A few problems arose, that for now I kinda dodged, or more accurately diverted onto the user to fix. Easy fix, do not worry (see file) Here is a working code, but not usable. Working because it actually does the job, not usable for the time it takes to do so. For 104 pieces, 96 frames, it took 50 seconds. If I recall correctly, for the whole 240 frames, it was something like 6 minutes. It works, but it's too long. Wayyy too long. EDIT : I must say I haven't tried sending the result to Maya or other packages yet. It's supposed to work, but eh, not tested. EDIT2 : At the current moment, importing in Maya with FBX works properly. Only drawback is that it floods the Outliner with a bunch of skinCluster and tweakSet. I'm not very used to the Maya-way, so if someone could tell me if there is a way to either get rid of them in Maya or at the export from Houdini, or tell me that it's normal, I'd be grateful P.S. Manually deleting the tweakSets doesn't seem to do anything. The next step is taking the problem from before, the one I diverted on the user, and try to correct it automatically. See code comments and file for reference. node = hou.pwd() obj = hou.node("/obj") def extractEulerRotates(self, rotate_order="zyx", thePivot=(0,0,0)): # Thanks to the Houdini help page for that. return hou.Matrix4(self.extractRotationMatrix3()).explode(rotate_order=rotate_order, pivot=thePivot)["rotate"] # Currently not used, as there is a line that does exactly that (a shorter line, as this is still only one line... whatever xD) def createGeomNodes(pieceName, masterSubnet, boneParent, workingNode, geoSubnet): # Creates a bone and a geometry node fetching the simulation's geometry, and then skins the geometry to the bone with a Capture Proximity. currentBone = masterSubnet.createNode("bone", str("bone_"+pieceName)) currentBone.setFirstInput(boneParent) currentBone.moveToGoodPosition() #initialPosition = workingNode.points()[loopValue].attribValue("P") # Keeping that for reference. #theFullTransform = workingNode.prims()[loopValue].fullTransform() #initialRotation = extractEulerRotates(theFullTransform) skinnedGeo = geoSubnet.createNode("geo", pieceName) skinnedGeo.moveToGoodPosition() skinnedGeo.deleteItems(skinnedGeo.allSubChildren()) # Removes the file node objectMergeNode = skinnedGeo.createNode("object_merge") objectMergeNode.parm("objpath1").set(str(workingNode.sopNode().path())) deleteNode = skinnedGeo.createNode("delete") deleteNode.setFirstInput(objectMergeNode) deleteNode.moveToGoodPosition() deleteNode.parm("group").set("@name="+pieceName) # Putting the piece's name in the group to keep only this one deleteNode.parm("negate").set(1) # Set to Delete Non-Selected deleteNode.parm("entity").set(1) # Set to Points timeShiftNode = skinnedGeo.createNode("timeshift") timeShiftNode.setFirstInput(deleteNode) timeShiftNode.moveToGoodPosition() timeShiftNode.parm("frame").deleteAllKeyframes() # Remove the expression already present timeShiftNode.parm("frame").set(1) # Just to be sure, manually set the frame parameter to 1. Could be useless though unpackNode = skinnedGeo.createNode("unpack") unpackNode.setFirstInput(timeShiftNode) unpackNode.moveToGoodPosition() captureProximNode = skinnedGeo.createNode("captureproximity") captureProximNode.setFirstInput(unpackNode) captureProximNode.moveToGoodPosition() captureProximNode.parm("rootpath").set(str(currentBone.path())) # Set the rootpath to only one bone and not the hierarchy. Easier skinning. deformNode = skinnedGeo.createNode("deform") deformNode.setFirstInput(captureProximNode) deformNode.moveToGoodPosition() deformNode.setDisplayFlag(True) deformNode.setRenderFlag(True) ''' # Applying some color to the skinned geometry. Used for debug attribWrangle = skinnedGeo.createNode("attribwrangle", "color") attribWrangle.setFirstInput(deformNode) attribWrangle.parm("snippet").set("@Cd = {0,0,1};") attribWrangle.moveToGoodPosition() attribWrangle.setDisplayFlag(True) attribWrangle.setRenderFlag(True) # ''' return currentBone # I need the created bone for later reference def bakePackedAnim(): # Saving out some time-related variables intialFrame = hou.intFrame() startFrame = int(hou.hscriptExpression("$RFSTART")) # Don't know how to do it in Python endFrame = int(hou.hscriptExpression("$RFEND")) # Don't know how to do it in Python hou.setFrame(startFrame) workingNode = hou.node("/obj/simulated_geo/OUT_script").geometry() # Gets the geometry. Change this to point to your geometry. <---- masterSubnet = obj.createNode("subnet", "baked_animation") # Will contain all the bones and geometry masterSubnet.moveToGoodPosition() boneParent = masterSubnet.createNode("null", "Parent") # All bones will be parented to this null boneParent.moveToGoodPosition() geoSubnet = masterSubnet.createNode("subnet", "geometry") # Will contain all the geometry geoSubnet.moveToGoodPosition() # I create it here for the moveToGoodPosition to place it where I want geoSubnet.setPosition((0,7)) # And I move it slightly up. This is just to have it at a nice place in the node editor :) # Another nicety would be to set the visible bounds for the view in the node editor. But I don't know how to, and it's not very important. boneList = [] for fragments in workingNode.points(): boneList.append( createGeomNodes(fragments.attribValue("name"), masterSubnet, boneParent, workingNode, geoSubnet) ) # There is no clever thinking into the order of the arguments. # I just made a function and passed the arguments as the errors showed up. =P # Transfers the animation from the specified geometry to the bone # I plan to make this next part into a VEX wrangler instead. The previous part is easier done in Python and is acceptably fast, # but for the next part, Python is very shitty, speed-wise. Will see. for i in xrange(startFrame, endFrame+1): # For some reasons, xrange goes from the correct start value to the end value, minus 1. Strange. for j in xrange(0, len(boneList)): # But xrange works here. Hmmmm. #for j in xrange(9, 10): # Used for debug currentBone = boneList[j] hou.setFrame(i) initialPosition = hou.Vector3(hou.node(geoSubnet.path() + "/piece" + str(j) + "/timeshift1").geometry().points()[0].attribValue("P")) theFullTransform = workingNode.prims()[j].fullTransform() #thePosition = workingNode.points()[j].attribValue("P") #initialPosition = hou.Vector3(workingNode.points()[j].attribValue("P")) #theRotation = extractEulerRotates(theFullTransform, initialPosition) #thePivot = hou.Vector3(workingNode.prims()[j].intrinsicValue("pivot")) thePosition = theFullTransform.extractTranslates("srt") # Get the transform information from the Identity Matrix # thePosition += initialPosition # Move to the right position # The previous line is required if the identity matrix hasn't been correctly set. See wall of text below. # As of now, the position is correct. # BUT THE ROTATION ISN'T # The problem is that it still rotates around the old pivot point, the one before the "thePosition += initialPosition" line. # I've got to figure out how to make the rotation rotate around another center # For now, I'll keep the fix as is and go on with the second option # The fix is in simulate_geo, in the input 0 of the switch # All it does is correctly populate the identity matrix before the simulation (see comment just before this wall of text) # The second option is doing this after the simulation, in a for-each loop nested into the HDA that this will become # I'm letting all the commented tests here for future reference if needed. # The problem is in Python, this code is utterly slow # For 104, 96 frames, it took 50 seconds. That's wayyy too much for wayyy too few pieces. # All the commented code is some tests to manually rebuild the identity matrix to be able to have to right rotation. # Without success. # Next step is described above. #print theFullTransform #theFullTransform.setAt(3,0,thePosition[0]) #theFullTransform.setAt(3,1,thePosition[1]) #theFullTransform.setAt(3,2,thePosition[2]) #print theFullTransform #print "\n" #initialPosition = hou.Vector3(workingNode.points()[j].attribValue("P")) #initialPosition = hou.Vector3(thePosition) #print initialPosition #theRotation = theFullTransform.extractRotates(transform_order="srt", rotate_order="zyx", pivot=initialPosition) #initialPosMatrix = hou.hmath.buildTranslate(initialPosition) #modifiedMatrix = theFullTransform + initialPosMatrix #print modifiedMatrix theRotation = theFullTransform.extractRotates(transform_order="srt", rotate_order="zyx") # Position key = hou.Keyframe(thePosition[0]) currentBone.parm("tx").setKeyframe(key) key = hou.Keyframe(thePosition[1]) currentBone.parm("ty").setKeyframe(key) key = hou.Keyframe(thePosition[2]) currentBone.parm("tz").setKeyframe(key) # Rotation key = hou.Keyframe(theRotation[0]) currentBone.parm("rx").setKeyframe(key) key = hou.Keyframe(theRotation[1]) currentBone.parm("ry").setKeyframe(key) key = hou.Keyframe(theRotation[2]) currentBone.parm("rz").setKeyframe(key) hou.setFrame(intialFrame) bakePackedAnim() # Would need to create a UI or a button for convenience, calling this out. packed_anim_baker.hip EDIT : For the ones that doesn't have access to Houdini FX, I'll explain the "diverted-on-the-user" fix. Just before sending the geometry to the simulation, drop down an attribute wrangle, store the current position in a variable, and set the position to the origin. v@oldP = @P; @P = (0,0,0); Then unpack, then pack (make sure to have the same amount of pieces after repacking). This little ping-pong game is absolutely necessary. I suggest using the probably already-present name attribute in the pack node, and to transfer it too, so that you have a name primitive attribute. Then, place an attribute promote to move the name attribute from primitive to the points. Then, place an attribute copy with the attribpromote wired into its left input, and the AttributeWrangle wired to its right input. Use "name" in Attribute to Match, and "oldP" in Attribute Name. It's then just a matter of placing an Attribute Wrangle under all that, like so v@P = v@oldP; Send that to the simulation, and the code will be all too happy to spit out correct position and rotation when you run it later on ! All it does really, is correctly populate the Identity Matrix (see in the Geometry Spreadsheet, Intrinsic "PackedFullTransform"). Without the fix, the position is all zeros, but with it, it has the correct initial positions and will be correctly updated. Yay !
  4. Extract rotation from packed geometry to a bone (Python)

    Well, I've found the reason for why the bone have an incorrect interpretation of the rotation information inputted to it. Answer : Rotation Order ! The bones has a rotation order fixed at ZYX. The animation being made in XYZ order, the bone said noppe, I do as I please. For the test case, if I change the rotation order of the keyframe-animated source to match the bone's rotation order, the two animations match. Yay ! Will have to do some test with actual from-dop sim geometry instead of my keyframe-animated test case. EDIT : Well, re-reading my code, I've got a pretty easy fix : it's at the fourth line, it's called "rotate_order" and it's currently set to "xyz". Congrats to me for taking this long to figure this out. >.< Setting this to "zyx" pretty much solves the problem. Will have to do some more test, and I'll post a working solution.
  5. Hello ! I'm trying to get an animation transfer from packed geometry to bone to work. It works when transferring the animation to a geometry (there is no visible problem in the viewport), but in the Animation Editor, the keys are not very clean. See below Here is the nice and tidy one, the source : Here is the result from the script, the baked one : As I said, in the viewport it works, but these keys are not very clean. Why do they look like that ? How to make them cleaner ? (See script and scene below) BUT ! What I really want is to bake the animation on a bone, not on a box. The previous problem still apply to this situation. The position works, but the rotation just fails miserably (with the same code !). The very same rotation is applied to the bone as the previous one that was applied to the test box, but the result in the viewport is not the same at all. The red is the source and the blue is the skinned box (to the visible bone). Why is that ? What am I missing ? Here's the code : node = hou.pwd() obj = hou.node("/obj") def extractEulerRotates(self, rotate_order="xyz"): # Thanks to the Houdini help page for that. But there is a problem here though return hou.Matrix4(self.extractRotationMatrix3()).explode(rotate_order=rotate_order)["rotate"] # The extracted rotation from this function is incorrect. def bakePackedAnim(): # Saving out some time-related variables intialFrame = hou.intFrame() startFrame = int(hou.hscriptExpression("$RFSTART")) # Don't know how to do it in Python endFrame = int(hou.hscriptExpression("$RFEND")) # Don't know how to do it in Python hou.setFrame(startFrame) # ''' # Initial setup : Creates a bone and a box, and then skins the box to the bone with a Capture Proximity. theBone = obj.createNode("bone", "tranformed_bone") # Create only one bone. Would put it in a loop to create multiple. # theBone.moveToGoodPosition() # Easier to work without it. Will uncomment in the end # TO REMOVE... But weirdly with -not a bone- it's working. Hmmm. testGeo = obj.createNode("geo", "test_geo") fileNode = testGeo.allSubChildren()[0] testTransform = testGeo.createNode("xform") testTransform.setFirstInput(fileNode) testTransform.moveToGoodPosition() testTransform.setDisplayFlag(True) testTransform.setRenderFlag(True) # Remove up to here skinnedGeo = obj.createNode("geo", "skinned_geo") # skinnedGeo.moveToGoodPosition() # Easier to work without it. Will uncomment in the end skinnedGeo.deleteItems(skinnedGeo.allSubChildren()) # Removes the file node boxNode = skinnedGeo.createNode("box") captureProximNode = skinnedGeo.createNode("captureproximity") captureProximNode.setFirstInput(boxNode) captureProximNode.moveToGoodPosition() captureProximNode.parm("rootpath").set(str(theBone.path())) deformNode = skinnedGeo.createNode("deform") deformNode.setFirstInput(captureProximNode) deformNode.moveToGoodPosition() #deformNode.setDisplayFlag(True) #deformNode.setRenderFlag(True) # Applying some color to the skinned box attribWrangle = skinnedGeo.createNode("attribwrangle", "color") attribWrangle.setFirstInput(deformNode) attribWrangle.parm("snippet").set("@Cd = {0,0,1};") attribWrangle.moveToGoodPosition() attribWrangle.setDisplayFlag(True) attribWrangle.setRenderFlag(True) # ''' # Transfers the animation from the specified geometry to the bone workingNode = hou.node("/obj/animated_box/OUT_script").geometry() # Gets the geometry of my test scenario for i in xrange(startFrame, endFrame+1): # For some reasons, xrange goes from the correct start value to the end value, minus 1. Strange. hou.setFrame(i) theFullTransform = workingNode.prims()[0].fullTransform() thePosition = workingNode.points()[0].attribValue("P") # This code works only for one object. Would do a loop here through all the pack geo. theRotation = extractEulerRotates(theFullTransform) # Got a problem with how this function extracts the rotation # Position key = hou.Keyframe(thePosition[0]) theBone.parm("tx").setKeyframe(key) testTransform.parm("tx").setKeyframe(key) key = hou.Keyframe(thePosition[1]) theBone.parm("ty").setKeyframe(key) testTransform.parm("ty").setKeyframe(key) key = hou.Keyframe(thePosition[2]) theBone.parm("tz").setKeyframe(key) testTransform.parm("tz").setKeyframe(key) # Rotation key = hou.Keyframe(theRotation[0]) theBone.parm("rx").setKeyframe(key) testTransform.parm("rx").setKeyframe(key) key = hou.Keyframe(theRotation[1]) theBone.parm("ry").setKeyframe(key) testTransform.parm("ry").setKeyframe(key) key = hou.Keyframe(theRotation[2]) theBone.parm("rz").setKeyframe(key) testTransform.parm("rz").setKeyframe(key) hou.setFrame(intialFrame) bakePackedAnim() # Would need to create a UI or a button for convenience, calling this out. And the scene : packed_anim_baker.hip Thanks ! EDIT : P.S. If I copy and paste relative reference from the source's rotation to the bone's rotation, the result is the same : obviously wrong rotation.
  6. Group in dops [SOLVED]

    The answer is here, in the third paragraph -"If the drag value is very large with respect to the timestep, some solvers can experience instability." Upping the substep significantly solved the problem (to 15 in my case, although it depends on the drag's value). For the clean sop, I'm not sure how you would use it to correct a dop's nan error, plugging it before or after the dopimport in sopland didn't do the trick. But hey, upping the substep helps ! Thanks again
  7. Group in dops [SOLVED]

    Weird things happens sometimes though - I get "-nan(ind)" positions, and my object(s) dissapear. Strange. If you know right away what the problem is, great ! If not, then that's alright, I'm going to investigate ! group_in_dops_nan.hipnc EDIT : Well, there doesn't seem to be much people on the internets who have this problem, so, darn it But ! I think this happens only when the drag force is too strong. In my case this doesn't pose a problem, but it's still a bit strange. [SOLVED]... kinda Good day !
  8. Group in dops [SOLVED]

    Well, that did the trick ! Thanks a lot ! Have a good day group_in_dops[SOLVED].hipnc
  9. Group in dops [SOLVED]

    Hey Dominik, thanks for you answer ! I actually tried the Pop Group, but I get an error on the node ( merge1: Error: Connection to input 1 is the wrong type. Connection to input 2 is the wrong type. ) I don't know what I did wrong. Why is it throwing me this error ? I never used POP Forces in dops, I don't know if there is a certain way to plug them up. Thanks ! group_in_dops.hipnc
  10. Group in dops [SOLVED]

    Hello ! I'm trying to apply a force in dops to some packed geometry based on some rule. For the test, I use a group that have "@P.y<2.5" in its expression box, and use this group inside of a drag node. But for some reasons, it's not working properly. I never used the group node in dops before, so maybe I'm missing something. Not working properly being the force still applied to the geometry, even though the geometry is clearly above 2.5 in y position. Anyone have an idea ? Thanks ! group_in_dops.hipnc
  11. Adding temperature to flip sim

    Hello ! I'm trying to add temperature to a flip sim, but it doesn't seem to work well... I have bubbles going through the particles and affecting them with their velocity, but the temperature doesn't seem to be added. Each of these bubbles/strands/thingy are supposed to be white. The bubbles are converted to a VDB, with wich I specify to transfer vel and temperature (temperature's been set to a static float value prior to it). Scene included below. Thanks ! temperature_flip_test.hipnc
  12. Creating Uvs for viscous flip sim

    Hey @Flamingburrit008, I'm having the same problem as you do ! Sorry, haven't figured it out either. I provided an example scene below where we can see the issue. This picture below is the result I have from the video - the same result as a planar uv projection. If somebody could have some pointers as to how to use the rest position for UVs, I'd be grateful ! Thanks ! flip_uvs.hipnc
  13. Sorry for double-post (triple if we count yesterday's), but here's a little change in logic, should be more optimized now : for( int i=0; i<len(f[]@boneCapture_data); i++ ) { if(f[]@boneCapture_data[i] == 0.0 ) { setpointattrib( 0, "boneCapture_data", @ptnum, slice( f[]@boneCapture_data, 0, i ), "set" ); setpointattrib( 0, "boneCapture_index", @ptnum, slice( i[]@boneCapture_index, 0, i ), "set" ); break; } } Cheers !
  14. Well, I figured out how to do it in VEX. int success = 0; // Don't know why this is not optional float data_array[] = pointattrib( 0, "boneCapture_data", @ptnum, success ); float index_array[] = pointattrib( 0, "boneCapture_index", @ptnum, success ); for( int i=0; i<len(data_array); i++ ) { pop(f[]@boneCapture_data); // Would need a more efficient way to clear the current point's array data pop(i[]@boneCapture_index); } for( int i=0; i<len(data_array); i++ ) { if(data_array[i] != 0.0 ) { setpointattrib( 0, "boneCapture_data", @ptnum, data_array[i], "append" ); setpointattrib( 0, "boneCapture_index", @ptnum, index_array[i], "append" ); } } I heard that Python is pretty slow compared to VEX, so I thought why not. And it turned out easier to do. delete bone from skin_1.hipnc
  15. Hello there ! I'm looking for a way to replicate the "prune small skin weights" of Maya into Houdini. I've found the capture correct node, in which I can clamp the weights. The thing is, the bones are still weighted to the points, just with a zero weight. I want the bone to be removed from the list altogether. Is there a way of doing that ? The "Regions to Remove" field sounds promising, but I haven't been able to do anything with it. If you can answer the previous question, then the rest is not usefull anymore. But if you can answer it too, I'll be a happy little Houdini user grateful. Instead, I tried to do it manually. I dropped down a capture attrib unpack and a python node in which I recreate the arrays without the zero-weight bones. The thing is, I can't find how to create an array attribute on the points ! What is the correct syntax ? I've tried node = hou.pwd() geo = node.geometry() geo.addAttrib(hou.attribType.Point, 'myAttrib', [ 1, 2, 3 ]) but this creates 3 attributes myAttrib[0] myAttrib[1] myAttrib[2]. Thanks ! delete bone from skin.hipnc EDIT : Real-time update : Figured how to create an array attribute : geo.addArrayAttrib( hou.attribType.Point, "myAttrib", hou.attribData.Float, 1 ) geo.addArrayAttrib( hou.attribType.Point, "myAttrib", hou.attribData.Float, 1 ) But now I've got to figure how to populate it.