Jump to content

Offset time on Copy to Points

Recommended Posts

Hello All

 I have a little personal project going on, where I have a single rope dangling and want to make multiple copies of it, but I want them to start falling at different times and not all together. I have tried a couple of tutorials on internet and found some explanations in this forum using for loops with a time shift node but it didn't really work. I was wondering what is the solution for that. I tried a couple of rudimentary expressions comparing point numbers to frames to see if I could activate them when the frames are equal to point numbers, but it also didn't work. Anyway I am posting 2 screenshots of my project and I hope you can help me figure it out. 


Thanks in advance




Link to comment
Share on other sites

Many ways to do this. My take:

  1. Put a timeshift node after the file node and add foreach point with the copy to points node second input in the loop coming from the line (look at the picture of the graph).
  2. Click on the Create Meta Input Node. When it creates the node, rename it to something shorter, which you can find later, for example, "shift_iteration".
  3. Go to your timeshift node and add a new integer parameter in your parameter interface (in my case I called it shift).
  4. Edit the Frame parameter in the timeshift node - the default is $F, but you can add data which comes from for-loop by using detail function and taking the value of the attribute "itteration" on the Meta Input Node (in this example: "shift_iteration"). You can check the detail function in documentation, but it is very simple - detail("addres_to_the_node", "attribute_name", index).
  5. Multiply this value to the offset parameter by using ch() function and delete it from the current frame ($F).
  6. The full expression in your timeshift frame parameter will be: $F-detail("../shift_iteration", "iteration", 0)*ch("shift"). By changing the value of the shift parameter on the timeshift node you are making the animation to delay number of frames you define it. If you want them to start at random times, you can either use the sort node at the line, to change the ptnum attribute. Or you can use another expression on the new parameter, by putting shift_iteration into rand function. 

Good luck :) 


Edited by skomdra
  • Like 4
Link to comment
Share on other sites

Hello Sir

Many thanks for taking the time to write such thorough response. Being honest, while waiting for my post to be approved I figure it out by myself and our approach was the same. Your "Ch" input is a bit more elegant though. I'll implement it and save is as an asset. 

This post will surely help other people in the same situation. It took me ages ( I am quite new ) to figure it out and the explanations out there are either old or overcomplicated.

Cheers :rolleyes:

Link to comment
Share on other sites

Another way you can do this is by writing your animation to disk, then loading it back in as a Packed Disk Sequence (the option is on the File SOP). Copy this packed sequence to points, then afterwards you can set the "index" primitive intrinsic to whatever frame (or subframe) you need. 

setprimintrinsic(0, "index", @ptnum, f@some_attribute, "add"); // this would offset the start of each copy by the value of f@some_attribute


Edited by toadstorm
  • Like 2
Link to comment
Share on other sites

I saw a similar post of yours explaining this technique, but as my knowledge is still limited , I couldn't implement it. How do you "set the index" ?  I remember I copied and pasted this snippet to a wrangler but It didn't do much. I am sure I am missing something. Btw I tried my luck at the beginning using the MOPS delay but obviously it didn't work. At the momement I try everything I can until I get it. :ph34r:

Edited by dariosaquetti
Link to comment
Share on other sites

Ah, I mistyped my code up there. Just edited it.

Packed Disk Sequences have an intrinsic primitive attribute called "index"... this refers to the index of the sequence that you want to load, which is generally the frame. It's a float value, because packed disk sequences interpolate between frames. 

If you cache the animation of a single curve to disk, then load it in via a File SOP in Packed Disk Primitives mode, you can copy that one animation to all of your points, then afterwards adjust the timing using that VEX I posted above, or something similar. The relevant function is setprimintrinsic().

If you wanted to do this with MOPs, the right node to use would probably be MOPs Set Sequence Time. You just have to make sure that you are modifying packed disk sequences (or packed Alembics).

Edited by toadstorm
Link to comment
Share on other sites

  • 2 months later...

That is really cool !

If you don't mind me asking, is it possible to use this on a PNG sequence to start the sequence from an attribute on each point ?
 Say I have animated a traditional spark and would like that sequence to be copied to points, and to play from it's first frame whenever a point has it's attribute changed or created ?

I have been trying to find the answer to this for so long. I have learned several ways to do it with cached geometry, but just to apply it to a material/pngs I have been stumped for months.

setprimintrinsic(0, "index", @ptnum, f@some_attribute, "add"); // this would offset the start of each copy by the value of f@some_attribute


Link to comment
Share on other sites

Hmm... what you'd probably want to do here is start by creating an incrementing point attribute on your template points that represents what frame in the sequence you want each copy to load from. For this example, let's call it i@frame. Once you have that, you could create a string primitive attribute on your packed primitives (after the copy operation) that would point to the full path of the texture on disk:

s@texture_path = sprintf("/path/to/textures/root/texture_%g.png", i@frame);

Now that you have this as a primitive attribute, you could leverage material stylesheets to override the emissive texture (or whatever texture) on the material applied to your sparks. Stylesheets are a bit cumbersome to use in Houdini, but they're very powerful and they'll work with any render engine. Once you have a material assigned to your object, go to Inspectors > Data Tree > Material Style Sheets, then create a new stylesheet on the geometry container that your sparks live in. Then right-click the stylesheet in the Data Tree and "Add Style". You can then add a Target of type "Primitive", and then an "Override Script" of type "Material Parameter". Then change the "Override Name" column to the name of the parameter you want to override in your material... if you hover over the name of the material parameter in your shader network, you should see the parameter name. In your case it's probably going to be the emission color texture, which is "emitcolor_texture" in a Principled Shader. The "Override Type" should be "Attribute Binding", because you're using the attribute you created earlier to override the material value. Then set the Override Value to the name of the attribute you created: "texture_path".

Your stylesheet should look something like the attached screenshot.

Once that's done, if you render (and your material is set to be emissive, emissive textures are enabled, and your emission color is 1.0), you should see a unique texture applied to each spark.


  • Like 1
  • Thanks 1
Link to comment
Share on other sites


Thank you so much for the quick and in-depth reply !

I'm only a few months into this amazing Houdini/Vex thing, and I am still a beginner, but I have so much more understanding of these things than I did, thanks in part to the great information you put online.

I have made an attribute based on the frameBorn att in my pops network that records the birth frame of each particle and then freezes on that number.

I've never messed with stylesheets before, but I am going go through what you said step by step this evening to try it out.

Thanks again ! I really appreciate the help. Not knowing this was giving me weird dreams. haha.

Link to comment
Share on other sites

  • 2 months later...

Hi Guys !!

I'm running into a similar situation but couldn't make it work, I have a pre cached SIM which I want to attach to the points when the character is running ,I do have the startFrame numbers which I want to use in the Shift to Frame field of the timeblend sop ,but how can I do that ? I tried the setprimintrinsic(0, "index", @ptnum, @startFrame, "add"); VEX but its causing some random flickers.

Would really appreciate if anyone can help me out.








Link to comment
Share on other sites

35 minutes ago, toadstorm said:

Not sure just by glancing at your network, but it looks like your startFrame attribute is an int. Try changing it to a float?

Also, the viewport will never show time offset sequences correctly. Make sure you render or unpack to get a proper preview.

@toadstorm Thanks for your prompt reply, I tried doing both but still no luck  :( ,Im attaching the hip file and connected data, would really appreciate if you can take a look at it.

Thanks a lot !!





Link to comment
Share on other sites

6 hours ago, toadstorm said:

Try setting your frame intrinsic to @Frame-@startFrame instead, and use "set" in place of "add".

@toadstorm Brilliant !! It worked, thanks a lot.So setting the index back to 0 was the key right ? If you don't mind me asking, how can I attach different wedges of the pre cached SIMs on this ? just by standard switch node or can it be done thru this setprimintrinsic VEX.

Thanks again for your help !! :) 

Link to comment
Share on other sites

  • 1 year later...

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.

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