Texture coord breaking between events

I have a PRT file of a single frame generated from several PRT volumes.

The PRT is accessed via a PRT loader, which is fed into PFlow, with a PRT Birth and PRT Update. The particles are then fed through a krakatoa geometry test and passed to a new event, where they animate away. They are meshed with Frost and rendered.

I need to capture the textureCoords from the original geometry of the PRT volumes, and pass them through to the render. This works fine all the way through the setup, until the particles start to move to the second PFlow event. At that point, the IDs seem to get jumbled up, and the mapping goes haywire.

Is there some way of maintaining the textureCoord information from one event to the next? The total particle count isn’t changing.

Side note - the default geometry meshing options in Frost don’t read the textureCoord channel from the PRT, I have to use custom geometry and make a box for this to work. Is this expected?

Sam

I tested this in a rather simple setup, and at first could not reproduce the issue.
Here is my setup:

*I created a Teapot, a PRT Volume from it (uniform grid), saved to PRT with just Position and TextureCoord channels saved.
*I created the single frame in a PRT Loader, checked “Single Frame Only”
*I created a PFlow, loaded the PRT via PRT Birth. It warned me that there is no ID channel, and told me it would use the Index instead.
*I created a PRT Update right after the Birth and checked the TextureCoord channel.
*I then set up a Collision with a Deflector moving down, set to Continue, so it sends out particles by touch.
*I added a second Event to host the sent out particles, and added a Force with a Turbulent Wind to blow them away.
*I then frosted this PFlow using a custom Box Geometry as you suggested.

RESULT: The particles kept their UVs throughout the simulation, regardless of what Event they were in.

*I tried moving the PRT Update to the global event. I added a global Delete operator to delete by Age and change the count - nothing could break it.
*I rendered it in Scanline to confirm it was working not only in the viewport.

What could be going wrong in your case? Could it be the ID channel? You mentioned “the IDs seem to get jumbled up”. However, PRT Volumes do not generate any IDs, unless you add an ID channel based on the Index channel via Magma. So I resaved the PRT Volume WITH an ID channel, but without generating one. So looking in the Particle Data Viewer, the ID was 0 for every particle. That’s not a good ID to use. But since there IS an ID channel, PFlow started using it when I checked it in the PRT Update operator. As expected, the moment particles started moving from the one event to the other, their mapping in Frost started jumping around.

To solve this, I simply selected the PRT Loader, added a Magma and created InputChannel:Index → OUT:ID. Now PFlow found a consistent ID channel from 1 to N where N is the number of particles. That ID would be loaded by PRT Update and assigned to the particles, tracking them between the events. As soon as I did that, the jumping of the mapping in Frost stopped.

So you have two choices:

  • Do not specify the ID channel for saving when writing the PRT Volumes to PRT - PFlow will warn you that the Index will be used. Since your PRT has only one frame, that is safe to use. Internally, an ID channel will be set to the Index once, and it will persist.
  • Copy the Index to ID on the PRT Loader feeding the PFlow - this does exactly the same with more work on your side :wink:

What not to do:

  • Do not save ID channel from objects that don’t have one (pretty much all PRT objects except a PRT Loader reading a PRT sequence that does have IDs).
  • Do not add the Magma to the PRT Volume before saving it with ID channel - if you have multiple PRTs from multiple PRT Volumes, you might get colliding IDs in the particles from multiple sequences. Generate the ID channel (if you must) on the PRT Loader after the streams are combined, to ensure unique values based on the total combined count.

Yes, it is expected. The primitive geometry shapes bring their own UVs, mainly because you would expect Plane and Sprite to have their own mapping to produce facing particles. So it made sense to keep the same behavior for all other shapes except for Custom Geometry which uses the UVs of the particles instead.

However, this only applies to the TextureCoord channel. So the Box primitive shape in Frost only generates and overwrites the Mapping Channel 1. But if you copy the TextureCoord channel into Mapping2 on the PRT Loader and pass that to PFlow, and frost the PFlow using the built-in Boxes, if the Texture Map is set to use Channel 2, it will see the particles’ data from the PRT Volume, and when set to Channel 1 it will see the Box primitive’s own coordinates.

I will make sure it is mentioned in the documentation…

Hi Bobo,

Thanks as always for your extensive response to my post! I turned the ID channel off when saving and now it works as expected.

I didn’t know that PRT Volumes didn’t generate IDs and trying to save one from them would be problematic. Now that you describe it, it would make sense that multiple PRT Volumes wouldn’t know about each other and wouldn’t be able generate IDs that would take each other into account. I didn’t know that the PRT loader would automatically create an ID channel based on the index if it didn’t find the channel in the file, but that doesn’t happen when saving IDless particles with that channel enabled.

I looked in the channels area of the documentation but there is no mention of the ID channel. I’d love to see a more in depth section which discusses where this is used, what generates it, when it is read from the index, how Pflow then uses it, etc.

For the Frost note, I understand what you are saying. I had assumed that because the custom geometry would also usually come in with UV coordinates, Frost would want to use those first, too. Maybe for future versions a checkbox on the geometry section to select using either UVs from particles to be meshed or from the selected geometry would be handy.

Thanks again.

Yeah, if you enable a channel to be saved and that channel does not exist in the source, it gets saved as default value, usually 0. That’s what happens with PRT Volume and ID - PRT Volume cannot ID a particle because there is no history of birth in PRT Volume. On the other hand, PFlow, TP, RealFlow, Naiad and Stoke track particles through their life by a unique ID, so we support that channel when saving.
If you enabled ID saving, you got a bunch of zeros in the PRT, but the PRT Birth and Update found a valid channel description (they don’t check what the data is), and do not tell you anything. When there is no ID channel at all, the PRT Birth pops up a warning when you pick the PRT Loader, telling you that it has no ID and Index will be used instead. That is usually a very bad thing to use unless all particles are always there, never switch events and never get born or die during the sequence. But with a single frame, nothing can go wrong.

Luckily, I am in the process of converting all documentation to the new Sphinx format, including all Krakatoas. I intend to merge the general information about the renderer (non-application specific) in one place, and provide the Max/Maya/C4D/SR info in separate chapters, but sharing the general info. It will be a bit of work, but it will also allow me to remove old info, refresh the existing and add new info. So keep those suggestions coming!

I agree that an option which channel to use from where would be neat, but right now it is very easy to juggle channels (as Max gives you 100) - if you have a Channel 1 in some mesh but you want it in Channel 10 for some reason, just use Magma to pipe it somewhere else. We consider KMX an extension to Frost workflows, that’s why we encourage people to download the Eval. version of KMX if they don’t have a license to extend their Frost powers…