here is a scripted approach (its a rolling snowball done with scripting, it shows how sticky particles can be achieved without using any operators) its a slow solution and not the best one, i did this long back as a pet project and the file is in 2010 so i just quickly copied a similar setup in 2009 so it can run your machine, to get speed and reality out of a rolling snowball you will need box2 and max 2010. Anyways here’s the setup and the script(s):
in summary : the birth grid script places particles on a plane surface (like a rectangle shape) the script test operator shoots rays from each particle towards the center of the sphere if the length of this ray is lesser than 1 then the face and barry coordinates are stored in the particleinteger, particlevector channel and the particles are passed to the next event where the script operator uses the information in the particleinteger and the particlevector channel to position the particles correctly as the sphere rolls down the hill (it also scales the particles over time, this was done to cheat the growing snow ball effect) (Still confused? look up the mxs help file for intersectrayex function)
-
particle flow setup

-
Birth Grid Script:
on ChannelsUsed pCont do
(
pCont.useTM = true
pCont.usePosition = true
)
on Init pCont do
(
)
on Proceed pCont do
(
currentTick = pcont.gettimeEnd()
if currentTick == 0 then
(
for x = -$rectangle.width/2 to $rectangle.width/2 by 2 do
(
for y = -$rectangle.length/2 to $rectangle.length/2 by 2 do
(
pcont.addparticle()
pcont.particleindex = pcont.numparticles()
pcont.particleTM = $rectangle.transform
pcont.particleposition = ($rectangle.transform.row1 * x) + ($rectangle.transform.row2 * y) + $rectangle.pivot
)
)
)
)
- script test operator (particles close to snow ball?)
on ChannelsUsed pCont do
(
pCont.useInteger = true
pCont.useVector = true
pCont.usePosition = true
)
on Init pCont do
(
)
on Proceed pCont do
(
for i = 1 to pcont.numparticles() do
(
pcont.particleindex = i
--if ((distance pcont.particleposition $sphere.pos) < ($sphere.radius)) do
--(
particleRay = ray pcont.particleposition (normalize ($sphere.center - pcont.particleposition))
resultArray = (intersectRayEx $sphere particleRay)
if (distance resultArray[1].pos pcont.particleposition) < 2 do
(
pcont.particleInteger = resultArray[2]
pcont.particleVector = resultArray[3]
pcont.particleteststatus = true
)
--)
)
)
on Release pCont do
(
)
- script operator (glued particles follow snow ball)
on ChannelsUsed pCont do
(
pCont.useInteger = true
pCont.useVector = true
pCont.usePosition = true
pCont.useScale = true
)
on Init pCont do
(
)
on Proceed pCont do
(
local sphereMesh
currenttick = pcont.gettimeend()
at time currenttick
(
sphereMesh = snapshotasmesh $sphere
)
for i in 1 to pCont.NumParticles() do
(
pCont.particleIndex = i
faceVerts = (getface spheremesh pcont.particleinteger)
particlePosition = [0,0,0]
particlePosition = particlePosition + ((getvert spheremesh faceVerts.x)*pcont.particlevector.x)
particlePosition = particlePosition + ((getvert spheremesh faceVerts.y)*pcont.particlevector.y)
particlePosition = particlePosition + ((getvert spheremesh faceVerts.z)*pcont.particlevector.z)
pcont.particleposition = particleposition
if (pcont.gettimeend() as float) < (ticksperframe * 70.0) do
pcont.particlescale = ((pcont.gettimeend() as float) / animationrange.end.ticks)*12
)
)
the script can definitely be improved and made much more efficient and less memory consuming… (for example you could shoot rays only when particles are close to the bounding box of the geometry) or maybe use a totally different method of computing ray intersections instead of intersectray which is very slow
here is a viewport grab:

[attached max 2009 file]
cheers! 