📄 quaternion.java
字号:
float ys = y * s;
float zs = z * s;
float xx = x * xs;
float xy = x * ys;
float xz = x * zs;
float xw = w * xs;
float yy = y * ys;
float yz = y * zs;
float yw = w * ys;
float zz = z * zs;
float zw = w * zs;
// using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
result.m00 = 1 - ( yy + zz );
result.m01 = ( xy - zw );
result.m02 = ( xz + yw );
result.m10 = ( xy + zw );
result.m11 = 1 - ( xx + zz );
result.m12 = ( yz - xw );
result.m20 = ( xz - yw );
result.m21 = ( yz + xw );
result.m22 = 1 - ( xx + yy );
return result;
}
/**
* <code>getRotationColumn</code> returns one of three columns specified
* by the parameter. This column is returned as a <code>Vector3f</code>
* object.
*
* @param i
* the column to retrieve. Must be between 0 and 2.
* @return the column specified by the index.
*/
public Vector3f getRotationColumn(int i) {
return getRotationColumn(i, null);
}
/**
* <code>getRotationColumn</code> returns one of three columns specified
* by the parameter. This column is returned as a <code>Vector3f</code>
* object. The value is retrieved as if this quaternion was first normalized.
*
* @param i
* the column to retrieve. Must be between 0 and 2.
* @param store
* the vector object to store the result in. if null, a new one
* is created.
* @return the column specified by the index.
*/
public Vector3f getRotationColumn(int i, Vector3f store) {
if (store == null)
store = new Vector3f();
float norm = norm();
if (norm != 1.0f) {
norm = FastMath.invSqrt(norm);
}
float xx = x * x * norm;
float xy = x * y * norm;
float xz = x * z * norm;
float xw = x * w * norm;
float yy = y * y * norm;
float yz = y * z * norm;
float yw = y * w * norm;
float zz = z * z * norm;
float zw = z * w * norm;
switch (i) {
case 0:
store.x = 1 - 2 * ( yy + zz );
store.y = 2 * ( xy + zw );
store.z = 2 * ( xz - yw );
break;
case 1:
store.x = 2 * ( xy - zw );
store.y = 1 - 2 * ( xx + zz );
store.z = 2 * ( yz + xw );
break;
case 2:
store.x = 2 * ( xz + yw );
store.y = 2 * ( yz - xw );
store.z = 1 - 2 * ( xx + yy );
break;
default:
logger.warning("Invalid column index.");
throw new JmeException("Invalid column index. " + i);
}
return store;
}
/**
* <code>fromAngleAxis</code> sets this quaternion to the values specified
* by an angle and an axis of rotation. This method creates an object, so
* use fromAngleNormalAxis if your axis is already normalized.
*
* @param angle
* the angle to rotate (in radians).
* @param axis
* the axis of rotation.
* @return this quaternion
*/
public Quaternion fromAngleAxis(float angle, Vector3f axis) {
Vector3f normAxis = axis.normalize();
fromAngleNormalAxis(angle, normAxis);
return this;
}
/**
* <code>fromAngleNormalAxis</code> sets this quaternion to the values
* specified by an angle and a normalized axis of rotation.
*
* @param angle
* the angle to rotate (in radians).
* @param axis
* the axis of rotation (already normalized).
*/
public Quaternion fromAngleNormalAxis(float angle, Vector3f axis) {
if (axis.x == 0 && axis.y == 0 && axis.z == 0) {
loadIdentity();
} else {
float halfAngle = 0.5f * angle;
float sin = FastMath.sin(halfAngle);
w = FastMath.cos(halfAngle);
x = sin * axis.x;
y = sin * axis.y;
z = sin * axis.z;
}
return this;
}
/**
* <code>toAngleAxis</code> sets a given angle and axis to that
* represented by the current quaternion. The values are stored as
* following: The axis is provided as a parameter and built by the method,
* the angle is returned as a float.
*
* @param axisStore
* the object we'll store the computed axis in.
* @return the angle of rotation in radians.
*/
public float toAngleAxis(Vector3f axisStore) {
float sqrLength = x * x + y * y + z * z;
float angle;
if (sqrLength == 0.0f) {
angle = 0.0f;
if (axisStore != null) {
axisStore.x = 1.0f;
axisStore.y = 0.0f;
axisStore.z = 0.0f;
}
} else {
angle = (2.0f * FastMath.acos(w));
if (axisStore != null) {
float invLength = (1.0f / FastMath.sqrt(sqrLength));
axisStore.x = x * invLength;
axisStore.y = y * invLength;
axisStore.z = z * invLength;
}
}
return angle;
}
/**
* <code>slerp</code> sets this quaternion's value as an interpolation
* between two other quaternions.
*
* @param q1
* the first quaternion.
* @param q2
* the second quaternion.
* @param t
* the amount to interpolate between the two quaternions.
*/
public Quaternion slerp(Quaternion q1, Quaternion q2, float t) {
// Create a local quaternion to store the interpolated quaternion
if (q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w) {
this.set(q1);
return this;
}
float result = (q1.x * q2.x) + (q1.y * q2.y) + (q1.z * q2.z)
+ (q1.w * q2.w);
if (result < 0.0f) {
// Negate the second quaternion and the result of the dot product
q2.x = -q2.x;
q2.y = -q2.y;
q2.z = -q2.z;
q2.w = -q2.w;
result = -result;
}
// Set the first and second scale for the interpolation
float scale0 = 1 - t;
float scale1 = t;
// Check if the angle between the 2 quaternions was big enough to
// warrant such calculations
if ((1 - result) > 0.1f) {// Get the angle between the 2 quaternions,
// and then store the sin() of that angle
float theta = FastMath.acos(result);
float invSinTheta = 1f / FastMath.sin(theta);
// Calculate the scale for q1 and q2, according to the angle and
// it's sine value
scale0 = FastMath.sin((1 - t) * theta) * invSinTheta;
scale1 = FastMath.sin((t * theta)) * invSinTheta;
}
// Calculate the x, y, z and w values for the quaternion by using a
// special
// form of linear interpolation for quaternions.
this.x = (scale0 * q1.x) + (scale1 * q2.x);
this.y = (scale0 * q1.y) + (scale1 * q2.y);
this.z = (scale0 * q1.z) + (scale1 * q2.z);
this.w = (scale0 * q1.w) + (scale1 * q2.w);
// Return the interpolated quaternion
return this;
}
/**
* Sets the values of this quaternion to the slerp from itself to q2 by
* changeAmnt
*
* @param q2
* Final interpolation value
* @param changeAmnt
* The amount diffrence
*/
public void slerp(Quaternion q2, float changeAmnt) {
if (this.x == q2.x && this.y == q2.y && this.z == q2.z
&& this.w == q2.w) {
return;
}
float result = (this.x * q2.x) + (this.y * q2.y) + (this.z * q2.z)
+ (this.w * q2.w);
if (result < 0.0f) {
// Negate the second quaternion and the result of the dot product
q2.x = -q2.x;
q2.y = -q2.y;
q2.z = -q2.z;
q2.w = -q2.w;
result = -result;
}
// Set the first and second scale for the interpolation
float scale0 = 1 - changeAmnt;
float scale1 = changeAmnt;
// Check if the angle between the 2 quaternions was big enough to
// warrant such calculations
if ((1 - result) > 0.1f) {
// Get the angle between the 2 quaternions, and then store the sin()
// of that angle
float theta = FastMath.acos(result);
float invSinTheta = 1f / FastMath.sin(theta);
// Calculate the scale for q1 and q2, according to the angle and
// it's sine value
scale0 = FastMath.sin((1 - changeAmnt) * theta) * invSinTheta;
scale1 = FastMath.sin((changeAmnt * theta)) * invSinTheta;
}
// Calculate the x, y, z and w values for the quaternion by using a
// special
// form of linear interpolation for quaternions.
this.x = (scale0 * this.x) + (scale1 * q2.x);
this.y = (scale0 * this.y) + (scale1 * q2.y);
this.z = (scale0 * this.z) + (scale1 * q2.z);
this.w = (scale0 * this.w) + (scale1 * q2.w);
}
/**
* <code>add</code> adds the values of this quaternion to those of the
* parameter quaternion. The result is returned as a new quaternion.
*
* @param q
* the quaternion to add to this.
* @return the new quaternion.
*/
public Quaternion add(Quaternion q) {
return new Quaternion(x + q.x, y + q.y, z + q.z, w + q.w);
}
/**
* <code>add</code> adds the values of this quaternion to those of the
* parameter quaternion. The result is stored in this Quaternion.
*
* @param q
* the quaternion to add to this.
* @return This Quaternion after addition.
*/
public Quaternion addLocal(Quaternion q) {
this.x += q.x;
this.y += q.y;
this.z += q.z;
this.w += q.w;
return this;
}
/**
* <code>subtract</code> subtracts the values of the parameter quaternion
* from those of this quaternion. The result is returned as a new
* quaternion.
*
* @param q
* the quaternion to subtract from this.
* @return the new quaternion.
*/
public Quaternion subtract(Quaternion q) {
return new Quaternion(x - q.x, y - q.y, z - q.z, w - q.w);
}
/**
* <code>subtract</code> subtracts the values of the parameter quaternion
* from those of this quaternion. The result is stored in this Quaternion.
*
* @param q
* the quaternion to subtract from this.
* @return This Quaternion after subtraction.
*/
public Quaternion subtractLocal(Quaternion q) {
this.x -= q.x;
this.y -= q.y;
this.z -= q.z;
this.w -= q.w;
return this;
}
/**
* <code>mult</code> multiplies this quaternion by a parameter quaternion.
* The result is returned as a new quaternion. It should be noted that
* quaternion multiplication is not cummulative so q * p != p * q.
*
* @param q
* the quaternion to multiply this quaternion by.
* @return the new quaternion.
*/
public Quaternion mult(Quaternion q) {
return mult(q, null);
}
/**
* <code>mult</code> multiplies this quaternion by a parameter quaternion.
* The result is returned as a new quaternion. It should be noted that
* quaternion multiplication is not cummulative so q * p != p * q.
*
* It IS safe for q and res to be the same object.
*
* @param q
* the quaternion to multiply this quaternion by.
* @param res
* the quaternion to store the result in.
* @return the new quaternion.
*/
public Quaternion mult(Quaternion q, Quaternion res) {
if (res == null)
res = new Quaternion();
float qw = q.w, qx = q.x, qy = q.y, qz = q.z;
res.x = x * qw + y * qz - z * qy + w * qx;
res.y = -x * qz + y * qw + z * qx + w * qy;
res.z = x * qy - y * qx + z * qw + w * qz;
res.w = -x * qx - y * qy - z * qz + w * qw;
return res;
}
/**
* <code>apply</code> multiplies this quaternion by a parameter matrix
* internally.
*
* @param matrix
* the matrix to apply to this quaternion.
*/
public void apply(Matrix3f matrix) {
float oldX = x, oldY = y, oldZ = z, oldW = w;
fromRotationMatrix(matrix);
float tempX = x, tempY = y, tempZ = z, tempW = w;
x = oldX * tempW + oldY * tempZ - oldZ * tempY + oldW * tempX;
y = -oldX * tempZ + oldY * tempW + oldZ * tempX + oldW * tempY;
z = oldX * tempY - oldY * tempX + oldZ * tempW + oldW * tempZ;
w = -oldX * tempX - oldY * tempY - oldZ * tempZ + oldW * tempW;
}
/**
*
* <code>fromAxes</code> creates a <code>Quaternion</code> that
* represents the coordinate system defined by three axes. These axes are
* assumed to be orthogonal and no error checking is applied. Thus, the user
* must insure that the three axes being provided indeed represents a proper
* right handed coordinate system.
*
* @param axis
* the array containing the three vectors representing the
* coordinate system.
*/
public Quaternion fromAxes(Vector3f[] axis) {
if (axis.length != 3)
throw new IllegalArgumentException(
"Axis array must have three elements");
return fromAxes(axis[0], axis[1], axis[2]);
}
/**
*
* <code>fromAxes</code> creates a <code>Quaternion</code> that
* represents the coordinate system defined by three axes. These axes are
* assumed to be orthogonal and no error checking is applied. Thus, the user
* must insure that the three axes being provided indeed represents a proper
* right handed coordinate system.
*
* @param xAxis vector representing the x-axis of the coordinate system.
* @param yAxis vector representing the y-axis of the coordinate system.
* @param zAxis vector representing the z-axis of the coordinate system.
*/
public Quaternion fromAxes(Vector3f xAxis, Vector3f yAxis, Vector3f zAxis) {
return fromRotationMatrix(xAxis.x, yAxis.x, zAxis.x, xAxis.y, yAxis.y,
zAxis.y, xAxis.z, yAxis.z, zAxis.z);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -