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 |
.Enable
the Particle Shape and Particle Position channels
Take
a scene object with a MultiRes modifier on top.
Loop
trough all particles in the Particle Container.
For
each particle, get the particle position, measure the distance to a scene
camera, calculate a percentage based on this distance and assign the result
to the Vertex Percentage of the MultiRes modifier.
Get the mesh from top of the stack and assign it to the particle shape.
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. |