Added ability to quantize animations to a set of preskinned meshes.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4172 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Andrzej Kapolka
2006-06-06 01:37:34 +00:00
parent cd8c665cf5
commit e3f54a52bb
5 changed files with 167 additions and 5 deletions
+56 -5
View File
@@ -106,6 +106,9 @@ public class Model extends ModelNode
/** The animation transforms (one transform per target per frame). */
public transient Transform[][] transforms;
/** Uniquely identifies this animation within the model. */
public transient int animId;
/**
* Returns this animation's duration in seconds.
*/
@@ -130,6 +133,7 @@ public class Model extends ModelNode
anim.transformTargets[ii] =
(Spatial)pnodes.get(transformTargets[ii]);
}
anim.animId = animId;
return anim;
}
@@ -353,6 +357,13 @@ public class Model extends ModelNode
*/
public void initPrototype ()
{
// assign identifiers to the animations
if (_anims != null) {
int nextId = 1;
for (Animation anim : _anims.values()) {
anim.animId = nextId++;
}
}
setReferenceTransforms();
cullInvisibleNodes();
initInstance();
@@ -396,6 +407,28 @@ public class Model extends ModelNode
updateWorldData(0f);
}
/**
* Sets the resolution at which to quantize animations over time.
* This should be set on the prototype before any animations are
* started or any instances are created.
*
* @param the temporal quantization rate in frames per second, or
* <code>0</code> to disable quantization
*/
public void setAnimationResolution (float resolution)
{
_animResolution = resolution;
}
/**
* Returns the resolution at which animations are quantized over time,
* or <code>0</code> if quantization is disabled.
*/
public float getAnimationResolution ()
{
return _animResolution;
}
/**
* Returns the names of the model's animations.
*/
@@ -654,6 +687,7 @@ public class Model extends ModelNode
mstore._anims = new HashMap<String, Animation>();
}
mstore._pnodes = (HashMap)properties.originalToCopy.clone();
mstore._animResolution = _animResolution;
return mstore;
}
@@ -731,19 +765,35 @@ public class Model extends ModelNode
*/
protected void updateAnimation (float time)
{
float res = (_animResolution == 0f) ?
0f : (_anim.frameRate / _animResolution);
if (_elapsed < res && _elapsed > 0f) {
_elapsed += (time * _anim.frameRate);
return;
}
// advance the frame counter if necessary
while (_elapsed > 1f) {
advanceFrameCounter();
_elapsed -= 1f;
}
float qelapsed = (res == 0f) ?
_elapsed : (res * (int)(_elapsed / res));
// update the target transforms if not outside the view frustum
// update the target transforms and animation frame if not outside the
// view frustum
if (!_outside) {
Spatial[] targets = _anim.transformTargets;
Transform[] xforms = _anim.transforms[_fidx],
nxforms = _anim.transforms[_nidx];
for (int ii = 0; ii < targets.length; ii++) {
xforms[ii].blend(nxforms[ii], _elapsed, targets[ii]);
xforms[ii].blend(nxforms[ii], qelapsed, targets[ii]);
}
if (res != 0f) {
int frameId = (_anim.animId << 16) |
(int)((_fidx + _elapsed)/res);
setAnimationFrame(frameId);
}
}
@@ -822,6 +872,9 @@ public class Model extends ModelNode
* instances. */
protected CloneCreator _ccreator;
/** The resolution of the model's animations in frames per second. */
protected float _animResolution;
/** For instances, maps prototype nodes to their corresponding instance
* nodes. */
protected HashMap _pnodes;
@@ -927,8 +980,6 @@ public class Model extends ModelNode
/** The name of the animation cancelled. */
protected String _name;
}
private static final long serialVersionUID = 1;
}
@@ -342,6 +342,12 @@ public class ModelMesh extends TriMesh
}
}
// documentation inherited from interface ModelSpatial
public void setAnimationFrame (int frameId)
{
// no-op
}
// documentation inherited from interface ModelSpatial
public void writeBuffers (FileChannel out)
throws IOException
@@ -248,6 +248,17 @@ public class ModelNode extends Node
}
}
// documentation inherited from interface ModelSpatial
public void setAnimationFrame (int frameId)
{
for (int ii = 0, nn = getQuantity(); ii < nn; ii++) {
Spatial child = getChild(ii);
if (child instanceof ModelSpatial) {
((ModelSpatial)child).setAnimationFrame(frameId);
}
}
}
// documentation inherited from interface ModelSpatial
public void writeBuffers (FileChannel out)
throws IOException
@@ -63,6 +63,17 @@ public interface ModelSpatial
*/
public void resolveTextures (TextureProvider tprov);
/**
* Recursively sets the quantized animation frame. For skinned meshes,
* the first time the frame is set causes the current skin to be stored
* in a table shared by all instances. At subsequent times, the stored
* skin is displayed.
*
* @param frameId the frame id, which uniquely identifies one frame of
* one animation
*/
public void setAnimationFrame (int frameId);
/**
* Creates or populates and returns a clone of this object using the given
* clone properties.
@@ -40,9 +40,15 @@ import com.jme.math.Matrix4f;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.scene.VBOInfo;
import com.jme.scene.batch.SharedBatch;
import com.jme.scene.batch.TriangleBatch;
import com.jme.system.DisplaySystem;
import com.jme.util.geom.BufferUtils;
import com.samskivert.util.HashIntMap;
import com.threerings.jme.Log;
/**
@@ -171,6 +177,9 @@ public class SkinMesh extends ModelMesh
// store the current buffers as the originals
storeOriginalBuffers();
// initialize the quantized frame table
_frames = new HashIntMap<TriangleBatch>();
}
@Override // documentation inherited
@@ -198,6 +207,7 @@ public class SkinMesh extends ModelMesh
properties.addProperty("vertices");
properties.addProperty("normals");
properties.addProperty("displaylistid");
mstore._frames = _frames;
mstore._bones = new Bone[_bones.length];
HashMap<Bone, Bone> bmap = new HashMap<Bone, Bone>();
for (int ii = 0; ii < _bones.length; ii++) {
@@ -263,6 +273,14 @@ public class SkinMesh extends ModelMesh
vboinfo.setVBOIndexEnabled(true);
setVBOInfo(vboinfo);
}
_useDisplayLists = useDisplayLists;
}
@Override // documentation inherited
public void setAnimationFrame (int frameId)
{
// switch to the specified frame id on next update
_updateFrameId = frameId;
}
@Override // documentation inherited
@@ -287,6 +305,51 @@ public class SkinMesh extends ModelMesh
if (_weightGroups == null) {
return;
}
// determine if we are using/updating a quantized frame
TriangleBatch lockBatch = null;
if (_updateFrameId > 0) {
if (_currentFrameId == _updateFrameId) {
return;
}
TriangleBatch batch = getBatch(0),
tbatch = _frames.get(_updateFrameId);
boolean reskin = false;
if (tbatch == null) {
_frames.put(_updateFrameId, tbatch = new TriangleBatch());
tbatch.setParentGeom(DUMMY_MESH);
tbatch.setColorBuffer(batch.getColorBuffer());
tbatch.setTextureBuffer(batch.getTextureBuffer(0), 0);
tbatch.setIndexBuffer(batch.getIndexBuffer());
tbatch.setVertexBuffer(
BufferUtils.createFloatBuffer(_ovbuf.length));
tbatch.setNormalBuffer(
BufferUtils.createFloatBuffer(_onbuf.length));
VBOInfo ovboinfo = batch.getVBOInfo();
if (ovboinfo != null) {
VBOInfo vboinfo = new VBOInfo(true);
vboinfo.setVBOIndexEnabled(true);
vboinfo.setVBOColorID(ovboinfo.getVBOColorID());
vboinfo.setVBOTextureID(0, ovboinfo.getVBOTextureID(0));
vboinfo.setVBOIndexID(ovboinfo.getVBOIndexID());
tbatch.setVBOInfo(vboinfo);
} else if (_useDisplayLists) {
lockBatch = tbatch;
}
reskin = true;
}
if (batch instanceof SharedBatch) {
((SharedBatch)batch).setTarget(tbatch);
} else {
clearBatches();
addBatch(new SharedBatch(tbatch));
getBatch(0).updateRenderState();
}
_currentFrameId = _updateFrameId;
if (!reskin) {
return;
}
}
// update the bone transforms
_modelTransform.invert(_transform);
for (Bone bone : _bones) {
@@ -341,6 +404,12 @@ public class SkinMesh extends ModelMesh
vbuf.put(_vbuf);
nbuf.rewind();
nbuf.put(_nbuf);
// compile the target batch to a display list if requested
if (lockBatch != null) {
lockBatch.lockMeshes(
DisplaySystem.getDisplaySystem().getRenderer());
}
}
/**
@@ -357,6 +426,10 @@ public class SkinMesh extends ModelMesh
_nbuf = new float[_onbuf.length];
}
/** Pre-skinned meshes shared between all instances corresponding to
* frame ids from {@link #setAnimationFrame}. */
protected HashIntMap<TriangleBatch> _frames;
/** The groups of vertices influenced by different sets of bones. */
protected WeightGroup[] _weightGroups;
@@ -367,11 +440,21 @@ public class SkinMesh extends ModelMesh
* versions. */
protected float[] _ovbuf, _onbuf, _vbuf, _nbuf;
/** The desired and current frame id, or -1 for continuous animation. */
protected int _updateFrameId = -1, _currentFrameId;
/** Whether or to use display lists if VBOs are unavailable for quantized
* meshes. */
protected boolean _useDisplayLists;
/** The node's transform in model space. */
protected Matrix4f _modelTransform = new Matrix4f();
/** Working transform. */
protected Matrix4f _transform = new Matrix4f();
/** A dummy mesh that simply hold transformation values. */
protected static final TriMesh DUMMY_MESH = new TriMesh();
private static final long serialVersionUID = 1;
}