Metaball Sample Script


The following example shows a sample Metaball script using the Parray particle system.

Can Be Used With:

Should be used in a Script_Operator.



In the Proceed handler, a new Mesh object is created with a vertex at every particle. Then a PArray classical particle system is created and used to generate a metaball mesh out of all vertices of the supplied mesh. Then using a Mesher compound object, a snapshot of the metaball is made and used as the shape of the first particle.



--The ChannelsUsed handler defines the channels

--to be made available to the script.

--For the list of all channels, see

--Interface: MaxscriptParticleContainer

--The parameter pCont passed to the handler

--contains the Particle Container the script is applied to

on ChannelsUsed pCont do


pCont.usePosition = true

pCont.useTime = true

pCont.useSpeed = true

pCont.useShape = true



--The Init hander is called on initialization.

--It is not used in this case.

on Init pCont do




on Proceed pCont do


--Get the start and end times

t1 = pCont.getTimeStart() as float

t2 = pCont.getTimeEnd() as float


--As long as there are particles  

if (pCont.NumParticles() > 0) then


--Disable screen redraws to keep speed up

with redraw off


-- create an empty mesh

nMesh = editable_mesh()

-- Set the number of vertices and faces to the

-- number of particles.

nMesh.numVerts = pCont.NumParticles()

nMesh.numFaces = pCont.NumParticles()

-- We will make a single vertex for each particle

for i in 1 to pCont.NumParticles() do


-- Time for the particle to travel at this integration step

timeStep = t2 - (pCont.getParticleTime(i) as float)

-- Speed is added to foresee the particle position at the end

-- of the integration step

nMesh.verts[i] = pCont.getParticlePosition(i) + timeStep*pCont.getParticleSpeed(i)

-- The faces references the same vertex 3 times!

nMesh.faces[i] = [i,i,i]



-- create PArray with particles on vertices of the mesh

a = PArray()

a.speed = 0

a.formation = 2 -- at all vertices

a.quantityMethod = 1 -- use Total

a.Total_Number = 1 -- just initializing

a.viewPercent = 100

a.Emitter_Start = 0f

a.Emitter_Stop = 0f

a.subsampleCreationTime = off

a.Display_Until = 2000f = 2000f

a.Growth_Time = 0f

a.Fade_Time = 0f

a.particleType = 1 -- metaballs

a.metaballAutoCoarsness = off

a.metaballRenderCoarsness = 0.9

a.metaballViewCoarsness = 0.9

a.Metaparticle_Tension = 1.0

a.size = 5

a.Total_Number = pCont.NumParticles() --use particles count

a.emitter = nMesh


-- acquire the metaball mesh from the PArray

mshr = mesher()  --create a Mesher Compound object

mshr.pick = a  --get the PArray

metaballMesh = snapshot mshr --make a snapshot of the Mesher

delete a   --delete the PArray

delete #(mshr, nMesh) --delete the Mesher and our mesh


-- speed is added to foresee the particle position at the end

-- of the integration step

timeStep = t2 - (pCont.getParticleTime(1) as float)

spaceOffset = pCont.getParticlePosition(1) + timeStep*pCont.getParticleSpeed(1)

-- adjust vertex location to center around the first particle

for i in 1 to metaballMesh.verts.count do

( move metaballMesh.verts[i] (-spaceOffset) )

--Create an empty mesh to assign to all particles

emptyMesh = editable_mesh()

--Assign the empty mesh to all particles.

--This makes them invisible


--First particle carries all the mesh data

pCont.setParticleShape 1 metaballMesh.mesh

--Delete the empty mesh and the snapshot

delete #(emptyMesh, metaballMesh)





--The Release handler is used to do cleanup work.

--Not used in this case.

on Release pCont do




See also

Using MAXScript in Script Actions

Particle Flow Sample Scripts