LUA MD5 (skeletal animation etc)
Posted: 01 Aug 2008, 02:34
Seeing as some people
http://spring.clan-sy.com/phpbb/viewtop ... 7&start=20
seem to be quietly working on new animation/model systems, I felt like trying someting too and wanted to make a LUA script for .md5. I have so far managed to draw the contents of an .md5mesh in a basic way (no normals, etc). Unfortunately however, the performance so far really sucks.

This is some crappy .md5 model I found on the internet with apparantly 4372 triangles. This would be the equivalent of about 20 guys with a more reasonable 200polygons for example. Sadly this makes fps go down to around 18. Looking closely at the model, it's really bad, it doesn't even make use of skeletal animation the way it's setup, with one mesh per bone. I couldn't find any of the doom3 models around, might install it to get at them later.
It's probably handling all the weights that slows it down the most, requireing a quaternion rotation (25 multiplications + 25 additions) and all the function calls between the thousands of weights, vertices etc.
I was hoping to maybe unload processing into the vertice shader to circumvent LUA:s disadvantages, but I think one would need to use a geametry shader (nvidia8800+) for this to be feasible. In the end it's probably necessary to go with engine side code to be practical, but I have never felt like going trough with the troubles of setting up the ability to compile the spring source code and then getting intimate enough to work with it.
Anyway it's still useful to me as an experiment to learn stuff, see what can be done etc so I will probably continue a bit more.
Here's the code sofar:
http://spring.clan-sy.com/phpbb/viewtop ... 7&start=20
seem to be quietly working on new animation/model systems, I felt like trying someting too and wanted to make a LUA script for .md5. I have so far managed to draw the contents of an .md5mesh in a basic way (no normals, etc). Unfortunately however, the performance so far really sucks.

This is some crappy .md5 model I found on the internet with apparantly 4372 triangles. This would be the equivalent of about 20 guys with a more reasonable 200polygons for example. Sadly this makes fps go down to around 18. Looking closely at the model, it's really bad, it doesn't even make use of skeletal animation the way it's setup, with one mesh per bone. I couldn't find any of the doom3 models around, might install it to get at them later.
It's probably handling all the weights that slows it down the most, requireing a quaternion rotation (25 multiplications + 25 additions) and all the function calls between the thousands of weights, vertices etc.
I was hoping to maybe unload processing into the vertice shader to circumvent LUA:s disadvantages, but I think one would need to use a geametry shader (nvidia8800+) for this to be feasible. In the end it's probably necessary to go with engine side code to be practical, but I have never felt like going trough with the troubles of setting up the ability to compile the spring source code and then getting intimate enough to work with it.
Anyway it's still useful to me as an experiment to learn stuff, see what can be done etc so I will probably continue a bit more.
Here's the code sofar:
Code: Select all
function widget:GetInfo()
return {
name = "boneanim",
desc = "Skeletal animation",
author = "zpock",
date = "July 28, 2008",
license = "GPL",
layer = 0,
enabled = true -- loaded by default?
}
end
local shieldshader
local joints = {}
local meshes = {}
function widget:Initialize()
io.input("cubby3.md5mesh")
local total = io.read("*all")
_,_,skel = string.find(total, "joints %{(.-)%}")
local i ,j, t = 0, 0, -1
while true do
i, j, nr = string.find(skel, '(".-".-)\n', j+1)
if i == nil then break end
t = t+1
local _,_,name = string.find(nr, '"(.-)"')
local _,_,parent = string.find(nr, '".-" (.-) ')
local _,_,x = string.find(nr, '%( (.-) ')
local _,_,y = string.find(nr, '%( .- (.-) ')
local _,_,z = string.find(nr, '%( .- .- (.-) ')
local _,_,xo = string.find(nr, '%(.-%) %( (.-) ')
local _,_,yo = string.find(nr, '%(.-%) %( .- (.-) ')
local _,_,zo = string.find(nr, '%(.-%) %( .- .- (.-) ')
local joint = {}
joint.name = name
joint.parent = tonumber(parent)
joint.x = tonumber(x)
joint.y = tonumber(y)
joint.z = tonumber(z)
joint.xo = tonumber(xo)
joint.yo = tonumber(yo)
joint.zo = tonumber(zo)
local kuk = 1 - xo^2 - yo^2 - zo^2
if kuk < 0 then
joint.wo = 0
else
joint.wo = -math.sqrt(kuk)
end
joints[t] = joint
end
local i2, j2, t2 = 0,0,0
while true do
i2,j2,s = string.find(total, "mesh %{(.-)%}", j2+1)
if i2 == nil then break end
local verts = {}
local tris = {}
local weights = {}
i ,j = 0, 0
while true do
i, j, nr = string.find(s, "vert (.-)\n", i+1)
if i == nil then break end
local _,_,t = string.find(nr, "(%d+)")
local _,_,u = string.find(nr, "%( (.-) ")
local _,_,v = string.find(nr, "%( .- (.-) ")
local _,_,start = string.find(nr, "%) (%d+)")
local _,_,count = string.find(nr, "%) %d+ (%d+)")
local vert = {}
vert.u = tonumber(u)
vert.v = tonumber(v)
vert.start = tonumber(start)
vert.count = tonumber(count)
verts[tonumber(t)] = vert
end
i ,j = 0, 0
while true do
i, j, nr = string.find(s, "tri (.-)\n", i+1)
if i == nil then break end
local _,_,t = string.find(nr, "(%d+)")
local _,_,v1 = string.find(nr, "%d+ (%d+)")
local _,_,v2 = string.find(nr, "%d+ %d+ (%d+)")
local _,_,v3 = string.find(nr, "%d+ %d+ %d+ (%d+)")
local tri = {}
tri[1] = tonumber(v1)
tri[2] = tonumber(v2)
tri[3] = tonumber(v3)
tris[tonumber(t)] = tri
end
i ,j = 0, 0
while true do
i, j, nr = string.find(s, "weight (.-)\n", i+1)
if i == nil then break end
local _,_,t = string.find(nr, "(%d+)")
local _,_,joint = string.find(nr, "%d+ (%d+)")
local _,_,bias = string.find(nr, "%d+ %d+ (.-) ")
local _,_,x = string.find(nr, "%( (.-) ")
local _,_,y = string.find(nr, "%( .- (.-) ")
local _,_,z = string.find(nr, "%( .- .- (.-) ")
local weight = {}
weight.joint = tonumber(joint)
weight.bias = tonumber(bias)
weight.x = tonumber(x)
weight.y = tonumber(y)
weight.z = tonumber(z)
weights[tonumber(t)] = weight
end
meshes[t2] = {}
meshes[t2].verts = verts
meshes[t2].tris = tris
meshes[t2].weights = weights
t2 = t2+1
end
end
function widget:GameFrame(n)
end
function qmult(qax,qay,qaz,qaw,qbx,qby,qbz,qbw)
local rw = (qaw * qbw) - (qax * qbx) - (qay * qby) - (qaz * qbz)
local rx = (qax * qbw) + (qaw * qbx) + (qay * qbz) - (qaz * qby)
local ry = (qay * qbw) + (qaw * qby) + (qaz * qbx) - (qax * qbz)
local rz = (qaz * qbw) + (qaw * qbz) + (qax * qby) - (qay * qbx)
return rx, ry, rz, rw
end
function qrot(qax,qay,qaz,qaw,qbx,qby,qbz,qbw)
rx, ry, rz, rw = qmult(qax,qay,qaz,qaw,qbx,qby,qbz,qbw)
rx, ry, rz, rw = qmult(rx,ry,rz,rw,-qax,-qay,-qaz,qaw)
return rx, ry, rz
end
function widget:DrawWorld()
local numtris = 0
for key2, value2 in pairs(meshes) do
for key, value in pairs(value2.weights) do
value.xp, value.yp, value.zp = qrot(joints[value.joint].xo, joints[value.joint].yo, joints[value.joint].zo, joints[value.joint].wo, value.x, value.y, value.z, 0)
value.xp = value.xp + joints[value.joint].x
value.yp = value.yp + joints[value.joint].y
value.zp = value.zp + joints[value.joint].z
end
for key, value in pairs(value2.verts) do
value.xp,value.yp,value.zp = 0,0,0
for i = 0, value.count - 1 do
local bias = value2.weights[value.start + i].bias
value.xp = value.xp + value2.weights[value.start + i].xp*bias
value.yp = value.yp + value2.weights[value.start + i].yp*bias
value.zp = value.zp + value2.weights[value.start + i].zp*bias
end
end
gl.DepthTest(true)
gl.DepthMask(true)
gl.PushMatrix()
gl.Translate(100, 100, 100)
gl.Texture('mupp/pCube1_joint1 copy.jpg')
for key, value in pairs(value2.tris) do
gl.BeginEnd(GL.TRIANGLES, function()
gl.TexCoord(0,0)
gl.Vertex(value2.verts[value[1]].xp,value2.verts[value[1]].yp,value2.verts[value[1]].zp)
gl.TexCoord(1,0)
gl.Vertex(value2.verts[value[2]].xp,value2.verts[value[2]].yp,value2.verts[value[2]].zp)
gl.TexCoord(1,1)
gl.Vertex(value2.verts[value[3]].xp,value2.verts[value[3]].yp,value2.verts[value[3]].zp)
end)
numtris = numtris + 1
end
gl.PopMatrix();
end
Spring.Echo(numtris)
end