I’ve finished a rough version of exploding meshes. This code will take a mesh (and a few other params) and make the mesh explode in either a vector impact or bloom method.
I still have a bug with my shadows; they are rotating in all 3 axes though I only want then to rotate in two.
Part 1 of 2 - the Fragment class and functions to explode
--Fragment.lua
Fragment = class()
Fragment.DEFAULT_MASS = 1
Fragment.GRAVITY=9.81 --GRAVITY constant...
Fragment.EXPLODEBLOOM = 1
Fragment.EXPLODEIMPACT = 2
--------------------------------------------------------
-- Creates a fragment object. The mesh that the fragment renders is passed
-- to this function, so a custom mesh could override a fragment of a source mesh
-- if desired.
--------------------------------------------------------
function Fragment:init(params)
self.rotationSpeed = params.rotationSpeed or 10
self.motionSpeed = params.motionSpeed or 100
self.location = params.location or vec3(0,0,0)
self.thisMesh = params.Mesh
self.v = params.velocity or vec3(1,1,1) -- velocity (vec3)
self.life = params.life or 15 -- life cycle, default 1/4 sec
self.scale = params.scale or self.DEFAULT_SCALE -- scale of mesh
--every cycle shrink frag by this multiplier. Keep under 1 to shrink, > 1 to grow.
self.scalediminish = params.scalediminish or .99
self.mass = params.mass or Fragment.DEFAULT_MASS -- mass
--CALCULATE / ASSIGN some items
self.curangle=0
--fudging mass as # of G's in the y direction. Y is up only in this world!
--base acceleration for this fragment
self.acc = vec3(0, -Fragment.GRAVITY*self.mass, 0)
self.lifeLeft = self.life --set up for run, this gets decremented per frame
if params.shadows then
self.shadow=mesh()
self.shadow.vertices = params.Mesh.vertices
self.shadow:setColors(color(0,0,0,64))
end
end
function Fragment:draw()
if self.lifeLeft > 0 then
self.lifeLeft = self.lifeLeft - 1
end
if self.lifeLeft ~= 0 then
pushMatrix()
local x,y,z = GetCenter(self.thisMesh)
translate(self.location.x, self.location.y, self.location.z)
translate(-x,-y,-z)
rotate(self.curangle,1,1,1) --rotation values
translate(-x,-y,-z)
scale(self.scale, self.scale,self.scale) --scale factor overall. static .99 or vec3
self.thisMesh:draw()
popMatrix()
--shadow?
if self.shadow ~= nil then
pushMatrix()
translate(self.location.x, 0, self.location.z)
translate(-x,0,-z)
rotate(90,0,1,0)
rotate(self.curangle,1,0,1) --rotation values
translate(-x,0,-z)
scale(self.scale, self.scale,self.scale)
tint(0, 0, 0, 255)
self.shadow:draw()
noTint()
popMatrix()
end
--set up for next frame
self.curangle = self.curangle + self.rotationSpeed --change rotation angle
self.scale = self.scale * self.scalediminish --change fragment size
--move this fragment. Note that 60 represents FPS.
local curframe = self.life- self.lifeLeft
self.location = self.location + (self.v * (curframe/60))/self.motionSpeed -- hack!!
self.v = self.v + (self.acc * (curframe/60))/self.motionSpeed --change velocity
end
end
--------------------------------------------------------
-- takes a source mesh and creates all of the fragments - as seperate small meshes.
-- this is done so we can rotate, translate and scale pieces seperate that the
-- master body from whence they came.
--------------------------------------------------------
function FragmentMesh(params)
tri = {} tc={} triColor = {}
pos = 0
local meshlist = {}
local triangleCount = 0
local moduloTriangle = params.moduloTriangle or 10
aMesh = mesh()
aMesh=params.Mesh
--explode a mesh
for k,v in pairs(aMesh.vertices) do
pos=pos+1
if (pos > 2) then
triangleCount = triangleCount + 1
if triangleCount == moduloTriangle then
--make new copies of prev mesh
table.insert(tri,aMesh:vertex(k-2))
table.insert(tri,aMesh:vertex(k-1))
table.insert(tri, v) -- aMesh:vertex(k) is the same thing... add the vertex
if (#params.Mesh.texCoords >0) then
table.insert(tc,aMesh:texCoord(k-2))
table.insert(tc,aMesh:texCoord(k-1))
table.insert(tc,aMesh:texCoord(k)) --add the texCoord
end
if (#params.Mesh.colors >0) then
table.insert(triColor, GetColor(aMesh:color(k-2)))
table.insert(triColor, GetColor(aMesh:color(k-1)))
table.insert(triColor, GetColor(aMesh:color(k)))
else
table.insert(triColor, color(255,0,0,255))
table.insert(triColor, color(0,0,255,255))
table.insert(triColor, color(0,255,0,255))
end
exp = mesh()
exp.vertices = tri
exp.colors = triColor
exp.texture = params.Mesh.texture
exp.texCoords = tc
--
--create attributes of this mesh for later use
life = params.life or 60*3 --3 secs to live
sc = params.scale or 1
sd = params.scalediminish ---needed to make a copy to pass it?!
local location = params.location
local mass=params.mass
local hasShadows = params.shadows
if (params.impactVector == nil) then
_, sz = GetBoundingBox(exp)
if sz.x <1 then sz.x=sz.x*2 end
if sz.y <1 then sz.y=sz.y*2 end
if sz.z <1 then sz.z=sz.z*2 end
velocity = vec3(
math.random(-sz.x,sz.x),
math.random(sz.y,sz.y),
math.random(-sz.z,sz.z))
else
if (params.explosiontype == Fragment.EXPLODEIMPACT) then
velocity = vec3(
(math.random(-100,100))/100+params.impactVector.x,
(math.random(-100,100))/100+params.impactVector.y,
(math.random(-100,100))/100+params.impactVector.z)
else
velocity = vec3(
(math.random(-100,100)/100)*params.impactVector.x,
(math.random(-20,100) /100)*params.impactVector.y,
(math.random(-100,100)/100)*params.impactVector.z)
end
end
--print(location)
local param = {life=life, velocity=velocity, mass=mass,
scale=sc, scalediminish = sd,
location=location, rotationSpeed = 15,
motionSpeed = 5, Mesh = exp, shadows = hasShadows}
f = Fragment(param)
table.insert(meshlist, f)
tri = {} tc={} triColor = {}
pos = 0
triangleCount = 0
end
end
end
return meshlist
end