0 like
0 dislike

I want to be able to use a custom mesh in a Shape Sampler and have my particles spawn at the mesh edges rather than on the surface or inside the volume.

Is this possible?

I had a look through the sample packs and there's an effect called CarTronRed.pkfx which seems to be doing this but I can't figure exactly how. I know it uses a shape sampler of a car (Mustang2014_Low.pkmm) and has ribbon renderers outlining the shape of the car by drawing lines along the car's edges and wheel arches - but I can't see how it's following those paths?

Any pointers on how to achieve this effect would be awesome!

Thanks

Is this possible?

I had a look through the sample packs and there's an effect called CarTronRed.pkfx which seems to be doing this but I can't figure exactly how. I know it uses a shape sampler of a car (Mustang2014_Low.pkmm) and has ribbon renderers outlining the shape of the car by drawing lines along the car's edges and wheel arches - but I can't see how it's following those paths?

Any pointers on how to achieve this effect would be awesome!

Thanks

1 like
0 dislike

Best answer

Hi,

not in a builtin way.

Those example effects were made with a special mesh where the edges were actually very thin quads.

You could do this (in a non-uniform fashion though) by manually building the parametric coords used for sampling in a mesh setup in 'surface' mode.

Here's a regular sample of the surface using pCoords:

int3 pCoords = Mesh.sampleParametricCoords();

Position = Mesh.samplePosition(pCoords);

You can manually build the parametric coordinates of a sample by calling 'Shape.buildParametricCoordsMesh' and passing the triangle ID and the float2 barycentric coordinates in that triangle.

For example, to randomly sample all the triangles at their centers:

int triangleID = int(rand(0, Mesh.triangleCount()));

int3 pCoords = Mesh.buildParametricCoordsMesh(triangleID, float2(0.333));

Position = Mesh.samplePosition(pCoords);

Now, we can construct this float2's x and y based on random values so that the barycentric coordinates are only defined on the edges of the triangle.

The first edge of the triangle has its barycentric coords varying in the range x=[0,0] and y=[0,1] (x stays at 0 and y varies between 0 and 1, 0 being one end of the edge, 1 being the other, 0.5 being the center of the edge, etc)

the second edge is defined by x=[0,1] and y=0

and the third edge must satisfy x+y = 1

For barycentric coordinates to be inside the triangle, the following must be satisfied: x+y <= 1

Here's an example that samples the first edge of every triangle:

int triangleID = int(rand(0, Mesh.triangleCount()));

int3 pCoords = Mesh.buildParametricCoordsMesh(triangleID, float2(0, rand(0,1)));

Position = Mesh.samplePosition(pCoords);

To sample all 3 edges of all triangles, we can use a simple select:

int triangleID = int(rand(0, Mesh.triangleCount()));

float cursor = rand(0,3);

float r0 = remap(cursor, 0,1, 0,1);

float r1 = remap(cursor, 1,2, 0,1);

float r2 = remap(cursor, 2,3, 0,1);

float2 bc = select(float2(0, r0), select(float2(r1, 0), float2(r2, 1 - r2), cursor > 2), cursor > 1);

int3 pCoords = Mesh.buildParametricCoordsMesh(triangleID, bc);

Position = Mesh.samplePosition(pCoords);

Here we generate a random number between 0 and 3, when it falls in the range [0,1[ we'll sample the first edge, when it falls in [1,2[ we'll sample the second, and when it falls in [2,3] we'll sample the third (diagonal).

(it could probably be written more efficiently).

Downside with that "hack" is that you won't get a proper uniform distribution, some edges will appear denser than others.

Proper uniform distribution would require remapping both the triangleID random sample based on each triangle's perimeter, AND changing the locations of the second random 'cursor' split based on the relative lengths of each edge (so that a longer edge gets more samples)

Hope this helps !

Can't believe you gave such a detailed answer so quickly too - thanks!

I'll dive in and have a go at some point - it kinda makes sense in theory from a quick couple of read throughs but I'll have to give it a go to learn it properly.

Luckily in my use case I don't think I'll need uniform distribution, what I have in mind should look good if it's distributed heavier in smaller areas. Good to have the info on how to look into doing that though if I need.

Thanks Julien!

...

For future readers, in v1.12, this is:

int triangleID = int(rand(0, Mesh.triangleCount()));

float cursor = rand(0,3);

float r0 = remap(cursor, 0,1, 0,1);

float r1 = remap(cursor, 1,2, 0,1);

float r2 = remap(cursor, 2,3, 0,1);

float2 bc = select(float2(0, r0), select(float2(r1, 0), float2(r2, 1 - r2), cursor > 2), cursor > 1);

int3 pCoords = shape.buildPCoordsMesh(triangleID, bc); // <--- CHANGE

Position = Mesh.samplePosition(pCoords);

all the parametric-coords building functions have been moved to a "shape" namespace, and are not members of the sampler anymore, as they don't depend nor require an actual sampler to work. Also, all functions containing "ParametricCoords" have been renamed to the more terse "PCoords".