Sort particle ids by vector


Hi everyone,
I have an object which I use to distribute particles on its surface. What i try to achieve is that I try to sort the particle IDs according to a vector. For example if I had 100 particles covered the surface of a snake model (or a straight line), the Id of the first particle on its nose should be 1 and at the very end of its tail should be 100. Just like the sort sop on houdini if anyone is familiar with that.
I know it may be impossible to change Ids of existing particles but i can also use a duplicate of the particle network and re-align the particles using positions of the duplicate network. I am not that experienced with data operator, but i guess the solution lies there and will probably be much more efficient compared to a scripted approach.
Any help would be appreciated.

Thank you


I would actually suggest trying a simple Birth Script operator to create a new system with the desired order. All you need to do is

*Get the indices of all the source particles in one array, and their positions in another.
*Use qsort() to sort the Index array by the Position length relative to the “front” reference position or whatever logic you want (see example in MXS docs for indexed sort)
*Now run a for loop creating new particles based on the sorted Index array, reading any of their channels and giving birth to new particles and assigning them the same values.

The resulting system should have the IDs running front to back, while mimicking the look of the original system.

In fact, I created a test scene and it seems to work ok (except you need to toggle the copy system off and on again if you make changes to the original). It is in Max 2013 format and is attached.

In the example, I created a Cylinder, moved and rotated it to be in some arbitrary place and orientation. I then created a default PFlow on its surface, with random Speed and Rotation. Its particles are blue and shown as ticks. You can turn on the display of the IDs to see they are random.

I then created a second PFlow with Birth Script as described above. It uses the Pivot Point of the Cylinder as the reference position and sorts the source particles’ index array based on their distance to that point. Then it creates new particles that acquire the Transform (position, rotation and scale), the Speed, and the Shape of the original particles. These new particles are shown as Geometry in red and have the ID displayed so you can see it runs bottom to top along the Cylinder.


Bobo I honestly don’t know where you find all this time to deal with all the problems people have. I was almost sure that you will be the one answering my question while asking. The best part is, you both give the fish and teach how to catch the fish.

I cant thank you enough. Not only for solving this particular issue, but also helping me -and all society- to solve countless problems during the last ten years.

I am still processing the script but I got the idea. Thank you again.


You don’t know how fitting that analogy really is :slight_smile: …or maybe you do

findString "Thanks for all the fish!" "all" -- returns 12

QFA :slight_smile:


Thanks for the {flowers|kind words|fish}! :slight_smile:
In reality I barely found the time to answer that post, I have been too busy lately with all the Stoke, Krakatoa and whatnot (wait for Siggraph to see;) ). But since I did not know the answer, I was curious if my idea would work, so I sat down to test it and then sent you the scene…

John, I wish that example in the Help returned 42. THAT would have been fitting.
I looked and the song from the Disney movie kinda works

findString "So long, so long, so long and thanks for all the fish!" "all" -->42

I will change that next year if I get to edit the docs again.


Hah! funny that works! :slight_smile:


I certainly know the line but I didn’t intentionally make the analogy fit :slight_smile:

Before seeing Bobo’s reply, as a workaround I tried to create the particles and sort them in houdini. Then I have written the initial particle state as .prt. You know the rest.
(since this is not the houdini forum, I will skip the details, anyone who wants the details can contact me.)

Then I realized I even dont need the particles in houdini. PRT loader is also capable of turning scattered points into particles. If there are no Particle IDs, it automatically assigns according to the creation order (vertex point number) of point, which is exactly what I am looking for.

I probably both use this and Bobo’s solution, according to the particle count.


If it is as simple as matching the particle ID to the matching vertex you could do something like this with a data op.


Thank you Johnny. I actually thinked about that, but vertex points wont be enough and easy to control all the time.
What I have done in Houdini is basicly scattering points on the surface of object just like the “position object” operator. Although they are not actually particles (just floating verices) prt loader can assign particle ID’s on each point according to the Vertex ID - which I already sorted.
In some scenes which needs to be more procedural, I will use Bobo’s approach but most of the time it will slow me down too much since there will be hundreds of thousands particles.

Thank you for the file though, It will be handy sooner or later.



I tried a simpler approach. Actually this one works best in my case and probably faster than other approaches. I was not happy with using two identical pf sources, because since I already have to use another one to store target vectors for each piece I had to build 3 seperate systems.
This time, I am not creating a new particle system based on the positions of another one, but re-position the existing particles using a script operator. It is based on Bobo’s birth script approach, but needs only one pf source.

Below script operator example sorts the particles on z axis, but you can also change the compare function to sort the particles according to the distance of an object.

on ChannelsUsed pCont do
	pCont.useTime = true
	pCont.usePosition = true

on Init pCont do 

on Proceed pCont do 
	if (currentTime < 2f ) do 
	count = pCont.NumParticles()

	posArray = #()
	indexArray = for i = 1 to count collect
			pCont.particleIndex = i
			append posArray pCont.particlePosition
fn compareFN v1 v2 valArray: =
		local refPos = $Cylinder001.pos
		local v1i = valArray[v1]
		local v2i = valArray[v2]
		if (distance v1i refPos) > (distance v2i refPos) then 1 else -1

fn compareFN v1 v2 valArray: =
	local v1i = valArray[v1].z
	local v2i = valArray[v2].z
	local d = (v1i) - (v2i)
		case of
			(d < 0.): -1
			(d > 0.): 1
			default: 0

		posArray = #()
		indexArray = for i = 1 to count collect
			pCont.particleIndex = i
			append posArray pCont.particlePosition

	qsort indexArray compareFN valArray:posArray



	for x = 1 to count do
	pCont.particleIndex = x




on Release pCont do 


a simple vanilla approach:

birth particles from frames -10 to 0. Have an emitter move from the beginning to end of your snake model. This way the particles id’s are arranged by time of birth. You can use a lock/bond snap to object setting to have positions snap to your snake if needed. TADA!


Actually the snake was an example to easily express my intention. I have used several different shaped 3d models (Huts, Humans, buildings etc.) some of them are even animated.

Anyway, that project is finished quite a while ago but I still want to find a better and faster solution for the future.

I think the best and fastest solution would be implementing the script to a data operator, but since I am not that experienced with data operators I couldnt find a way to do that.

I was hoping that someone more experienced with data operator may give me a clue about that. Basically I need to find a way to make an array of all particle positions inside data operator and sort that array somehow. It may be passing the limits of data operator but I have a feeling that there should be a way to do that.



Well the arrays of data are already with the Data op depending on what channels you are requesting.

This may or may not be of interest to you. Bobo showed me an excellent example to organize multiple shapes. The basic idea was to count the number of vertices in the particle shape instance to give you specific groups (hats, humans, huts, ect), then you could organize them within the group by say distance from a point and assign an integer. You would more than likely use the Script Vector channel (or if you need more channels you have 99 Mapping channels you can fill too) so you could assign it a group integer [X,0,0], the distance from something [0,Y,0], and the individuals current Birth ID [0,0,Z]

This would give you a full vector [X,Y,Z] of data to manipulate. I attached a simple example that demos acquiring and storing.


Thank you Johnny. At first glance it seems that I can learn things from that example. I will take a deeper look and share the results here (if any)

Thanks again.