Skinned animation now works, although there are still some optimizations
to be made. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4027 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,98 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.jme.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
import com.jme.scene.Node;
|
||||
|
||||
import com.jme.math.Quaternion;
|
||||
import com.jme.math.TransformMatrix;
|
||||
import com.jme.math.Vector3f;
|
||||
|
||||
import com.threerings.jme.Log;
|
||||
|
||||
/**
|
||||
* Represents a bone in a scene. Bones can have simple meshes as children,
|
||||
* or they can be used to deform {@link SkinMesh}es.
|
||||
*/
|
||||
public class BoneNode extends ModelNode
|
||||
{
|
||||
/**
|
||||
* No-arg constructor for deserialization.
|
||||
*/
|
||||
public BoneNode ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @param name the name of the node
|
||||
*/
|
||||
public BoneNode (String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void setReferenceTransforms ()
|
||||
{
|
||||
super.setReferenceTransforms();
|
||||
|
||||
// store the inverse of the reference transform
|
||||
_invRefTransform.set(worldRotation, worldTranslation);
|
||||
_invRefTransform.setScale(worldScale);
|
||||
_invRefTransform.inverse();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void updateWorldVectors ()
|
||||
{
|
||||
super.updateWorldVectors();
|
||||
_skinTransform.set(worldRotation, worldTranslation);
|
||||
_skinTransform.setScale(worldScale);
|
||||
_skinTransform.multLocal(_invRefTransform, _tempStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the matrix that transforms vertices in the
|
||||
* reference position to vertices in the current position.
|
||||
*/
|
||||
public TransformMatrix getSkinTransform ()
|
||||
{
|
||||
return _skinTransform;
|
||||
}
|
||||
|
||||
/** The inverse of the bone's world space reference transform. */
|
||||
protected TransformMatrix _invRefTransform = new TransformMatrix();
|
||||
|
||||
/** The bone's current skin transform. */
|
||||
protected TransformMatrix _skinTransform = new TransformMatrix();
|
||||
|
||||
/** A temporary vector for transformations. */
|
||||
protected Vector3f _tempStore = new Vector3f();
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
@@ -39,8 +39,11 @@ import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.samskivert.util.ObserverList;
|
||||
|
||||
import com.jme.math.Quaternion;
|
||||
import com.jme.math.Vector3f;
|
||||
import com.jme.scene.Controller;
|
||||
import com.jme.scene.Spatial;
|
||||
|
||||
import com.threerings.jme.Log;
|
||||
@@ -50,10 +53,36 @@ import com.threerings.jme.Log;
|
||||
*/
|
||||
public class Model extends ModelNode
|
||||
{
|
||||
/** Lets listeners know when animations are completed (which only happens
|
||||
* for non-repeating animations) or cancelled. */
|
||||
public interface AnimationObserver
|
||||
{
|
||||
/**
|
||||
* Called when a non-repeating animation has finished.
|
||||
*
|
||||
* @return true to remain on the observer list, false to remove self
|
||||
*/
|
||||
public boolean animationCompleted (Model model, String anim);
|
||||
|
||||
/**
|
||||
* Called when an animation has been cancelled.
|
||||
*
|
||||
* @return true to remain on the observer list, false to remove self
|
||||
*/
|
||||
public boolean animationCancelled (Model model, String anim);
|
||||
}
|
||||
|
||||
/** An animation for the model. */
|
||||
public static class Animation
|
||||
implements Serializable
|
||||
{
|
||||
/** The rate of the animation in frames per second. */
|
||||
public int frameRate;
|
||||
|
||||
/** The animation repeat type ({@link Controller#RT_CLAMP},
|
||||
* {@link Controller#RT_CYCLE}, or {@link Controller#RT_WRAP}). */
|
||||
public int repeatType;
|
||||
|
||||
/** The transformation targets of the animation. */
|
||||
public Spatial[] transformTargets;
|
||||
|
||||
@@ -173,6 +202,10 @@ public class Model extends ModelNode
|
||||
model.readBuffers(fc);
|
||||
}
|
||||
ois.close();
|
||||
|
||||
// set the reference transforms before any animations are applied
|
||||
model.setReferenceTransforms();
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -225,13 +258,20 @@ public class Model extends ModelNode
|
||||
*/
|
||||
public void startAnimation (String name)
|
||||
{
|
||||
if (_anim != null) {
|
||||
stopAnimation();
|
||||
}
|
||||
_anim = _anims.get(name);
|
||||
if (_anim == null) {
|
||||
Log.warning("Requested unknown animation [name=" +
|
||||
name + "].");
|
||||
return;
|
||||
}
|
||||
_fidx = -1;
|
||||
_animName = name;
|
||||
_fidx = 0;
|
||||
_nidx = 1;
|
||||
_fdir = +1;
|
||||
_elapsed = 0f;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +279,44 @@ public class Model extends ModelNode
|
||||
*/
|
||||
public void stopAnimation ()
|
||||
{
|
||||
if (_anim == null) {
|
||||
return;
|
||||
}
|
||||
_anim = null;
|
||||
_animObservers.apply(new AnimCancelledOp(_animName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the animation speed, which acts as a multiplier for the frame rate
|
||||
* of each animation.
|
||||
*/
|
||||
public void setAnimationSpeed (float speed)
|
||||
{
|
||||
_animSpeed = speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently configured animation speed.
|
||||
*/
|
||||
public float getAnimationSpeed ()
|
||||
{
|
||||
return _animSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an animation observer.
|
||||
*/
|
||||
public void addAnimationObserver (AnimationObserver obs)
|
||||
{
|
||||
_animObservers.add(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an animation observer.
|
||||
*/
|
||||
public void removeAnimationObserver (AnimationObserver obs)
|
||||
{
|
||||
_animObservers.remove(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,7 +370,49 @@ public class Model extends ModelNode
|
||||
*/
|
||||
protected void updateAnimation (float time)
|
||||
{
|
||||
// advance the frame counter if necessary
|
||||
while (_elapsed > 1f) {
|
||||
advanceFrameCounter();
|
||||
_elapsed -= 1f;
|
||||
}
|
||||
|
||||
// update the target transforms
|
||||
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]);
|
||||
}
|
||||
|
||||
// if the next index is the same as this one, we are finished
|
||||
if (_fidx == _nidx) {
|
||||
_anim = null;
|
||||
_animObservers.apply(new AnimCompletedOp(_animName));
|
||||
return;
|
||||
}
|
||||
|
||||
_elapsed += (time * _anim.frameRate * _animSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the frame counter by one frame.
|
||||
*/
|
||||
protected void advanceFrameCounter ()
|
||||
{
|
||||
_fidx = _nidx;
|
||||
int nframes = _anim.transforms.length;
|
||||
if (_anim.repeatType == Controller.RT_CLAMP) {
|
||||
_nidx = Math.min(_nidx + 1, nframes - 1);
|
||||
|
||||
} else if (_anim.repeatType == Controller.RT_CYCLE) {
|
||||
_nidx = (_nidx + 1) % nframes;
|
||||
|
||||
} else { // _anim.repeatType == Controller.RT_WRAP
|
||||
if ((_nidx + _fdir) < 0 || (_nidx + _fdir) >= nframes) {
|
||||
_fdir *= -1; // reverse direction
|
||||
}
|
||||
_nidx += _fdir;
|
||||
}
|
||||
}
|
||||
|
||||
/** The model properties. */
|
||||
@@ -305,14 +424,60 @@ public class Model extends ModelNode
|
||||
/** The currently running animation, or <code>null</code> for none. */
|
||||
protected Animation _anim;
|
||||
|
||||
/** The last frame index. */
|
||||
protected int _fidx;
|
||||
/** The name of the currently running animation, if any. */
|
||||
protected String _animName;
|
||||
|
||||
/** The time corresponding to the last frame. */
|
||||
protected float _ftime;
|
||||
/** The current animation speed multiplier. */
|
||||
protected float _animSpeed = 1f;
|
||||
|
||||
/** Identifies a transform frame element. */
|
||||
protected static final byte TRANSFORM_ELEMENT = 0;
|
||||
/** The index of the current and next frames. */
|
||||
protected int _fidx, _nidx;
|
||||
|
||||
/** The direction for wrapping animations (+1 forward, -1 backward). */
|
||||
protected int _fdir;
|
||||
|
||||
/** The frame portion elapsed since the start of the current frame. */
|
||||
protected float _elapsed;
|
||||
|
||||
/** Animation completion listeners. */
|
||||
protected ObserverList<AnimationObserver> _animObservers =
|
||||
new ObserverList<AnimationObserver>(ObserverList.FAST_UNSAFE_NOTIFY);
|
||||
|
||||
/** Used to notify observers of animation completion. */
|
||||
protected class AnimCompletedOp
|
||||
implements ObserverList.ObserverOp<AnimationObserver>
|
||||
{
|
||||
public AnimCompletedOp (String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public boolean apply (AnimationObserver obs)
|
||||
{
|
||||
return obs.animationCompleted(Model.this, _name);
|
||||
}
|
||||
|
||||
/** The name of the animation completed. */
|
||||
protected String _name;
|
||||
}
|
||||
|
||||
/** Used to notify observers of animation cancellation. */
|
||||
protected class AnimCancelledOp
|
||||
implements ObserverList.ObserverOp<AnimationObserver>
|
||||
{
|
||||
public AnimCancelledOp (String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public boolean apply (AnimationObserver obs)
|
||||
{
|
||||
return obs.animationCancelled(Model.this, _name);
|
||||
}
|
||||
|
||||
/** The name of the animation cancelled. */
|
||||
protected String _name;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
|
||||
@@ -71,16 +71,6 @@ public class ModelMesh extends TriMesh
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and populates a mesh.
|
||||
*/
|
||||
public ModelMesh (
|
||||
String name, FloatBuffer vertices, FloatBuffer normals,
|
||||
FloatBuffer colors, FloatBuffer tcoords, IntBuffer indices)
|
||||
{
|
||||
super(name, vertices, normals, colors, tcoords, indices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this mesh based on the given (sub-)properties.
|
||||
*/
|
||||
@@ -138,7 +128,7 @@ public class ModelMesh extends TriMesh
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
@Override // documentation inherited
|
||||
public void reconstruct (
|
||||
FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors,
|
||||
FloatBuffer textures, IntBuffer indices)
|
||||
@@ -152,7 +142,7 @@ public class ModelMesh extends TriMesh
|
||||
_indexBufferSize = (indices == null) ? 0 : indices.capacity();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
@Override // documentation inherited
|
||||
public void reconstruct (
|
||||
FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors,
|
||||
FloatBuffer textures)
|
||||
@@ -203,6 +193,12 @@ public class ModelMesh extends TriMesh
|
||||
_transparent = in.readBoolean();
|
||||
}
|
||||
|
||||
// documentation inherited from interface ModelSpatial
|
||||
public void setReferenceTransforms ()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
// documentation inherited from interface ModelSpatial
|
||||
public void resolveTextures (TextureProvider tprov)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.nio.channels.FileChannel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.jme.math.Matrix4f;
|
||||
import com.jme.math.Quaternion;
|
||||
import com.jme.math.Vector3f;
|
||||
import com.jme.scene.Node;
|
||||
@@ -62,18 +63,39 @@ public class ModelNode extends Node
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively sets the reference transforms for any {@link BoneNode}s in
|
||||
* the model.
|
||||
* Returns a reference to the model space transform of the node.
|
||||
*/
|
||||
public Matrix4f getModelTransform ()
|
||||
{
|
||||
return _modelTransform;
|
||||
}
|
||||
|
||||
// documentation inherited from interface ModelSpatial
|
||||
public void setReferenceTransforms ()
|
||||
{
|
||||
updateWorldVectors();
|
||||
for (Object child : getChildren()) {
|
||||
if (child instanceof ModelNode) {
|
||||
((ModelNode)child).setReferenceTransforms();
|
||||
if (child instanceof ModelSpatial) {
|
||||
((ModelSpatial)child).setReferenceTransforms();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void updateWorldVectors ()
|
||||
{
|
||||
super.updateWorldVectors();
|
||||
if (parent instanceof ModelNode) {
|
||||
setTransform(getLocalTranslation(), getLocalRotation(),
|
||||
getLocalScale(), _localTransform);
|
||||
((ModelNode)parent).getModelTransform().mult(_localTransform,
|
||||
_modelTransform);
|
||||
|
||||
} else {
|
||||
_modelTransform.loadIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface Externalizable
|
||||
public void writeExternal (ObjectOutput out)
|
||||
throws IOException
|
||||
@@ -141,5 +163,35 @@ public class ModelNode extends Node
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a matrix to the transform defined by the given translation,
|
||||
* rotation, and scale values.
|
||||
*/
|
||||
protected static Matrix4f setTransform (
|
||||
Vector3f translation, Quaternion rotation, Vector3f scale,
|
||||
Matrix4f result)
|
||||
{
|
||||
result.set(rotation);
|
||||
result.setTranslation(translation);
|
||||
|
||||
result.m00 *= scale.x;
|
||||
result.m01 *= scale.y;
|
||||
result.m02 *= scale.z;
|
||||
|
||||
result.m10 *= scale.x;
|
||||
result.m11 *= scale.y;
|
||||
result.m12 *= scale.z;
|
||||
|
||||
result.m20 *= scale.x;
|
||||
result.m21 *= scale.y;
|
||||
result.m22 *= scale.z;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** The node's transform in local and model space. */
|
||||
protected Matrix4f _localTransform = new Matrix4f(),
|
||||
_modelTransform = new Matrix4f();
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
|
||||
@@ -27,11 +27,18 @@ import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
import com.jme.math.Matrix4f;
|
||||
|
||||
/**
|
||||
* Contains method common to both {@link ModelNode}s and {@link ModelMesh}es.
|
||||
*/
|
||||
public interface ModelSpatial
|
||||
{
|
||||
/**
|
||||
* Recursively sets the reference transforms for any bones in the model.
|
||||
*/
|
||||
public void setReferenceTransforms ();
|
||||
|
||||
/**
|
||||
* Recursively resolves texture references using the given provider.
|
||||
*/
|
||||
|
||||
@@ -26,9 +26,14 @@ import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import com.jme.math.Matrix4f;
|
||||
import com.jme.math.Vector3f;
|
||||
import com.jme.util.geom.BufferUtils;
|
||||
|
||||
import com.threerings.jme.Log;
|
||||
|
||||
/**
|
||||
@@ -45,13 +50,16 @@ public class SkinMesh extends ModelMesh
|
||||
public int[] indices;
|
||||
|
||||
/** The bones influencing this group. */
|
||||
public BoneNode[] bones;
|
||||
public ModelNode[] bones;
|
||||
|
||||
/** The array of interleaved weights (of length <code>indices.length *
|
||||
* bones.length</code>): weights for first vertex, weights for second,
|
||||
* etc. */
|
||||
public float[] weights;
|
||||
|
||||
/** The inverses of the bones' mesh space reference transforms. */
|
||||
public transient Matrix4f[] invRefTransforms;
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
|
||||
@@ -70,16 +78,6 @@ public class SkinMesh extends ModelMesh
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and populates a mesh.
|
||||
*/
|
||||
public SkinMesh (
|
||||
String name, FloatBuffer vertices, FloatBuffer normals,
|
||||
FloatBuffer color, FloatBuffer texture, IntBuffer indices)
|
||||
{
|
||||
super(name, vertices, normals, color, texture, indices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the weight groups that determine how vertices are affected by
|
||||
* bones.
|
||||
@@ -97,6 +95,18 @@ public class SkinMesh extends ModelMesh
|
||||
return _weightGroups;
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void reconstruct (
|
||||
ByteBuffer vertices, ByteBuffer normals, ByteBuffer colors,
|
||||
ByteBuffer textures, ByteBuffer indices)
|
||||
{
|
||||
super.reconstruct(vertices, normals, colors, textures, indices);
|
||||
|
||||
// replace the vertex and normal buffers with working buffers
|
||||
setVertexBuffer(BufferUtils.clone(_ovbuf = getVertexBuffer()));
|
||||
setNormalBuffer(BufferUtils.clone(_onbuf = getNormalBuffer()));
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void writeExternal (ObjectOutput out)
|
||||
throws IOException
|
||||
@@ -113,6 +123,36 @@ public class SkinMesh extends ModelMesh
|
||||
_weightGroups = (WeightGroup[])in.readObject();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void setReferenceTransforms ()
|
||||
{
|
||||
updateWorldVectors();
|
||||
_modelTransform.invert(_transform);
|
||||
for (int ii = 0; ii < _weightGroups.length; ii++) {
|
||||
WeightGroup group = _weightGroups[ii];
|
||||
group.invRefTransforms = new Matrix4f[group.bones.length];
|
||||
for (int jj = 0; jj < group.bones.length; jj++) {
|
||||
group.invRefTransforms[jj] = _transform.mult(
|
||||
group.bones[jj].getModelTransform()).invertLocal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void updateWorldVectors ()
|
||||
{
|
||||
super.updateWorldVectors();
|
||||
if (parent instanceof ModelNode) {
|
||||
ModelNode.setTransform(getLocalTranslation(), getLocalRotation(),
|
||||
getLocalScale(), _transform);
|
||||
((ModelNode)parent).getModelTransform().mult(_transform,
|
||||
_modelTransform);
|
||||
|
||||
} else {
|
||||
_modelTransform.loadIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
public void updateWorldData (float time)
|
||||
{
|
||||
@@ -120,15 +160,72 @@ public class SkinMesh extends ModelMesh
|
||||
if (_weightGroups == null) {
|
||||
return;
|
||||
}
|
||||
_modelTransform.invert(_transform);
|
||||
|
||||
// deform the mesh according to the positions of the bones
|
||||
ModelNode[] bones;
|
||||
int idx;
|
||||
int[] indices;
|
||||
float[] weights;
|
||||
Matrix4f xform;
|
||||
Matrix4f[] invRefXforms;
|
||||
float weight;
|
||||
FloatBuffer vbuf = getVertexBuffer(), nbuf = getNormalBuffer();
|
||||
for (int ii = 0; ii < _weightGroups.length; ii++) {
|
||||
|
||||
bones = _weightGroups[ii].bones;
|
||||
invRefXforms = _weightGroups[ii].invRefTransforms;
|
||||
if (_transforms == null || _transforms.length < bones.length) {
|
||||
_transforms = new Matrix4f[bones.length];
|
||||
}
|
||||
for (int jj = 0; jj < bones.length; jj++) {
|
||||
if (_transforms[jj] == null) {
|
||||
_transforms[jj] = new Matrix4f();
|
||||
}
|
||||
_transform.mult(bones[jj].getModelTransform(),
|
||||
_transforms[jj]);
|
||||
_transforms[jj].multLocal(invRefXforms[jj]);
|
||||
}
|
||||
indices = _weightGroups[ii].indices;
|
||||
weights = _weightGroups[ii].weights;
|
||||
for (int jj = 0, ww = 0; jj < indices.length; jj++) {
|
||||
idx = indices[jj];
|
||||
BufferUtils.populateFromBuffer(_overtex, _ovbuf, idx);
|
||||
BufferUtils.populateFromBuffer(_onormal, _onbuf, idx);
|
||||
_vertex.zero();
|
||||
_normal.zero();
|
||||
for (int kk = 0; kk < bones.length; kk++) {
|
||||
xform = _transforms[kk];
|
||||
weight = weights[ww++];
|
||||
_vertex.addLocal(
|
||||
xform.mult(_overtex, _tmp).mult(weight));
|
||||
_normal.addLocal(
|
||||
xform.multAcross(_onormal, _tmp).mult(weight));
|
||||
}
|
||||
BufferUtils.setInBuffer(_vertex, vbuf, idx);
|
||||
BufferUtils.setInBuffer(_normal, nbuf, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The groups of vertices influenced by different sets of bones. */
|
||||
protected WeightGroup[] _weightGroups;
|
||||
|
||||
/** The original (undeformed) vertex and normal buffers. */
|
||||
protected FloatBuffer _ovbuf, _onbuf;
|
||||
|
||||
/** The node's transform in model space. */
|
||||
protected Matrix4f _modelTransform = new Matrix4f();
|
||||
|
||||
/** A working array for transforms. */
|
||||
protected Matrix4f[] _transforms;
|
||||
|
||||
/** Working vectors. */
|
||||
protected Vector3f _overtex = new Vector3f(), _vertex = new Vector3f(),
|
||||
_onormal = new Vector3f(), _normal = new Vector3f(),
|
||||
_tmp = new Vector3f();
|
||||
|
||||
/** Working transform. */
|
||||
protected Matrix4f _transform = new Matrix4f();
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user