Looping particle positions
#1
I've been banging my head against an effect I'm trying to achieve with tyFlow and I think I've reached the point where my ignorance is getting the way.

I'm trying to loop a simple animation, very similar to the various tests people have been doing with reforming objects from particles. So far I've been using the Custom Proprties to store the Custom TM and then Find Target to return them to this location/orientation - so far, so good! However, what I really want to do is have the particles return to their original locations, over time, as the emitter geometry is also travelling and this is where I'm stuck.

If I set the timing of the Custom Properties operator to a time range, does it store the transform matrix information for each frame? Is it possible to interpolate those positions back over time, not as in the interpolate value in the CustomTM section but so that the particles seek the position that they should be on that frame?

If not, is there another way to store the particles positions for a set of frame and then call those back, either through scripting or using cache or even driving a new flow from the first?

My apologies if this doesn't make any sense. The scene I'm working is a bit of a mess, but I will try and work up a simplified version and upload it.
  Reply
#2
I think I've understood what you need. In PFlow, I do that with a proxy system (with the same number of particles, with lockbond to the emition object) that retains the information of where the particles should find the target (the original TM of the time they leave the emition object). The emition object can be an animated one, no problem. Below the Lockbond operator on the Proxy system, I put a data operator that is always recording and stores the particles TM. Thus, every time I want them to get back to their original position on the animated object, I put a find target operator looking at a script vector and a data operator below that that refers and gets the stored original TM of the proxy system.

I guess that it could only be done in Tyflow via scripting for now... Am I wrong?
  Reply
#3
Yep, what you've described is pretty much the exact setup I'm trying to replicate. I'm going to see if I can script it based upon a few of Tyson's examples.
  Reply
#4
So basically you want the targets to follow the animation on the target object, but when storing custom properties the particles are going back to their saved location at frame 0, instead of where the object is at frame 50 (or whatever)?

You'll definitely need a script operator for this, it's just a matter of saving your transforms in local space and retrieving them relative to the object's TM.

So basically your script would be something like this (not sure if this compiles, it's off the top of my head but it looks ok at a glance):

Code:
//...inside the particle loop
if (tf.EventAge(sInx) == 0)
{
    tf.SetCustomTM(sInx, "localTM", tf.GetTM(sInx) * Inverse(obj001.GetTM()); //when particles are born, save their initial offset from the object transform
}

tf.SetCustomTM(sInx, "worldTM", tf.GetCustomTM(sInx, "localTM") * obj001.GetTM()); //continuously update the worldTM channel with the saved localTM x the object's currentTM (ie, the updated TM)

Then you'd put your Find Target operator below this script op, load the target TM from the "worldTM" channel and it would update accordingly.
  Reply
#5
trying to implement this in my flow, but I´m getting some errors:

   
  Reply
#6
(05-15-2019, 10:43 AM)insertmesh Wrote: trying to implement this in my flow, but I´m getting some errors:

try this:


Code:
public void simulationStep()
{


for (int i = 0; i < eventParticleCount; i++) //this for-loop iterates through all particles in this event
{
int sInx = tf.GetSimIndex(i); //for each event particle, we fetch its simulation index

if (tf.GetEventAge(sInx) == 0)
{
tf.SetCustomTM(sInx, "localTM", tf.GetTM(sInx) * Inverse(obj001.GetTM())); //when particles are born, save their initial offset from the object transform
}

tf.SetCustomTM(sInx, "worldTM", tf.GetCustomTM(sInx, "localTM") * obj001.GetTM()); //continuously update the worldTM channel with the saved localTM x the object's currentTM (ie, the updated TM)

}

}


There was a missing closed bracket in this line tf.SetCustomTM(sInx, "localTM", tf.GetTM(sInx) * Inverse(obj001.GetTM()))   -- should have 3x ")" at the end. 
  Reply
#7
Thanks man, how did I not get this right? I added and deleted brackets left and right but apparently I missed the right combo...Wink

This works!
Well...somewhat...
It only works as long as the target shapes transforms end within the time the particles are in the same event as the script. As soon as the particles move to the next event, the tm seems to not be updated anymore and I can´t just copy the script op.

It also doesn´t work on deforming meshes, for that we probably need some more help...
  Reply
#8
(05-16-2019, 03:20 PM)insertmesh Wrote: Thanks man, how did I not get this right? I added and deleted brackets left and right but apparently I missed the right combo...Wink

This works!
Well...somewhat...
It only works as long as the target shapes transforms end within the time the particles are in the same event as the script. As soon as the particles move to the next event, the tm seems to not be updated anymore and I can´t just copy the script op.

It also doesn´t work on deforming meshes, for that we probably need some more help...

Yes it does not work on deforming meshes, but for the event thing, just execute the script again without the localTM.
The localTM is only calculated on frame 0, the worldTM is updated on every frame of the event (multiplying localTM - which is fixed - by the obj TM - which keeps changing).
In the next event just call the same class functions and set the worldTM again, then get it back using custom properties.
So, for example you can in another event do just this:

Code:
public void simulationStep()
{


for (int i = 0; i < eventParticleCount; i++) //this for-loop iterates through all particles in this event
{
int sInx = tf.GetSimIndex(i); //for each event particle, we fetch its simulation index


tf.SetCustomTM(sInx, "worldTM", tf.GetCustomTM(sInx, "localTM") * obj001.GetTM()); //continuously update the worldTM channel with the saved localTM x the object's currentTM (ie, the updated TM)

}

}


and use a custom properties in that event to GET the custom TM and put "worldTM" in the channel box

For the deforming mesh it's trickier and i'm trying to wrap my head around it still.
  Reply
#9
Thanks man, i´ll give this a shot! If you have an idea how to do it with deforming mesh, please let me know!

Or if you have any ressources where I could at least learn the basic syntax of these kinds of scripts...started googling C but that leads to way to many roads to cross...Wink
  Reply
#10
For a deforming mesh you need to be able to construct a TM that can be created at any frame, which will correspond to the same location on the mesh. Obviously the object's TM won't work, but luckily such a TM is easy to construct.

You need 4 vectors to create such a TM: Forward, right, up and translation. The process for creating these is as follows:

First, at frame 0, find the closest point on the mesh and get the face index as well as the barycentric coordinates. From the face, get vertex1, 2 and 3 which create the face.

For the forward vector, use (vertex1 - vertex2) and normalize it.
For the right vector, use the cross product of (vertex1 - vertex2) and (vertex3 - vertex2) and normalize it.
For the up vector, use the cross product of forward and right.
Finally, orthogonalize the TM by resetting the right vector as the cross of up and forward.

For the translation, multiply the barycentric coordinates by the vertex1, 2 and 3 coordinates (v1 * b.x + v2 * b.y + v3 * b.z).

Use all 4 vectors to construct your TM (Matrix3 tm = new Matrix3(forward, right, up, translation); )

Then, store the barycentric coordinates and face index in custom data channels for later access.

Later, at any given frame, reconstruct the TM using the face index (to get v1, v2, v3) and barycentric coordinates. Use the method previous explained in this thread to also get the localTM you'll be storing and loading from using this new deformation-compatible TM.
  Reply
#11
(05-17-2019, 10:37 PM)tyFlow Wrote: For a deforming mesh you need to be able to construct a TM that can be created at any frame, which will correspond to the same location on the mesh. Obviously the object's TM won't work, but luckily such a TM is easy to construct.

You need 4 vectors to create such a TM: Forward, right, up and translation. The process for creating these is as follows:

First, at frame 0, find the closest point on the mesh and get the face index as well as the barycentric coordinates. From the face, get vertex1, 2 and 3 which create the face.

For the forward vector, use (vertex1 - vertex2) and normalize it.
For the right vector, use the cross product of (vertex1 - vertex2) and (vertex3 - vertex2) and normalize it.
For the up vector, use the cross product of forward and right.
Finally, orthogonalize the TM by resetting the right vector as the cross of up and forward.

For the translation, multiply the barycentric coordinates by the vertex1, 2 and 3 coordinates (v1 * b.x + v2 * b.y + v3 * b.z).

Use all 4 vectors to construct your TM (Matrix3 tm = new Matrix3(forward, right, up, translation); )

Then, store the barycentric coordinates and face index in custom data channels for later access.

Later, at any given frame, reconstruct the TM using the face index (to get v1, v2, v3) and barycentric coordinates. Use the method previous explained in this thread to also get the localTM you'll be storing and loading from using this new deformation-compatible TM.

I see. The way i was going about deforming meshes was to try and create a duplicate birth event that stays stuck on the deforming mesh using Object Bind, storing the TM of the particles, then Getting the TMs back by using the index offset you mentioned in another thread.
In your approach, correct me if i'm wrong, but you're basically  doing the following in the step iteration:

For each particle in the event:
Get particle SimIndex
if event age =0 then find the faceID of the closest Face to the particle and store it in a CustomFloat (using simIndex)?

Then when you wanna retrieve the position, in another script Op you would do something like:

For each particle in the event:

get simindex
Get customFloat (simindex)
Get v1, v2, v3
calculate the 3 vectors
Construct the newTM, barycentric coordinate etc..

SetTM(simIndex, newTM)


something like that maybe?

---

Scripting in c# is a really different beast.
  Reply
#12
Pretty close, but you'd be storing both the nearest face index, and barycentric coords....as well as the localTM from frame 0. I can provide a working example next week when I'm back home from my travels Smile
  Reply
#13
Attached is a working example.


Attached Files
.max   deformingTM_01.max (Size: 672 KB / Downloads: 491)
  Reply
#14
(05-20-2019, 04:17 AM)tyFlow Wrote: Attached is a working example.

Ah, sweet, thanks so much!!
  Reply
#15
Hello
Please can some one tell me why it is not working in this scene .

Thank you


Attached Files
.max   deformingTM_01_Help_.max (Size: 616 KB / Downloads: 295)
  Reply


Forum Jump: