Particle Resolution By Camera Distance

This scripted approach is a further development of the example found in the MAXScript Online Help.
 While the Help example uses a Sphere primitive and manipulates its segments based on the camera distance to control the resolution, this version can be used with arbitrary mesh as particle shape. To achieve this, the Particle Flow Script Operator will access and control the optimization values of a MultiRes modifier!

Natural Language
Complete Script

on ChannelsUsed pCont do
(
  pCont.useShape = true
  pCont.UsePosition = true
)

on Init pCont do
(

)

on Proceed pCont do
(
  local mres_obj = $CustomResObject_680217
  local count = pCont.NumParticles()
  for i in 1 to count do
  (
    pCont.particleIndex = i
    mres_obj.multiRes.vertexPercent = (2000.0/(length (pCont.particlePosition- $Camera01.pos)))
    pCont.particleShape = mres_obj.mesh
  )
)

on Release pCont do
(
 
)

Particle View Setup

Final Result

As the particles get farther away from the camera, their resolution changes based on the distance 
thanks to the Script Operator controlling the MultiRes vertex count...

Step-By-Step Comments

on ChannelsUsed pCont do
(

The ChannelsUsed handler defines the channels to be used by the Script Operator - you cannot get or set particle related values from the particle container without specifying which properties you need access to. This way, Particle Flow does not have to provide the Script Operator with all possible channels (and there can be an arbitrary number of channels in Particle Flow) but only with those that are actually needed.
The parameter pCont contains  the Particle Container.

pCont.useShape = true

Since we want to change the shape of the particles, we will need access to the Shape channel.

pCont.UsePosition = true

To measure the distance between the particles and the camera, we will also need the particle's position.

)

on Init pCont do
(

The Init  handler is used to initialize the Script Operator. Usually you define variables and acquire initial values or create objects to be used by the Proceed handler. In our case, we will not use this handler though.
The parameter pCont contains  the Particle Container.

)

on Proceed pCont do
(

The Proceed  handler is called every time the Script Operator is evaluated by Particle Flow. It contains the actual body of the script.
The parameter pCont contains  the Particle Container which contains all particles the Operator is applied to.

mres_obj = $CustomResObject_680217

We access a scene object by name. NOTE that this object must exist in the scene and have the exactly same name for the script to work. There is no "safety net" here, if you delete the object from the scene, the Script Operator will fail.

count = pCont.NumParticles()

Here we read the current number of particles in the particle container. We will access every one of them in the following loop. The reason we assign the value to a variable is that in the for loop that follows, the to limit is evaluated after each cycle of the loop to decide whether the i variable is greater than the limit. Using the pCont.NumParticles() method call inside the for loop would call the method n times where n is the number of particles. With the current code though, the method will be called just once and this will make the script faster!

for i in 1 to count do
(

Now we repeat the following code block for every single particle by using a for loop which counts from 1 to the number of particles. The variable i will contain the current particle index.

pCont.particleIndex = i

In order to work with multiple particles, we have to specify the current particle to access. Setting the .particleIndex property of the Particle Container to the i variable will make the i-th particle the current one. Any subsequent particle property access calls will be directed to that particle!

mres_obj.multiRes.vertexPercent = (2000.0/(length (pCont.particlePosition- $Camera01.pos)))

Here we access a MultiRes modifier which should be on the stack of the custom shape source in the scene. We set the vertexPercent value of the MultiRes modifier to a value calculated by dividing a constant by the distance between a scene camera called Camera01 and the current particle. Obviously, both the Camera and the MultiRes modifier must be present in the scene for the script to function correctly. The result of the calculation will be 100.0% when the distance between particle and camera is 20 or less units. When the particle is 200 units away from the camera, only 10 % of the mesh resolution will be used. At a distance of 2000.0 units, the mesh resolution will be 1% etc.

pCont.particleShape = mres_obj.mesh

Now we can read the current state of the mesh on top of the stack after the multiRes vertex number has been changed. We assign the resulting mesh to the current particle. The .mesh property returns a so-called TriMesh value - the internal representation of a mesh consisting of triangle faces. Getting the .mesh property gives you the result from the top of the modifier stack.
After repeating this for each particle, there will be mesh versions with different vertex counts of the same source object at each particle depending on the distance to the camera!

)

This is the end of the i loop.

)

This is the end of the Proceed handler.

on Release pCont do
(

The Release handler is usually needed to do cleanup work, but we do not need it this time around.

)

Copyright 2003 by Borislav 'Bobo' Petrov.