spatialtransformer.java
来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 900 行 · 第 1/3 页
JAVA
900 行
/*
* 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.jme.animation;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.logging.Logger;
import com.jme.math.Quaternion;
import com.jme.math.TransformQuaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Spatial;
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;
/**
* Started Date: Jul 9, 2004 <br>
* <br>
*
* This class animates spatials by interpolating between various
* transformations. The user defines objects to be transformed and what
* rotation/translation/scale to give each object at various points in time. The
* user must call interpolateMissing() before using the controller in order to
* interpolate unspecified translation/rotation/scale.
*
*
* @author Jack Lindamood
* @author Philip Wainwright (bugfixes)
*/
public class SpatialTransformer extends Controller {
private static final Logger logger = Logger.getLogger(SpatialTransformer.class.getName());
private static final long serialVersionUID = 1L;
/** Number of objects this transformer changes. */
private int numObjects;
/** Refrences to the objects that will be changed. */
public Spatial[] toChange;
/** Used internally by update specifying how to change each object. */
private TransformQuaternion[] pivots;
/**
* parentIndexes[i] states that toChange[i]'s parent is
* toChange[parentIndex[i]].
*/
public int[] parentIndexes;
/** Interpolated array of keyframe states */
public ArrayList<PointInTime> keyframes;
/** Current time in the animation */
private float curTime;
/** Time previous to curTime */
private transient PointInTime beginPointTime;
/** Time after curTime */
private transient PointInTime endPointTime;
/** Used internally in update to flag that a pivot has been updated */
private boolean[] haveChanged;
private float delta;
private final static Vector3f unSyncbeginPos = new Vector3f();
private final static Vector3f unSyncendPos = new Vector3f();
private final static Quaternion unSyncbeginRot = new Quaternion();
private final static Quaternion unSyncendRot = new Quaternion();
public SpatialTransformer() {}
/**
* Constructs a new SpatialTransformer that will operate on
* <code>numObjects</code> Spatials
*
* @param numObjects
* The number of spatials to change
*/
public SpatialTransformer(int numObjects) {
this.numObjects = numObjects;
toChange = new Spatial[numObjects];
pivots = new TransformQuaternion[numObjects];
parentIndexes = new int[numObjects];
haveChanged = new boolean[numObjects];
Arrays.fill(parentIndexes, -1);
for (int i = 0; i < numObjects; i++)
pivots[i] = new TransformQuaternion();
keyframes = new ArrayList<PointInTime>();
}
public void update(float time) {
curTime += time * getSpeed();
setBeginAndEnd();
Arrays.fill(haveChanged, false);
delta = endPointTime.time - beginPointTime.time;
if (delta != 0f) delta = (curTime - beginPointTime.time) / delta;
for (int i = 0; i < numObjects; i++) {
updatePivot(i);
pivots[i].applyToSpatial(toChange[i]);
}
}
/**
* Called by update, and itself recursivly. Will, when completed, change
* toChange[objIndex] by pivots[objIndex]
*
* @param objIndex
* The index to update.
*/
private void updatePivot(int objIndex) {
if (haveChanged[objIndex])
return;
haveChanged[objIndex] = true;
int parentIndex = parentIndexes[objIndex];
if (parentIndex != -1) {
updatePivot(parentIndex);
}
pivots[objIndex].interpolateTransforms(beginPointTime.look[objIndex],
endPointTime.look[objIndex], delta);
if (parentIndex != -1)
pivots[objIndex].combineWithParent(pivots[parentIndex]);
}
/**
* overridden by SpatialTransformer to always set a time inside the first
* and the last keyframe's time in the animation.
* @author Kai Rabien (hevee)
*/
public void setMinTime(float minTime) {
if(keyframes != null && keyframes.size() > 0){
float firstFrame = keyframes.get(0).time;
float lastFrame = keyframes.get(keyframes.size() - 1).time;
if(minTime < firstFrame) minTime = firstFrame;
if(minTime > lastFrame) minTime = lastFrame;
}
curTime = minTime;
super.setMinTime(minTime);
}
/**
* overridden by SpatialTransformer to always set a time inside the first
* and the last keyframe's time in the animation
* @author Kai Rabien (hevee)
*/
public void setMaxTime(float maxTime) {
if(keyframes != null && keyframes.size() > 0){
float firstFrame = keyframes.get(0).time;
float lastFrame = keyframes.get(keyframes.size() - 1).time;
if(maxTime < firstFrame) maxTime = firstFrame;
if(maxTime > lastFrame) maxTime = lastFrame;
}
super.setMaxTime(maxTime);
}
/**
* Sets the new animation boundaries for this controller. This will start at
* newBeginTime and proceed in the direction of newEndTime (either forwards
* or backwards). If both are the same, then the animation is set to their
* time and turned off, otherwise the animation is turned on to start the
* animation acording to the repeat type. If either BeginTime or EndTime are
* invalid times (less than 0 or greater than the maximum set keyframe time)
* then a warning is set and nothing happens. <br>
* It is suggested that this function be called if new animation boundaries
* need to be set, instead of setMinTime and setMaxTime directly.
*
* @param newBeginTime
* The starting time
* @param newEndTime
* The ending time
*/
public void setNewAnimationTimes(float newBeginTime, float newEndTime) {
if (newBeginTime < 0
|| newBeginTime > keyframes
.get(keyframes.size() - 1).time) {
logger.warning("Attempt to set invalid begintime:" + newBeginTime);
return;
}
if (newEndTime < 0
|| newEndTime > keyframes
.get(keyframes.size() - 1).time) {
logger.warning("Attempt to set invalid endtime:" + newEndTime);
return;
}
setMinTime(newBeginTime);
setMaxTime(newEndTime);
setActive(true);
if (newBeginTime <= newEndTime) { // Moving forward
curTime = newBeginTime;
if (newBeginTime == newEndTime) {
update(0);
setActive(false);
}
} else { // Moving backwards
curTime = newEndTime;
}
}
/**
* Gets the current time in the animation
*/
public float getCurTime(){return curTime;}
/**
* Sets the current time in the animation
* @param time
* The time this Controller should continue at
*/
public void setCurTime(float time){ curTime = time;}
/**
* Called in update for calculating the correct beginPointTime and
* endPointTime, and changing curTime if neccessary.
* @author Kai Rabien (hevee)
*/
private void setBeginAndEnd() {
float minTime = getMinTime();
float maxTime = getMaxTime();
if(getSpeed() > 0){
if(curTime >= maxTime){
if(getRepeatType() == RT_WRAP){
int[] is = findIndicesBeforeAfter(minTime);
int beginIndex = is[0];
int endIndex = is[1];
beginPointTime = keyframes.get(beginIndex);
endPointTime = keyframes.get(endIndex);
float overshoot = curTime - maxTime;
curTime = minTime + overshoot;
} else if (getRepeatType() == RT_CLAMP){
int[] is = findIndicesBeforeAfter(maxTime);
int beginIndex = is[1];
beginPointTime = keyframes.get(beginIndex);
endPointTime = beginPointTime;
curTime = maxTime;
} else if(getRepeatType() == RT_CYCLE){
int[] is = findIndicesBeforeAfter(maxTime);
int beginIndex = is[0];
int endIndex = is[1];
beginPointTime = keyframes.get(beginIndex);
endPointTime = keyframes.get(endIndex);
float overshoot = curTime - maxTime;
curTime = maxTime - overshoot;
setSpeed(- getSpeed());
}
} else if(curTime <= minTime){
int[] is = findIndicesBeforeAfter(minTime);
int beginIndex = is[0];
int endIndex = is[1];
beginPointTime = keyframes.get(beginIndex);
endPointTime = keyframes.get(endIndex);
curTime = minTime;
} else{//curTime is inside minTime and maxTime
int[] is = findIndicesBeforeAfter(curTime);
int beginIndex = is[0];
int endIndex = is[1];
beginPointTime = keyframes.get(beginIndex);
endPointTime = keyframes.get(endIndex);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?