/** * Sets the world axis values after checking that they are all orthogonal to each other. The check performed * is to verify that the cross product between {@code right} and {@code up} is equivilant to {@code forward} * withing 1ppm error on each component. * * @param right {@link Vector3} The desired right vector. Must be normalized. * @param up {@link Vector3} The desired up vector. Must be normalized. * @param forward {@link Vector3} The desired forward vector. Must be normalized. */ public static void setWorldAxes(Vector3 right, Vector3 up, Vector3 forward) { TEMP_VECTOR.crossAndSet(right, up); if (!TEMP_VECTOR.equals(forward, 1e-6)) { throw new IllegalArgumentException("World axes must be orthogonal."); } RIGHT_AXIS.setAll(right); NEG_RIGHT_AXIS.setAll(RIGHT_AXIS).inverse(); UP_AXIS.setAll(up); NEG_UP_AXIS.setAll(UP_AXIS).inverse(); FORWARD_AXIS.setAll(forward); NEG_FORWARD_AXIS.setAll(FORWARD_AXIS).inverse(); } }
/** * Resets the orientation of this {@link ATransformable3D} object to look at its look at * target and use the specified {@link Vector3} as up. If this is part of a scene graph, * the graph will be notified of the change. * * @param upAxis {@link Vector3} The direction to use as the up axis. * * @return A reference to this {@link ATransformable3D} to facilitate chaining. */ public ATransformable3D resetToLookAt(Vector3 upAxis) { mTempVec.subtractAndSet(mLookAt, mPosition); // In OpenGL, Cameras are defined such that their forward axis is -Z, not +Z like we have defined objects. if (mIsCamera) mTempVec.inverse(); mOrientation.lookAt(mTempVec, upAxis); mLookAtValid = true; markModelMatrixDirty(); return this; }
/** * Sets this {@link Quaternion} to be oriented to a target {@link Vector3}. * It is safe to use the input vectors for other things as they are cloned internally. * * @param lookAt {@link Vector3} The point to look at. * @param upDirection {@link Vector3} to use as the up direction. * * @return A reference to this {@link Quaternion} to facilitate chaining. */ @NonNull public Quaternion lookAt(@NonNull Vector3 lookAt, @NonNull Vector3 upDirection) { mTmpVec1.setAll(lookAt); mTmpVec2.setAll(upDirection); // Vectors are parallel/anti-parallel if their dot product magnitude and length product are equal final double dotProduct = Vector3.dot(lookAt, upDirection); final double dotError = Math.abs(Math.abs(dotProduct) - (lookAt.length() * upDirection.length())); if (dotError <= PARALLEL_TOLERANCE) { // The look and up vectors are parallel mTmpVec2.normalize(); if (dotProduct < 0) { mTmpVec1.inverse(); } fromRotationBetween(WorldParameters.FORWARD_AXIS, mTmpVec1); return this; } Vector3.orthoNormalize(mTmpVec1, mTmpVec2); // Find the forward and up vectors mTmpVec3.crossAndSet(mTmpVec2, mTmpVec1); // Create the right vector fromAxes(mTmpVec3, mTmpVec2, mTmpVec1); return this; }
@Test public void testInverse() { final Vector3 v = new Vector3(1d, 2d, 3d); final Vector3 out = v.inverse(); assertNotNull(out); assertTrue(out == v); assertEquals(-1d, v.x, 0); assertEquals(-2d, v.y, 0); assertEquals(-3d, v.z, 0); }
@Override public Matrix4 getViewMatrix() { Matrix4 m = super.getViewMatrix(); if (mTarget != null) { mScratchMatrix.identity(); mScratchMatrix.translate(mTarget.getPosition()); m.multiply(mScratchMatrix); } mScratchMatrix.identity(); mScratchMatrix.rotate(mEmpty.getOrientation()); m.multiply(mScratchMatrix); if (mTarget != null) { mScratchVector.setAll(mTarget.getPosition()); mScratchVector.inverse(); mScratchMatrix.identity(); mScratchMatrix.translate(mScratchVector); m.multiply(mScratchMatrix); } return m; }
@Override public void onDrawEye(Eye eye) { getCurrentCamera().updatePerspective( eye.getFov().getLeft(), eye.getFov().getRight(), eye.getFov().getBottom(), eye.getFov().getTop()); mCurrentEyeMatrix.setAll(eye.getEyeView()); mCurrentEyeOrientation.fromMatrix(mCurrentEyeMatrix); getCurrentCamera().setOrientation(mCurrentEyeOrientation); getCurrentCamera().setPosition(mCameraPosition); getCurrentCamera().getPosition().add(mCurrentEyeMatrix.getTranslation().inverse()); super.onRenderFrame(null); }
normal.inverse();
/** * Sets the world axis values after checking that they are all orthogonal to each other. The check performed * is to verify that the cross product between {@code right} and {@code up} is equivilant to {@code forward} * withing 1ppm error on each component. * * @param right {@link Vector3} The desired right vector. Must be normalized. * @param up {@link Vector3} The desired up vector. Must be normalized. * @param forward {@link Vector3} The desired forward vector. Must be normalized. */ public static void setWorldAxes(Vector3 right, Vector3 up, Vector3 forward) { TEMP_VECTOR.crossAndSet(right, up); if (!TEMP_VECTOR.equals(forward, 1e-6)) { throw new IllegalArgumentException("World axes must be orthogonal."); } RIGHT_AXIS.setAll(right); NEG_RIGHT_AXIS.setAll(RIGHT_AXIS).inverse(); UP_AXIS.setAll(up); NEG_UP_AXIS.setAll(UP_AXIS).inverse(); FORWARD_AXIS.setAll(forward); NEG_FORWARD_AXIS.setAll(FORWARD_AXIS).inverse(); } }
/** * Resets the orientation of this {@link ATransformable3D} object to look at its look at * target and use the specified {@link Vector3} as up. If this is part of a scene graph, * the graph will be notified of the change. * * @param upAxis {@link Vector3} The direction to use as the up axis. * * @return A reference to this {@link ATransformable3D} to facilitate chaining. */ public ATransformable3D resetToLookAt(Vector3 upAxis) { mTempVec.subtractAndSet(mLookAt, mPosition); // In OpenGL, Cameras are defined such that their forward axis is -Z, not +Z like we have defined objects. if (mIsCamera) mTempVec.inverse(); mOrientation.lookAt(mTempVec, upAxis); mLookAtValid = true; markModelMatrixDirty(); return this; }
/** * Sets this {@link Quaternion} to be oriented to a target {@link Vector3}. * It is safe to use the input vectors for other things as they are cloned internally. * * @param lookAt {@link Vector3} The point to look at. * @param upDirection {@link Vector3} to use as the up direction. * @return A reference to this {@link Quaternion} to facilitate chaining. */ public Quaternion lookAt(Vector3 lookAt, Vector3 upDirection) { mTmpVec1.setAll(lookAt); mTmpVec2.setAll(upDirection); // Vectors are parallel/anti-parallel if their dot product magnitude and length product are equal final double dotProduct = Vector3.dot(lookAt, upDirection); final double dotError = Math.abs(Math.abs(dotProduct) - (lookAt.length() * upDirection.length())); if (dotError <= 1e-6) { // The look and up vectors are parallel mTmpVec2.normalize(); if (dotProduct < 0) mTmpVec1.inverse(); fromRotationBetween(WorldParameters.FORWARD_AXIS, mTmpVec1); return this; } Vector3.orthoNormalize(mTmpVec1, mTmpVec2); // Find the forward and up vectors mTmpVec3.crossAndSet(mTmpVec1, mTmpVec2); // Create the right vector fromAxes(mTmpVec3, mTmpVec2, mTmpVec1); return this; }
@Override public Matrix4 getViewMatrix() { Matrix4 m = super.getViewMatrix(); if(mTarget != null) { mScratchMatrix.identity(); mScratchMatrix.translate(mTarget.getPosition()); m.multiply(mScratchMatrix); } mScratchMatrix.identity(); mScratchMatrix.rotate(mEmpty.getOrientation()); m.multiply(mScratchMatrix); if(mTarget != null) { mScratchVector.setAll(mTarget.getPosition()); mScratchVector.inverse(); mScratchMatrix.identity(); mScratchMatrix.translate(mScratchVector); m.multiply(mScratchMatrix); } return m; }
normal.inverse();