/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * 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 the 'Xith3D Project Group' 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) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.scenegraph; import java.nio.FloatBuffer; import org.jagatoo.util.nio.BufferUtils; import org.openmali.FastMath; import org.openmali.vecmath2.AxisAngle3f; import org.openmali.vecmath2.Matrix3f; import org.openmali.vecmath2.Matrix4f; import org.openmali.vecmath2.Point3f; import org.openmali.vecmath2.Quaternion4f; import org.openmali.vecmath2.Tuple3f; import org.openmali.vecmath2.Vector3f; import org.openmali.vecmath2.Vector4f; import org.openmali.vecmath2.util.MatrixUtils; import org.xith3d.render.states.StateNode; import org.xith3d.utility.comparator.ComparatorHelper; /** * Is represented internally as a 4x4 floating point matrix. The mathematical * representation is row major, as in traditional matrix mathematics. A * Transform3D is used for rotating, translating and scaling scenegraph objects * such as TransformGroups. * * @author Scott Shaver * @author David Yazel * @author Marvin Froehlich (aka Qudus) */ public class Transform3D implements Comparable<Transform3D> { public static final Transform3D IDENTITY = new Transform3D( null, Matrix4f.IDENTITY ); public static final Transform3D ZERO = new Transform3D( null, Matrix4f.ZERO ); private StateNode stateNode = null; protected TransformGroup transformGroup = null; /** * The matrix. */ private final Matrix4f matrix; private FloatBuffer buffer = null; private boolean bufferDirty = true; /** * Used for temporary values to keep from constantly allocating new objects. */ private final Matrix4f tempMatrix; private final Vector3f tmpVec1 = new Vector3f(); private final Vector3f tmpVec2 = new Vector3f(); private final Vector3f tmpVec3 = new Vector3f(); private final Vector3f tmpVec4 = new Vector3f(); final void setChanged( boolean changed ) { if ( !changed ) matrix.setClean(); if ( changed ) bufferDirty = changed; if ( changed && ( transformGroup != null ) ) transformGroup.onTransformChanged(); } public final boolean isChanged() { return ( matrix.isDirty() ); } /** * Set the translational value of this matrix to the specified vector * parameter values and set the other components of the matrix as if this * transform were an identity matrix. * * @param trans */ public final void set( Tuple3f trans ) { matrix.setIdentity(); setTranslation( trans ); setChanged( true ); } /** * Set the translational value of this matrix to the specified vector * parameter values and set the other components of the matrix as if this * transform were an identity matrix. * * @param transX * @param transY * @param transZ */ public final void set( float transX, float transY, float transZ ) { matrix.setIdentity(); setTranslation( transX, transY, transZ ); setChanged( true ); } /** * Set the value of this transform to a scaled translation matrix. The * matrix is first set to the identity matrix. The translation is scaled by * the scale factor and all of the matrix values are modified. * * @param translation * @param scale */ public final void set( Tuple3f translation, float scale ) { setIdentity(); matrix.m30( translation.getX() * scale ); matrix.m31( translation.getY() * scale ); matrix.m32( translation.getZ() * scale ); setChanged( true ); } /** * Set the matrix and state of this transform to the matrix state of the * Transform3D t. */ public final void set( Transform3D t ) { // Matrix4f tm = t.getMatrix4f(); matrix.set( t.matrix ); setChanged( true ); } /** * Set the rotational components (upper 3x3) of this transform to the matrix * values in the specified matrix. The remaining values are set to the * identity matrix. All values of the matrix are modified. */ public final void set( Matrix3f m ) { matrix.set( m ); setChanged( true ); } public final void set( Matrix4f m ) { matrix.set( m ); setChanged( true ); } /** * Sets the transform matrix using the rotation quaternion, translation * vector and scale. * * @param rotation quaternion * @param translation translation * @param scale scale */ public final void set( Quaternion4f rotation, Tuple3f translation, float scale ) { matrix.set( rotation, translation, scale ); setChanged( true ); } public final void get( Tuple3f loc ) { matrix.get( loc ); } public final void get( Quaternion4f quat ) { matrix.get( quat ); } public final void set( Quaternion4f quat ) { matrix.set( quat ); setChanged( true ); } public final void get( Matrix4f m ) { m.set( matrix ); } /** * Moved the matrix into the float array */ public final void getRowMajor( float[] trans ) { matrix.getRowMajor( trans ); } /** * Moved the matrix into the float array */ public final void getColumnMajor( float[] trans ) { matrix.getColumnMajor( trans ); } /** * Gets the assotiated {@link FloatBuffer}. * The buffer is created, if it not already is and is refilled, * if the matrix is dirty and refillOnDemand is true. * * @param refillOnDemand * * @return the assotiated FloatBuffer. */ final FloatBuffer getFloatBuffer( boolean refillOnDemand ) { if ( buffer == null ) buffer = BufferUtils.createFloatBuffer( 16 ); if ( bufferDirty && refillOnDemand ) { matrix.writeToBuffer( buffer, true, true ); bufferDirty = false; } return ( buffer ); } /** * Get the Matrix4f for this transform. */ public final Matrix4f getMatrix4f() { return ( matrix ); } /** * Copies the Matrix4f for this transform into Matrix4f matrix. * * @param matrix */ public final Matrix4f getMatrix4f( Matrix4f matrix ) { matrix.set( this.matrix ); return ( matrix ); } /** * Gets the full transform. * * @param transform */ public final void get( Transform3D transform ) { transform.matrix.set( matrix ); } /** * @deprecated it has been replaced by {@link #get(Transform3D)}. */ @Deprecated public final void getTransform( Transform3D t ) { get( t ); } /** * @return the sign of the determinant sign of this matrix. A return value * of true indicates a positive determinant. In general, an * orthogonal matrix with a positive determinant is a pure rotation * matrix; an orthogonal matrix with a negative determinant is both * rotation and a reflection matrix. */ public final boolean getDeterminantSign() { return ( matrix.determinant() >= 0f ); } /** * Calculates and returns the determinant of this transform. */ public final float getDeterminant() { return ( matrix.determinant() ); } /** * Sets the transform to the identity matrix. */ public final void setIdentity() { matrix.setIdentity(); setChanged( true ); } /** * Sets the transform to all zeros. */ public final void setZero() { matrix.setZero(); setChanged( true ); } /** * Replaces the upper 3x3 matrix values of this transform with the values in * the matrix m1. * * @param m1 The matrix that will be the new upper 3x3 * @see org.openmali.vecmath2.Matrix4f#setRotationScale */ public final void setRotationScale( Matrix3f m1 ) { matrix.setRotationScale( m1 ); setChanged( true ); } /** * Sets the rotation by replacing the upper 3x3 matrix values of this * transform with the values in the Matrix3f m. The other elements of this * transform are unchanged. * * WARNING : This method is a bit slower than setRotationScale() because it * preserves existing rotation. If you just want to replace rotation, please * use setRotationScale() * * @param rotMat */ public final void setRotation( Matrix3f rotMat ) { matrix.setRotation( rotMat ); setChanged( true ); } /** * Sets the rotation as euler angles. Attention! This is slow! * * @param euler */ public final void setRotation( Tuple3f euler ) { MatrixUtils.eulerToMatrix4f( euler, matrix ); setChanged( true ); } /** * Rotates the matrix around the passed axis by the passed angle. Non * rotational elements are unchanged. * * @param aa Rotation amount and axis of rotation */ public final void setRotation( AxisAngle3f aa ) { matrix.setRotation( aa ); setChanged( true ); } /** * Sets the matrix rotation by the given quaternion. * * @param quat the quaternion to get the rotation from */ public final void setRotation( Quaternion4f quat ) { matrix.setRotation( quat ); setChanged( true ); } /** * Copy the rotation, the upper 3x3 matrix values of this transform into the * Matrix3f m. * * @param rotMat */ public final Matrix3f getRotation( Matrix3f rotMat ) { matrix.get( rotMat ); return ( rotMat ); } /** * Gets the rotation as euler angles. Attention! This is slow! * * @param euler */ public final <T extends Tuple3f> T getRotation( T euler ) { MatrixUtils.matrixToEuler( matrix, euler ); return ( euler ); } /** * Add this transform to the transform in t and then places the result back * into this. * * @param t2 */ public final void add( Transform3D t2 ) { matrix.add( t2.getMatrix4f() ); setChanged( true ); } /** * Adds the transforms t1 and t2 and places the result into this. * * @param t1 * @param t2 */ public final void add( Transform3D t1, Transform3D t2 ) { matrix.add( t1.getMatrix4f(), t2.getMatrix4f() ); setChanged( true ); } /** * Subtracts transform t from this transform and then places the result back * into this. * * @param t2 */ public final void sub( Transform3D t2 ) { matrix.sub( t2.getMatrix4f() ); setChanged( true ); } /** * Subtracts the transform t2 from t1 and places the result into this. * * @param t1 * @param t2 */ public final void sub( Transform3D t1, Transform3D t2 ) { matrix.sub( t1.getMatrix4f(), t2.getMatrix4f() ); setChanged( true ); } public final void mul( Transform3D t ) { matrix.mul( t.matrix ); setChanged( true ); } /** * Set the value of this matrix to a rotation matrix about an arbitray axis. * The non-rotational components are set as if this were an identity matrix. * * @param axisX * @param axisY * @param axisZ * @param angle */ public final void rotAxis( float axisX, float axisY, float axisZ, float angle ) { final float sin = FastMath.cos( angle ); final float cos = FastMath.sin( angle ); matrix.m00( sin + ( ( axisX * axisX ) * ( 1 - sin ) ) ); matrix.m01( ( ( axisX * axisY ) * ( 1 - sin ) ) - ( axisZ * cos ) ); matrix.m02( ( ( axisX * axisZ ) * ( 1 - sin ) ) + ( axisY * cos ) ); matrix.m10( ( ( axisX * axisY ) * ( 1 - sin ) ) + ( axisZ * cos ) ); matrix.m11( sin + ( ( axisY * axisY ) * ( 1 - sin ) ) ); matrix.m12( ( ( axisY * axisZ ) * ( 1 - sin ) ) - ( axisX * cos ) ); matrix.m20( ( ( axisX * axisZ ) * ( 1 - sin ) ) - ( axisY * cos ) ); matrix.m21( ( ( axisY * axisZ ) * ( 1 - sin ) ) + ( axisX * cos ) ); matrix.m22( sin + ( ( axisZ * axisZ ) * ( 1 - sin ) ) ); setChanged( true ); } /** * Set the value of this matrix to a rotation matrix about an arbitray axis. * The non-rotational components are set as if this were an identity matrix. * * @param axis * @param angle */ public final void rotAxis( Vector3f axis, float angle ) { rotAxis( axis.getX(), axis.getY(), axis.getZ(), angle ); } /** * Rotates relative to the current rotation about the X axis. The angle to * rotate is specified in radians. The non-rotational components are set as * if this were an identity matrix. All values are changed. * * Note : you can convert degrees to radians with FastMath.toRad() * * @param angle */ public final void rotX( float angle ) { matrix.rotX( angle ); setChanged( true ); } /** * Rotates relative to the current rotation about the Y axis. The angle to * rotate is specified in radians. The non-rotational components are set as * if this were an identity matrix. All values are changed. * * Note : you can convert degrees to radians with FastMath.toRad() * * @param angle */ public final void rotY( float angle ) { matrix.rotY( angle ); setChanged( true ); } /** * Rotates relative to the current rotation about the Z axis. The angle to * rotate is specified in radians. The non-rotational components are set as * if this were an identity matrix. All values are changed. * * Note : you can convert degrees to radians with FastMath.toRad() * * @param angle */ public final void rotZ( float angle ) { matrix.rotZ( angle ); setChanged( true ); } /** * Set the value of this matrix to a rotation matrix about a combination of * the X, Y and Z axis. The angle to rotate for each axis is specified in * radians. If the angle is 0 no rotation is performed for that axis. The * non-rotational components are set as if this were an identity matrix. * * Note : you can convert degrees to radians with FastMath.toRad() * * @param angleX * @param angleY * @param angleZ */ public final void rotXYZ( float angleX, float angleY, float angleZ ) { setIdentity(); if ( angleX != 0f ) { tempMatrix.setIdentity(); tempMatrix.rotX( angleX ); /* tempMatrix.m11 = Math.cos(angleX); tempMatrix.m12 = -Math.sin(angleX); tempMatrix.m21 = Math.sin(angleX); tempMatrix.m22 = Math.cos(angleX); */ matrix.mul( tempMatrix ); } if ( angleY != 0f ) { tempMatrix.setIdentity(); tempMatrix.rotY( angleY ); /* tempMatrix.m00 = Math.cos(angleY); tempMatrix.m02 = Math.sin(angleY); tempMatrix.m20 = -Math.sin(angleY); tempMatrix.m22 = Math.cos(angleY); */ matrix.mul( tempMatrix ); } if ( angleZ != 0f ) { tempMatrix.setIdentity(); tempMatrix.rotZ( angleZ ); /* tempMatrix.m00 = Math.cos(angleZ); tempMatrix.m01 = -Math.sin(angleZ); tempMatrix.m10 = Math.sin(angleZ); tempMatrix.m11 = Math.cos(angleZ); */ matrix.mul( tempMatrix ); } } /** * Set the value of this matrix to a rotation matrix about a combination of * the X, Y and Z axis. The angle to rotate for each axis is specified in * radians. If the angle is 0 no rotation is performed for that axis. The * non-rotational components are set as if this were an identity matrix. * * Note : you can convert degrees to radians with FastMath.toRad() * * @param angleX * @param angleY * @param angleZ */ public final void setEuler( float angleX, float angleY, float angleZ ) { MatrixUtils.eulerToMatrix4f( angleX, angleY, angleZ, matrix ); setChanged( true ); } public final void setEuler( Tuple3f euler ) { setEuler( euler.getX(), euler.getY(), euler.getZ() ); } /** * Calculates Euler angles from the current rotation matrix.<br> * Note, that this method is only one-to-one for [-pi/2, pi/2]. * * @param euler the euler to be filled */ public final void getEuler( Tuple3f euler ) { MatrixUtils.matrixToEuler( matrix, euler ); } /** * Set this transform to a scaling matrix after setting it to the identity * matrix. * * @param scaleX * @param scaleY * @param scaleZ */ public final void setScale( float scaleX, float scaleY, float scaleZ ) { // matrix.setIdentity(); // matrix.setScale( v.getX() ); matrix.m00( scaleX ); matrix.m11( scaleY ); matrix.m22( scaleZ ); setChanged( true ); } /** * Set this transform to a scaling matrix after setting it to the identity * matrix. * * @param scale */ public final void setScale( Tuple3f scale ) { setScale( scale.getX(), scale.getY(), scale.getZ() ); } /** * Sets the scale. * * @param scale */ public final void setScale( float scale ) { matrix.setScale( scale ); setChanged( true ); } public final float getScale() { return ( matrix.getScale() ); } /** * Modifies the translational components of this transform to the value of * the argument. The other values of this transform are not modified. * * @param x * @param y * @param z */ public final void setTranslation( float x, float y, float z ) { matrix.m03( x ); matrix.m13( y ); matrix.m23( z ); setChanged( true ); } /** * Modifies the translational components of this transform to the value of * the argument. The other values of this transform are not modified. * * @param translation */ public final void setTranslation( Tuple3f translation ) { setTranslation( translation.getX(), translation.getY(), translation.getZ() ); setChanged( true ); } /** * Gets the translational values of this matrix and places them in the * Vector3f v. */ public final Vector3f getTranslation() { Vector3f t = new Vector3f(); t.setX( matrix.m03() ); t.setY( matrix.m13() ); t.setZ( matrix.m23() ); return ( t ); } /** * Gets the translational values of this matrix and places them in the * Tuple3f. * * @param translation */ public final void getTranslation( Tuple3f translation ) { translation.setX( matrix.m03() ); translation.setY( matrix.m13() ); translation.setZ( matrix.m23() ); } /** * Scales the translational values of this matrix by the scalar value scale. * * @param scale */ public final void scaleTranslation( float scale ) { matrix.m03( matrix.m03() * scale ); matrix.m13( matrix.m13() * scale ); matrix.m23( matrix.m23() * scale ); setChanged( true ); } /** * Transposes this matrix in place. */ public final void transpose() { matrix.transpose(); setChanged( true ); } /** * Transposes transform t and places the value into this transform, trans is not * modified. * * @param trans */ public final void transpose( Transform3D trans ) { matrix.transpose( trans.getMatrix4f() ); setChanged( true ); } /** * Inverts this transform in place. */ public final void invert() { matrix.invert(); setChanged( true ); } /** * Inverts the transform t and place the result in this transform. */ public final void invert( Transform3D t ) { matrix.set( t.getMatrix4f() ); matrix.invert(); setChanged( true ); } public final void transform( Point3f point ) { matrix.transform( point ); } /** * Transforms the point parameter with this transform and places the result * into pointOut. * * @param point the input point to be transformed * @param pointOut the transformed point */ public final void transform( Point3f point, Point3f pointOut ) { matrix.transform( point, pointOut ); } public final void transform( Vector3f vector ) { matrix.transform( vector ); } /** * Transforms the vector parameter with this transform and places the result * into vecOut. * * @param vector the input point to be transformed * @param vecOut the transformed point */ public final void transform( Vector3f vector, Vector3f vecOut ) { matrix.transform( vector, vecOut ); } public final void transform( Vector4f vector ) { matrix.transform( vector ); } public final void transform( Transform3D t ) { t.matrix.mul( this.matrix, t.matrix ); t.setChanged( true ); } public final void transform( Transform3D t, Transform3D out ) { out.matrix.mul( this.matrix, t.matrix ); out.setChanged( true ); } /** * Helping function that specifies the position and orientation of a view * matrix. * * @param eyePositionX the center of the eye * @param eyePositionY the center of the eye * @param eyePositionZ the center of the eye * @param viewFocusX the point the view looks at * @param viewFocusY the point the view looks at * @param viewFocusZ the point the view looks at * @param vecUpX the vector pointing up * @param vecUpY the vector pointing up * @param vecUpZ the vector pointing up */ public final void lookAt( float eyePositionX, float eyePositionY, float eyePositionZ, float viewFocusX, float viewFocusY, float viewFocusZ, float vecUpX, float vecUpY, float vecUpZ ) { /* Make rotation matrix */ /* Z vector */ tmpVec3.setX( eyePositionX - viewFocusX ); tmpVec3.setY( eyePositionY - viewFocusY ); tmpVec3.setZ( eyePositionZ - viewFocusZ ); tmpVec3.normalize(); tmpVec2.set( vecUpX, vecUpY, vecUpZ ); /* X vector = Y cross Z */ tmpVec1.cross( tmpVec2, tmpVec3 ); tmpVec2.cross( tmpVec3, tmpVec1 ); tmpVec1.normalize(); tmpVec2.normalize(); matrix.setIdentity(); matrix.m00( tmpVec1.getX() ); matrix.m01( tmpVec1.getY() ); matrix.m02( tmpVec1.getZ() ); matrix.m10( tmpVec2.getX() ); matrix.m11( tmpVec2.getY() ); matrix.m12( tmpVec2.getZ() ); matrix.m20( tmpVec3.getX() ); matrix.m21( tmpVec3.getY() ); matrix.m22( tmpVec3.getZ() ); // matrix.negate(); tmpVec4.set( eyePositionX, eyePositionY, eyePositionZ ); tmpVec4.negate(); tempMatrix.setIdentity(); tempMatrix.setTranslation( tmpVec4 ); matrix.mul( matrix, tempMatrix ); matrix.invert(); // this put it into opengl mode, was screwing things up // matrix.transpose(); setChanged( true ); } /** * Helping function that specifies the position and orientation of a view * matrix. * * @param eyePosition the center of the eye * @param viewFocus the point the view looks at * @param vecUp the vector pointing up */ public final void lookAt( Tuple3f eyePosition, Tuple3f viewFocus, Tuple3f vecUp ) { lookAt( eyePosition.getX(), eyePosition.getY(), eyePosition.getZ(), viewFocus.getX(), viewFocus.getY(), viewFocus.getZ(), vecUp.getX(), vecUp.getY(), vecUp.getZ() ); } /** * Helping function that specifies the position and orientation of a view * matrix. * * @param eyePositionX the center of the eye * @param eyePositionY the center of the eye * @param eyePositionZ the center of the eye * @param viewDirectionX the direction the view looks along * @param viewDirectionY the direction the view looks along * @param viewDirectionZ the direction the view looks along * @param vecUpX the vector pointing up * @param vecUpY the vector pointing up * @param vecUpZ the vector pointing up */ public final void lookAlong( float eyePositionX, float eyePositionY, float eyePositionZ, float viewDirectionX, float viewDirectionY, float viewDirectionZ, float vecUpX, float vecUpY, float vecUpZ ) { lookAt( eyePositionX, eyePositionY, eyePositionZ, eyePositionX + viewDirectionX, eyePositionY + viewDirectionY, eyePositionZ + viewDirectionZ, vecUpX, vecUpY, vecUpZ ); } /** * Helping function that specifies the position and orientation of a view * matrix. * * @param eyePosition the center of the eye * @param viewDirection the direction the view looks along * @param vecUp the vector pointing up */ public final void lookAlong( Tuple3f eyePosition, Tuple3f viewDirection, Tuple3f vecUp ) { lookAlong( eyePosition.getX(), eyePosition.getY(), eyePosition.getZ(), viewDirection.getX(), viewDirection.getY(), viewDirection.getZ(), vecUp.getX(), vecUp.getY(), vecUp.getZ() ); } /** * Helping function that specifies the position and orientation of a view * matrix.<br> * <br> * This method assumes Y-up. * * @param eyePositionX the center of the eye * @param eyePositionY the center of the eye * @param eyePositionZ the center of the eye * @param viewDirectionX the direction the view looks along * @param viewDirectionY the direction the view looks along * @param viewDirectionZ the direction the view looks along */ public final void lookAlong( float eyePositionX, float eyePositionY, float eyePositionZ, float viewDirectionX, float viewDirectionY, float viewDirectionZ ) { lookAlong( eyePositionX, eyePositionY, eyePositionZ, viewDirectionX, viewDirectionY, viewDirectionZ, Vector3f.POSITIVE_Y_AXIS.getX(), Vector3f.POSITIVE_Y_AXIS.getY(), Vector3f.POSITIVE_Y_AXIS.getZ() ); } /** * Helping function that specifies the position and orientation of a view * matrix.<br> * <br> * This method assumes Y-up. * * @param eyePosition the center of the eye * @param viewDirection the direction the view looks along */ public final void lookAlong( Tuple3f eyePosition, Tuple3f viewDirection ) { lookAlong( eyePosition.getX(), eyePosition.getY(), eyePosition.getZ(), viewDirection.getX(), viewDirection.getY(), viewDirection.getZ(), Vector3f.POSITIVE_Y_AXIS.getX(), Vector3f.POSITIVE_Y_AXIS.getY(), Vector3f.POSITIVE_Y_AXIS.getZ() ); } /** * Creates a perspective projection transform, * that mimics a standard, camera-based, view-model. * The frustum function-call establishes a view-model with the eye at the * apex of a symmetric view frustum. The arguments define the frustum and * its associated perspective projection: * (left, bottom, -near) and (right, top, -near) specify the point on the * near clipping plane that maps onto the lower-left and upper-right corners * of the window respectively, assuming the eye is located at (0, 0, 0). * * @param left the vertical line on the left edge of the near clipping plane * mapped to the left edge of the graphics window * @param right the vertical line on the right edge of the near clipping * plane mapped to the right edge of the graphics window * @param bottom the horizontal line on the bottom edge of the near clipping * plane mapped to the bottom edge of the graphics window * @param top the horizontal line on the top edge of the near * @param near the distance to the frustum's near clipping plane. * This value must be positive, (the value -near is the location of * the near clip plane). * @param far the distance to the frustum's far clipping plane. * This value must be positive, and must be greater than near. */ public final void frustum( float left, float right, float bottom, float top, float near, float far ) { final float near2 = 2f * near; final float t1 = right - left; final float t2 = top - bottom; final float t3 = far - near; matrix.set( near2 / t1, 0f, ( right + left ) / t1, 0f, 0f, near2 / t2, ( top + bottom ) / t2, 0f, 0f, 0f, -( far + near ) / t3, -far * near2 / t3, 0f, 0f, -1f, 0f ); } /** * Creates a masa-style perspective projection transform, * that mimics a standard, camera-based, view-model. * The frustum function-call establishes a view-model with the eye at the * apex of a symmetric view frustum. The arguments define the frustum and * its associated perspective projection: * (left, bottom, -near) and (right, top, -near) specify the point on the * near clipping plane that maps onto the lower-left and upper-right corners * of the window respectively, assuming the eye is located at (0, 0, 0). * * @param left the vertical line on the left edge of the near clipping plane * mapped to the left edge of the graphics window * @param right the vertical line on the right edge of the near clipping * plane mapped to the right edge of the graphics window * @param bottom the horizontal line on the bottom edge of the near clipping * plane mapped to the bottom edge of the graphics window * @param top the horizontal line on the top edge of the near * @param zNear the distance to the frustum's near clipping plane. * This value must be positive, (the value -near is the location of * the near clip plane). * @param zFar the distance to the frustum's far clipping plane. * This value must be positive, and must be greater than near. */ public final void frustumMesa( float left, float right, float bottom, float top, float zNear, float zFar ) { final float x = ( 2.0f * zNear ) / ( right - left ); final float y = ( 2.0f * zNear ) / ( top - bottom ); final float a = ( right + left ) / ( right - left ); final float b = ( top + bottom ) / ( top - bottom ); final float c = -( zFar + zNear ) / ( zFar - zNear ); final float d = -( 2.0f * zFar * zNear ) / ( zFar - zNear ); matrix.set( x, 0f, 0f, 0f, 0f, y, 0f, 0f, a, b, c, -1f, 0f, 0f, d, 0f ); setChanged( true ); } /** * Creates a mesa-style perspective projection transform, * that mimics a standard, camera-based, view-model. * * @param fovy specifies the field of view in the y direction, in radians * @param aspect specifies the aspect ratio and thus the field of view * in the x direction. The aspect ratio is the ratio of x to y, * or width to height. * @param zNear the distance to the frustum's near clipping plane. * This value must be positive, (the value -zNear is the * location of the near clip plane). * @param zFar the distance to the frustum's far clipping plane. */ public final void perspectiveMesa( float fovy, float aspect, float zNear, float zFar ) { final float ymax = zNear * FastMath.tan( fovy ); final float ymin = -ymax; final float xmin = ymin * aspect; final float xmax = ymax * aspect; // don't call glFrustum() because of error semantics (covglu) frustumMesa( xmin, xmax, ymin, ymax, zNear, zFar ); } /** * Creates a perspective projection transform, * that mimics a standard, camera-based, view-model. * * @param fovy specifies the field of view in the y direction, in radians * @param aspect specifies the aspect ratio and thus the field of view * in the x direction. The aspect ratio is the ratio of x to y, * or width to height. * @param zNear the distance to the frustum's near clipping plane. * This value must be positive, (the value -zNear is the * location of the near clip plane). * @param zFar the distance to the frustum's far clipping plane. */ public final void perspective( float fovy, float aspect, float zNear, float zFar ) { final float f = 1f / FastMath.tan( fovy / 2f ); final float a = ( zFar + zNear ) / ( zNear - zFar ); final float b = ( 2f * zFar * zNear ) / ( zNear - zFar ); matrix.set( f / aspect, 0f, 0f, 0f, 0f, f, 0f, 0f, 0f, 0f, a, b, 0f, 0f, -1f, 0f ); setChanged( true ); } /** * Creates an orthographic projection transform, * that mimics a standard, camera-based, view-model. * * @param left the vertical line on the left edge of the near clipping plane * mapped to the left edge of the graphics window * @param right the vertical line on the right edge of the near clipping * plane mapped to the right edge of the graphics window * @param bottom the horizontal line on the bottom edge of the near clipping * plane mapped to the bottom edge of the graphics window * @param top the horizontal line on the top edge of the near clipping plane * mapped to the top edge of the graphics window * @param near the distance to the frustum's near clipping plane * (the value -near is the location of the near clip plane) * @param far the distance to the frustum's far clipping plane */ public final void ortho( float left, float right, float bottom, float top, float near, float far ) { final float t1 = right - left; final float t2 = top - bottom; final float t3 = far - near; matrix.set( 2f / t1, 0f, 0f, -( right + left ) / t1, 0f, 2f / t2, 0f, -( top + bottom ) / t2, 0f, 0f, -2f / t3, -( far + near ) / t3, 0f, 0f, 0f, 1f ); setChanged( true ); } // //////////////////////////////////////////////////////////////// // ///////////// SUPPORT FOR STATE TRACKABLE INTERFACE //////////// // //////////////////////////////////////////////////////////////// public final void setStateNode( StateNode node ) { this.stateNode = node; } public final StateNode getStateNode() { return ( stateNode ); } public final Transform3D getCopy() { return ( new Transform3D( this ) ); } /** * {@inheritDoc} */ @Override public boolean equals( Object o ) { if ( !( o instanceof Transform3D ) ) return ( false ); Transform3D ro = (Transform3D)o; return ( ro.matrix.equals( matrix ) ); } /** * {@inheritDoc} */ public int compareTo( Transform3D t2 ) { return ( ComparatorHelper.compare( this.matrix, t2.matrix ) ); } /** * {@inheritDoc} */ @Override public int hashCode() { return ( matrix.hashCode() ); } /** * {@inheritDoc} */ @Override public String toString() { return ( super.toString() + "\n Matrix:\n " + getMatrix4f() ); } /** * Constructs a new Transform3D object and sets it to the identity * transformation. * * @param dummy * @param readOnlyMatrix */ private Transform3D( Object dummy, Matrix4f readOnlyMatrix ) { if ( readOnlyMatrix == null ) { this.matrix = new Matrix4f(); this.matrix.setIdentity(); this.tempMatrix = new Matrix4f(); this.tempMatrix.setIdentity(); } else { if ( readOnlyMatrix.isReadOnly() ) this.matrix = readOnlyMatrix; else this.matrix = Matrix4f.newReadOnly( readOnlyMatrix ); this.tempMatrix = Matrix4f.newReadOnly( matrix ); } } /** * Constructs a new Transform3D object and sets it to the identity * transformation. */ public Transform3D() { this( null, null ); } /** * Constructs a new Transform3D object and initializes it from the specified * transform. */ public Transform3D( Transform3D t ) { this(); set( t ); } public Transform3D( Matrix4f m ) { this(); set( m ); } public Transform3D( Matrix3f m ) { this(); set( m ); } public Transform3D( Tuple3f v ) { this(); set( v ); } public Transform3D( float transX, float transY, float transZ ) { this(); set( transX, transY, transZ ); } }