📄 jointcontroller.java
字号:
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jmex.model.animation;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import com.jme.math.Quaternion;
import com.jme.math.TransformMatrix;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.system.JmeException;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;
import com.jme.util.export.Savable;
import com.jme.util.geom.BufferUtils;
import com.jmex.model.JointMesh;
/**
* Started Date: Jun 9, 2004 <br>
*
* This controller animates a Node's JointMesh children acording to the joints
* stored inside <code>movementInfo</code>.
*
* @author Jack Lindamood
*/
public class JointController extends Controller {
private static final long serialVersionUID = 1L;
/**
* It is JointController's responsibility to keep changePoints sorted by
* <code>time</code> at all times.
*/
public int numJoints;
/**
* movementInfo[i] contains a float value time and an array of
* TransformMatrix. At time <code>time</code> the joint i is at movement
* <code>jointChange[i]</code>
*/
public ArrayList<PointInTime> movementInfo;
/**
* parentIndex contains a list of who's parent a joint is. -1 indicates a
* root joint with no parent
*/
public int[] parentIndex;
/**
* Local refrence matrix that can determine a joint's position in space
* relative to its parent.
*/
public TransformMatrix[] localRefMatrix;
/** Currently unused. */
public float FPS;
/**
* Array of all the meshes this controller should consider animating.
*/
public ArrayList<JointMesh> movingMeshes;
/**
* This controller's internal current time.
*/
private float curTime;
/**
* This controller's internal current PointInTime index.
*/
private int curTimePoint;
/**
* Used internally, they are updated every update(float) call to tell points
* how to change.
*/
private TransformMatrix[] jointMovements;
/**
* The inverse chain matrix of every joint. Calculated once with
* prosessController()
*/
private TransformMatrix[] inverseChainMatrix;
// Internal worker classes
private final static Quaternion unSyncbeginAngle = new Quaternion();
private final static Vector3f unSyncbeginPos = new Vector3f();
private final static TransformMatrix tempUnSyncd = new TransformMatrix();
/**
* Tells update that it should be called every <code>skipRate</code>
* seconds
*/
public float skipRate;
/**
* Used with skipRate internally.
*/
private float currentSkip;
/** If true, the model's bounding volume will update every frame. */
private boolean updatePerFrame = true;
private boolean movingForward = true;
public JointController() {
curTime = 0;
curTimePoint = 1;
}
/**
* Constructs a new JointController that will hold the given number of
* joints.
*
* @param numJoints
* The number of joints this jointController will have
*/
public JointController(int numJoints) {
this.numJoints = numJoints;
parentIndex = new int[numJoints];
localRefMatrix = new TransformMatrix[numJoints];
movingMeshes = new ArrayList<JointMesh>();
jointMovements = new TransformMatrix[numJoints];
inverseChainMatrix = new TransformMatrix[numJoints];
for (int i = 0; i < numJoints; i++) {
localRefMatrix[i] = new TransformMatrix();
jointMovements[i] = new TransformMatrix();
inverseChainMatrix[i] = new TransformMatrix();
}
movementInfo = new ArrayList<PointInTime>();
curTime = 0;
curTimePoint = 1;
currentSkip = 0;
skipRate = .01f;
}
public float getCurrentTime() {
return curTime;
}
/**
* Tells JointController that at time <code>time</code> the joint
* <code>jointNumber</code> will translate to x,y,z relative to its parent
*
* @param jointNumber
* Index of joint to affect
* @param time
* Which time the joint will take these values
* @param x
* Joint's x translation
* @param y
* Joint's y translation
* @param z
* Joint's z translation
*/
public void setTranslation(int jointNumber, float time, float x, float y,
float z) {
findUpToTime(time).setTranslation(jointNumber, x, y, z);
}
/**
* Tells JointController that at time <code>time</code> the joint
* <code>jointNumber</code> will translate to x,y,z relative to its parent
*
* @param jointNumber
* Index of joint to affect
* @param time
* Which time the joint will take these values
* @param trans
* Joint's translation
*
*/
public void setTranslation(int jointNumber, float time, Vector3f trans) {
findUpToTime(time).setTranslation(jointNumber, trans);
}
/**
* Tells JointController that at time <code>time</code> the joint
* <code>jointNumber</code> will rotate acording to the euler angles x,y,z
* relative to its parent's rotation
*
* @param jointNumber
* Index of joint to affect
* @param time
* Which time the joint will take these values
* @param x
* Joint's x rotation
* @param y
* Joint's y rotation
* @param z
* Joint's z rotation
*/
public void setRotation(int jointNumber, float time, float x, float y,
float z) {
findUpToTime(time).setRotation(jointNumber, x, y, z);
}
/**
* Tells JointController that at time <code>time</code> the joint
* <code>jointNumber</code> will rotate acording to
* <code>Quaternion</code>.
*
* @param jointNumber
* Index of joint to affect
* @param time
* Which time the joint will take these values
* @param quaternion
* The joint's new rotation
*/
public void setRotation(int jointNumber, float time, Quaternion quaternion) {
findUpToTime(time).setRotation(jointNumber, quaternion);
}
/**
* Used with setRotation and setTranslation. This function finds a point in
* time for given time. If one doesn't exist then a new PointInTime is
* created and returned.
*
* @param time
* @return The PointInTime at that given time, or a new one if none exist so
* far.
*/
private PointInTime findUpToTime(float time) {
int index = 0;
for (PointInTime point : movementInfo) {
float curTime = point.time;
if (curTime >= time) break;
index++;
}
PointInTime storedNext = null;
if (index == movementInfo.size()) {
storedNext = new PointInTime(numJoints);
movementInfo.add(storedNext);
storedNext.time = time;
} else {
if (movementInfo.get(index).time == time) {
storedNext = movementInfo.get(index);
} else {
storedNext = new PointInTime(numJoints);
movementInfo.add(index, storedNext);
storedNext.time = time;
}
}
return storedNext;
}
/**
* Updates the <code>movingMeshes</code> by updating their joints +=time
*
* @param time
* Time from last update
*/
public void update(float time) {
if (numJoints == 0) return;
if (movingForward)
curTime += time * this.getSpeed();
else
curTime -= time * this.getSpeed();
currentSkip += time;
if (currentSkip >= skipRate) {
currentSkip = 0;
} else {
return;
}
setCurTimePoint();
PointInTime now = movementInfo.get(curTimePoint);
PointInTime then = movementInfo.get(curTimePoint - 1);
float delta = (curTime - then.time) / (now.time - then.time);
createJointTransforms(delta);
combineWithInverse();
updateData();
}
private void setCurTimePoint() {
int repeatType = getRepeatType();
// reset if too far
if (curTime > getMaxTime()) {
if (repeatType == Controller.RT_WRAP)
curTime = getMinTime();
else if (repeatType == Controller.RT_CYCLE) {
curTime = getMaxTime();
movingForward = false;
} else if (repeatType == Controller.RT_CLAMP) {
setActive(false);
curTime = getMaxTime();
}
}
if (curTime < getMinTime()) {
if (repeatType == Controller.RT_WRAP)
curTime = getMaxTime();
else if (repeatType == Controller.RT_CYCLE) {
curTime = getMinTime();
movingForward = true;
} else if (repeatType == Controller.RT_CLAMP) {
setActive(false);
curTime = getMinTime();
}
}
// if curTimePoint works then return
PointInTime p1 = movementInfo.get(curTimePoint);
PointInTime p2 = movementInfo.get(curTimePoint - 1);
if (curTime <= p1.time && curTime >= p2.time) return;
for (curTimePoint = 1; curTimePoint < movementInfo.size(); curTimePoint++) {
p1 = movementInfo.get(curTimePoint);
if (p1.time >= curTime) return;
}
}
/**
* Sets the frames the joint controller will animate from and to. The frames
* are dependant upon the FPS. Remember that the first frame starts at 1,
* <b>NOT </b>0.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -