All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.joml.Matrix3f Maven / Gradle / Ivy

There is a newer version: 1.10.1
Show newest version
/*
 * The MIT License
 *
 * Copyright (c) 2015-2020 Richard Greenlees
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.joml;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.text.DecimalFormat;
import java.text.NumberFormat;


/**
 * Contains the definition of a 3x3 matrix of floats, and associated functions to transform
 * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
 * 

* m00 m10 m20
* m01 m11 m21
* m02 m12 m22
* * @author Richard Greenlees * @author Kai Burjack */ public class Matrix3f implements Externalizable, Matrix3fc { private static final long serialVersionUID = 1L; public float m00, m01, m02; public float m10, m11, m12; public float m20, m21, m22; /** * Create a new {@link Matrix3f} and set it to {@link #identity() identity}. */ public Matrix3f() { m00 = 1.0f; m11 = 1.0f; m22 = 1.0f; } /** * Create a new {@link Matrix3f} by setting its uppper left 2x2 submatrix to the values of the given {@link Matrix2fc} * and the rest to identity. * * @param mat * the {@link Matrix2fc} */ public Matrix3f(Matrix2fc mat) { set(mat); } /** * Create a new {@link Matrix3f} and make it a copy of the given matrix. * * @param mat * the {@link Matrix3fc} to copy the values from */ public Matrix3f(Matrix3fc mat) { set(mat); } /** * Create a new {@link Matrix3f} and make it a copy of the upper left 3x3 of the given {@link Matrix4fc}. * * @param mat * the {@link Matrix4fc} to copy the values from */ public Matrix3f(Matrix4fc mat) { set(mat); } /** * Create a new 3x3 matrix using the supplied float values. The order of the parameter is column-major, * so the first three parameters specify the three elements of the first column. * * @param m00 * the value of m00 * @param m01 * the value of m01 * @param m02 * the value of m02 * @param m10 * the value of m10 * @param m11 * the value of m11 * @param m12 * the value of m12 * @param m20 * the value of m20 * @param m21 * the value of m21 * @param m22 * the value of m22 */ public Matrix3f(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m20 = m20; this.m21 = m21; this.m22 = m22; } /** * Create a new {@link Matrix3f} by reading its 9 float components from the given {@link FloatBuffer} * at the buffer's current position. *

* That FloatBuffer is expected to hold the values in column-major order. *

* The buffer's position will not be changed by this method. * * @param buffer * the {@link FloatBuffer} to read the matrix values from */ public Matrix3f(FloatBuffer buffer) { MemUtil.INSTANCE.get(this, buffer.position(), buffer); } /** * Create a new {@link Matrix3f} and initialize its three columns using the supplied vectors. * * @param col0 * the first column * @param col1 * the second column * @param col2 * the third column */ public Matrix3f(Vector3fc col0, Vector3fc col1, Vector3fc col2) { set(col0, col1, col2); } public float m00() { return m00; } public float m01() { return m01; } public float m02() { return m02; } public float m10() { return m10; } public float m11() { return m11; } public float m12() { return m12; } public float m20() { return m20; } public float m21() { return m21; } public float m22() { return m22; } /** * Set the value of the matrix element at column 0 and row 0. * * @param m00 * the new value * @return this */ public Matrix3f m00(float m00) { this.m00 = m00; return this; } /** * Set the value of the matrix element at column 0 and row 1. * * @param m01 * the new value * @return this */ public Matrix3f m01(float m01) { this.m01 = m01; return this; } /** * Set the value of the matrix element at column 0 and row 2. * * @param m02 * the new value * @return this */ public Matrix3f m02(float m02) { this.m02 = m02; return this; } /** * Set the value of the matrix element at column 1 and row 0. * * @param m10 * the new value * @return this */ public Matrix3f m10(float m10) { this.m10 = m10; return this; } /** * Set the value of the matrix element at column 1 and row 1. * * @param m11 * the new value * @return this */ public Matrix3f m11(float m11) { this.m11 = m11; return this; } /** * Set the value of the matrix element at column 1 and row 2. * * @param m12 * the new value * @return this */ public Matrix3f m12(float m12) { this.m12 = m12; return this; } /** * Set the value of the matrix element at column 2 and row 0. * * @param m20 * the new value * @return this */ public Matrix3f m20(float m20) { this.m20 = m20; return this; } /** * Set the value of the matrix element at column 2 and row 1. * * @param m21 * the new value * @return this */ public Matrix3f m21(float m21) { this.m21 = m21; return this; } /** * Set the value of the matrix element at column 2 and row 2. * * @param m22 * the new value * @return this */ public Matrix3f m22(float m22) { this.m22 = m22; return this; } /** * Set the value of the matrix element at column 0 and row 0. * * @param m00 * the new value * @return this */ Matrix3f _m00(float m00) { this.m00 = m00; return this; } /** * Set the value of the matrix element at column 0 and row 1. * * @param m01 * the new value * @return this */ Matrix3f _m01(float m01) { this.m01 = m01; return this; } /** * Set the value of the matrix element at column 0 and row 2. * * @param m02 * the new value * @return this */ Matrix3f _m02(float m02) { this.m02 = m02; return this; } /** * Set the value of the matrix element at column 1 and row 0. * * @param m10 * the new value * @return this */ Matrix3f _m10(float m10) { this.m10 = m10; return this; } /** * Set the value of the matrix element at column 1 and row 1. * * @param m11 * the new value * @return this */ Matrix3f _m11(float m11) { this.m11 = m11; return this; } /** * Set the value of the matrix element at column 1 and row 2. * * @param m12 * the new value * @return this */ Matrix3f _m12(float m12) { this.m12 = m12; return this; } /** * Set the value of the matrix element at column 2 and row 0. * * @param m20 * the new value * @return this */ Matrix3f _m20(float m20) { this.m20 = m20; return this; } /** * Set the value of the matrix element at column 2 and row 1. * * @param m21 * the new value * @return this */ Matrix3f _m21(float m21) { this.m21 = m21; return this; } /** * Set the value of the matrix element at column 2 and row 2. * * @param m22 * the new value * @return this */ Matrix3f _m22(float m22) { this.m22 = m22; return this; } /** * Set the elements of this matrix to the ones in m. * * @param m * the matrix to copy the elements from * @return this */ public Matrix3f set(Matrix3fc m) { return _m00(m.m00()). _m01(m.m01()). _m02(m.m02()). _m10(m.m10()). _m11(m.m11()). _m12(m.m12()). _m20(m.m20()). _m21(m.m21()). _m22(m.m22()); } /** * Store the values of the transpose of the given matrix m into this matrix. * * @param m * the matrix to copy the transposed values from * @return this */ public Matrix3f setTransposed(Matrix3fc m) { float nm10 = m.m01(), nm12 = m.m21(); float nm20 = m.m02(), nm21 = m.m12(); return this ._m00(m.m00())._m01(m.m10())._m02(m.m20()) ._m10(nm10)._m11(m.m11())._m12(nm12) ._m20(nm20)._m21(nm21)._m22(m.m22()); } /** * Set the elements of this matrix to the left 3x3 submatrix of m. * * @param m * the matrix to copy the elements from * @return this */ public Matrix3f set(Matrix4x3fc m) { m00 = m.m00(); m01 = m.m01(); m02 = m.m02(); m10 = m.m10(); m11 = m.m11(); m12 = m.m12(); m20 = m.m20(); m21 = m.m21(); m22 = m.m22(); return this; } /** * Set the elements of this matrix to the upper left 3x3 of the given {@link Matrix4fc}. * * @param mat * the {@link Matrix4fc} to copy the values from * @return this */ public Matrix3f set(Matrix4fc mat) { m00 = mat.m00(); m01 = mat.m01(); m02 = mat.m02(); m10 = mat.m10(); m11 = mat.m11(); m12 = mat.m12(); m20 = mat.m20(); m21 = mat.m21(); m22 = mat.m22(); return this; } /** * Set the upper left 2x2 submatrix of this {@link Matrix3f} to the given {@link Matrix2fc} * and the rest to identity. * * @see #Matrix3f(Matrix2fc) * * @param mat * the {@link Matrix2fc} * @return this */ public Matrix3f set(Matrix2fc mat) { m00 = mat.m00(); m01 = mat.m01(); m02 = 0.0f; m10 = mat.m10(); m11 = mat.m11(); m12 = 0.0f; m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; return this; } /** * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4f}. * * @param axisAngle * the {@link AxisAngle4f} * @return this */ public Matrix3f set(AxisAngle4f axisAngle) { float x = axisAngle.x; float y = axisAngle.y; float z = axisAngle.z; float angle = axisAngle.angle; float invLength = Math.invsqrt(x*x + y*y + z*z); x *= invLength; y *= invLength; z *= invLength; float s = Math.sin(angle); float c = Math.cosFromSin(s, angle); float omc = 1.0f - c; m00 = c + x*x*omc; m11 = c + y*y*omc; m22 = c + z*z*omc; float tmp1 = x*y*omc; float tmp2 = z*s; m10 = tmp1 - tmp2; m01 = tmp1 + tmp2; tmp1 = x*z*omc; tmp2 = y*s; m20 = tmp1 + tmp2; m02 = tmp1 - tmp2; tmp1 = y*z*omc; tmp2 = x*s; m21 = tmp1 - tmp2; m12 = tmp1 + tmp2; return this; } /** * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}. * * @param axisAngle * the {@link AxisAngle4d} * @return this */ public Matrix3f set(AxisAngle4d axisAngle) { double x = axisAngle.x; double y = axisAngle.y; double z = axisAngle.z; double angle = axisAngle.angle; double invLength = Math.invsqrt(x*x + y*y + z*z); x *= invLength; y *= invLength; z *= invLength; double s = Math.sin(angle); double c = Math.cosFromSin(s, angle); double omc = 1.0f - c; m00 = (float)(c + x*x*omc); m11 = (float)(c + y*y*omc); m22 = (float)(c + z*z*omc); double tmp1 = x*y*omc; double tmp2 = z*s; m10 = (float)(tmp1 - tmp2); m01 = (float)(tmp1 + tmp2); tmp1 = x*z*omc; tmp2 = y*s; m20 = (float)(tmp1 + tmp2); m02 = (float)(tmp1 - tmp2); tmp1 = y*z*omc; tmp2 = x*s; m21 = (float)(tmp1 - tmp2); m12 = (float)(tmp1 + tmp2); return this; } /** * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaternionfc}. *

* This method is equivalent to calling: rotation(q) *

* Reference: http://www.euclideanspace.com/ * * @see #rotation(Quaternionfc) * * @param q * the {@link Quaternionfc} * @return this */ public Matrix3f set(Quaternionfc q) { return rotation(q); } /** * Set this matrix to a rotation - and possibly scaling - equivalent to the given quaternion. *

* Reference: http://www.euclideanspace.com/ * * @param q * the quaternion * @return this */ public Matrix3f set(Quaterniondc q) { double w2 = q.w() * q.w(); double x2 = q.x() * q.x(); double y2 = q.y() * q.y(); double z2 = q.z() * q.z(); double zw = q.z() * q.w(); double xy = q.x() * q.y(); double xz = q.x() * q.z(); double yw = q.y() * q.w(); double yz = q.y() * q.z(); double xw = q.x() * q.w(); m00 = (float) (w2 + x2 - z2 - y2); m01 = (float) (xy + zw + zw + xy); m02 = (float) (xz - yw + xz - yw); m10 = (float) (-zw + xy - zw + xy); m11 = (float) (y2 - z2 + w2 - x2); m12 = (float) (yz + yz + xw + xw); m20 = (float) (yw + xz + xz + yw); m21 = (float) (yz + yz - xw - xw); m22 = (float) (z2 - y2 - x2 + w2); return this; } /** * Multiply this matrix by the supplied right matrix. *

* If M is this matrix and R the right matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * transformation of the right matrix will be applied first! * * @param right * the right operand of the matrix multiplication * @return this */ public Matrix3f mul(Matrix3fc right) { return mul(right, this); } public Matrix3f mul(Matrix3fc right, Matrix3f dest) { float nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02())); float nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02())); float nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02())); float nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12())); float nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12())); float nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12())); float nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22())); float nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22())); float nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22())); dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Pre-multiply this matrix by the supplied left matrix and store the result in this. *

* If M is this matrix and L the left matrix, * then the new matrix will be L * M. So when transforming a * vector v with the new matrix by using L * M * v, the * transformation of this matrix will be applied first! * * @param left * the left operand of the matrix multiplication * @return this */ public Matrix3f mulLocal(Matrix3fc left) { return mulLocal(left, this); } public Matrix3f mulLocal(Matrix3fc left, Matrix3f dest) { float nm00 = left.m00() * m00 + left.m10() * m01 + left.m20() * m02; float nm01 = left.m01() * m00 + left.m11() * m01 + left.m21() * m02; float nm02 = left.m02() * m00 + left.m12() * m01 + left.m22() * m02; float nm10 = left.m00() * m10 + left.m10() * m11 + left.m20() * m12; float nm11 = left.m01() * m10 + left.m11() * m11 + left.m21() * m12; float nm12 = left.m02() * m10 + left.m12() * m11 + left.m22() * m12; float nm20 = left.m00() * m20 + left.m10() * m21 + left.m20() * m22; float nm21 = left.m01() * m20 + left.m11() * m21 + left.m21() * m22; float nm22 = left.m02() * m20 + left.m12() * m21 + left.m22() * m22; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Set the values within this matrix to the supplied float values. The result looks like this: *

* m00, m10, m20
* m01, m11, m21
* m02, m12, m22
* * @param m00 * the new value of m00 * @param m01 * the new value of m01 * @param m02 * the new value of m02 * @param m10 * the new value of m10 * @param m11 * the new value of m11 * @param m12 * the new value of m12 * @param m20 * the new value of m20 * @param m21 * the new value of m21 * @param m22 * the new value of m22 * @return this */ public Matrix3f set(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m20 = m20; this.m21 = m21; this.m22 = m22; return this; } /** * Set the values in this matrix based on the supplied float array. The result looks like this: *

* 0, 3, 6
* 1, 4, 7
* 2, 5, 8
* * This method only uses the first 9 values, all others are ignored. * * @param m * the array to read the matrix values from * @return this */ public Matrix3f set(float m[]) { MemUtil.INSTANCE.copy(m, 0, this); return this; } /** * Set the three columns of this matrix to the supplied vectors, respectively. * * @param col0 * the first column * @param col1 * the second column * @param col2 * the third column * @return this */ public Matrix3f set(Vector3fc col0, Vector3fc col1, Vector3fc col2) { this.m00 = col0.x(); this.m01 = col0.y(); this.m02 = col0.z(); this.m10 = col1.x(); this.m11 = col1.y(); this.m12 = col1.z(); this.m20 = col2.x(); this.m21 = col2.y(); this.m22 = col2.z(); return this; } public float determinant() { return (m00 * m11 - m01 * m10) * m22 + (m02 * m10 - m00 * m12) * m21 + (m01 * m12 - m02 * m11) * m20; } /** * Invert this matrix. * * @return this */ public Matrix3f invert() { return invert(this); } public Matrix3f invert(Matrix3f dest) { float a = Math.fma(m00, m11, -m01 * m10); float b = Math.fma(m02, m10, -m00 * m12); float c = Math.fma(m01, m12, -m02 * m11); float d = Math.fma(a, m22, Math.fma(b, m21, c * m20)); float s = 1.0f / d; float nm00 = Math.fma(m11, m22, -m21 * m12) * s; float nm01 = Math.fma(m21, m02, -m01 * m22) * s; float nm02 = c * s; float nm10 = Math.fma(m20, m12, -m10 * m22) * s; float nm11 = Math.fma(m00, m22, -m20 * m02) * s; float nm12 = b * s; float nm20 = Math.fma(m10, m21, -m20 * m11) * s; float nm21 = Math.fma(m20, m01, -m00 * m21) * s; float nm22 = a * s; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Transpose this matrix. * * @return this */ public Matrix3f transpose() { return transpose(this); } public Matrix3f transpose(Matrix3f dest) { return dest.set(m00, m10, m20, m01, m11, m21, m02, m12, m22); } /** * Return a string representation of this matrix. *

* This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-". * * @return the string representation */ public String toString() { DecimalFormat formatter = new DecimalFormat(" 0.000E0;-"); String str = toString(formatter); StringBuffer res = new StringBuffer(); int eIndex = Integer.MIN_VALUE; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c == 'E') { eIndex = i; } else if (c == ' ' && eIndex == i - 1) { // workaround Java 1.4 DecimalFormat bug res.append('+'); continue; } else if (Character.isDigit(c) && eIndex == i - 1) { res.append('+'); } res.append(c); } return res.toString(); } /** * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}. * * @param formatter * the {@link NumberFormat} used to format the matrix values with * @return the string representation */ public String toString(NumberFormat formatter) { return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + "\n" + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + "\n" + Runtime.format(m02, formatter) + " " + Runtime.format(m12, formatter) + " " + Runtime.format(m22, formatter) + "\n"; } /** * Get the current values of this matrix and store them into * dest. *

* This is the reverse method of {@link #set(Matrix3fc)} and allows to obtain * intermediate calculation results when chaining multiple transformations. * * @see #set(Matrix3fc) * * @param dest * the destination matrix * @return the passed in destination */ public Matrix3f get(Matrix3f dest) { return dest.set(this); } public Matrix4f get(Matrix4f dest) { return dest.set(this); } public AxisAngle4f getRotation(AxisAngle4f dest) { return dest.set(this); } public Quaternionf getUnnormalizedRotation(Quaternionf dest) { return dest.setFromUnnormalized(this); } public Quaternionf getNormalizedRotation(Quaternionf dest) { return dest.setFromNormalized(this); } public Quaterniond getUnnormalizedRotation(Quaterniond dest) { return dest.setFromUnnormalized(this); } public Quaterniond getNormalizedRotation(Quaterniond dest) { return dest.setFromNormalized(this); } public FloatBuffer get(FloatBuffer buffer) { return get(buffer.position(), buffer); } public FloatBuffer get(int index, FloatBuffer buffer) { MemUtil.INSTANCE.put(this, index, buffer); return buffer; } public ByteBuffer get(ByteBuffer buffer) { return get(buffer.position(), buffer); } public ByteBuffer get(int index, ByteBuffer buffer) { MemUtil.INSTANCE.put(this, index, buffer); return buffer; } public FloatBuffer get3x4(FloatBuffer buffer) { return get3x4(buffer.position(), buffer); } public FloatBuffer get3x4(int index, FloatBuffer buffer) { MemUtil.INSTANCE.put3x4(this, index, buffer); return buffer; } public ByteBuffer get3x4(ByteBuffer buffer) { return get3x4(buffer.position(), buffer); } public ByteBuffer get3x4(int index, ByteBuffer buffer) { MemUtil.INSTANCE.put3x4(this, index, buffer); return buffer; } public FloatBuffer getTransposed(FloatBuffer buffer) { return getTransposed(buffer.position(), buffer); } public FloatBuffer getTransposed(int index, FloatBuffer buffer) { MemUtil.INSTANCE.putTransposed(this, index, buffer); return buffer; } public ByteBuffer getTransposed(ByteBuffer buffer) { return getTransposed(buffer.position(), buffer); } public ByteBuffer getTransposed(int index, ByteBuffer buffer) { MemUtil.INSTANCE.putTransposed(this, index, buffer); return buffer; } public Matrix3fc getToAddress(long address) { if (Options.NO_UNSAFE) throw new UnsupportedOperationException("Not supported when using joml.nounsafe"); MemUtil.MemUtilUnsafe.put(this, address); return this; } public float[] get(float[] arr, int offset) { MemUtil.INSTANCE.copy(this, arr, offset); return arr; } public float[] get(float[] arr) { return get(arr, 0); } /** * Set the values of this matrix by reading 9 float values from the given {@link FloatBuffer} in column-major order, * starting at its current position. *

* The FloatBuffer is expected to contain the values in column-major order. *

* The position of the FloatBuffer will not be changed by this method. * * @param buffer * the FloatBuffer to read the matrix values from in column-major order * @return this */ public Matrix3f set(FloatBuffer buffer) { MemUtil.INSTANCE.get(this, buffer.position(), buffer); return this; } /** * Set the values of this matrix by reading 9 float values from the given {@link ByteBuffer} in column-major order, * starting at its current position. *

* The ByteBuffer is expected to contain the values in column-major order. *

* The position of the ByteBuffer will not be changed by this method. * * @param buffer * the ByteBuffer to read the matrix values from in column-major order * @return this */ public Matrix3f set(ByteBuffer buffer) { MemUtil.INSTANCE.get(this, buffer.position(), buffer); return this; } /** * Set the values of this matrix by reading 9 float values from off-heap memory in column-major order, * starting at the given address. *

* This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`. *

* This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process. * * @param address * the off-heap memory address to read the matrix values from in column-major order * @return this */ public Matrix3f setFromAddress(long address) { if (Options.NO_UNSAFE) throw new UnsupportedOperationException("Not supported when using joml.nounsafe"); MemUtil.MemUtilUnsafe.get(this, address); return this; } /** * Set all values within this matrix to zero. * * @return this */ public Matrix3f zero() { MemUtil.INSTANCE.zero(this); return this; } /** * Set this matrix to the identity. * * @return this */ public Matrix3f identity() { MemUtil.INSTANCE.identity(this); return this; } public Matrix3f scale(Vector3fc xyz, Matrix3f dest) { return scale(xyz.x(), xyz.y(), xyz.z(), dest); } /** * Apply scaling to this matrix by scaling the base axes by the given xyz.x, * xyz.y and xyz.z factors, respectively. *

* If M is this matrix and S the scaling matrix, * then the new matrix will be M * S. So when transforming a * vector v with the new matrix by using M * S * v, the * scaling will be applied first! * * @param xyz * the factors of the x, y and z component, respectively * @return this */ public Matrix3f scale(Vector3fc xyz) { return scale(xyz.x(), xyz.y(), xyz.z(), this); } public Matrix3f scale(float x, float y, float z, Matrix3f dest) { // scale matrix elements: // m00 = x, m11 = y, m22 = z // all others = 0 dest.m00 = m00 * x; dest.m01 = m01 * x; dest.m02 = m02 * x; dest.m10 = m10 * y; dest.m11 = m11 * y; dest.m12 = m12 * y; dest.m20 = m20 * z; dest.m21 = m21 * z; dest.m22 = m22 * z; return dest; } /** * Apply scaling to this matrix by scaling the base axes by the given x, * y and z factors. *

* If M is this matrix and S the scaling matrix, * then the new matrix will be M * S. So when transforming a * vector v with the new matrix by using M * S * v * , the scaling will be applied first! * * @param x * the factor of the x component * @param y * the factor of the y component * @param z * the factor of the z component * @return this */ public Matrix3f scale(float x, float y, float z) { return scale(x, y, z, this); } public Matrix3f scale(float xyz, Matrix3f dest) { return scale(xyz, xyz, xyz, dest); } /** * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor. *

* If M is this matrix and S the scaling matrix, * then the new matrix will be M * S. So when transforming a * vector v with the new matrix by using M * S * v * , the scaling will be applied first! * * @see #scale(float, float, float) * * @param xyz * the factor for all components * @return this */ public Matrix3f scale(float xyz) { return scale(xyz, xyz, xyz); } public Matrix3f scaleLocal(float x, float y, float z, Matrix3f dest) { float nm00 = x * m00; float nm01 = y * m01; float nm02 = z * m02; float nm10 = x * m10; float nm11 = y * m11; float nm12 = z * m12; float nm20 = x * m20; float nm21 = y * m21; float nm22 = z * m22; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Pre-multiply scaling to this matrix by scaling the base axes by the given x, * y and z factors. *

* If M is this matrix and S the scaling matrix, * then the new matrix will be S * M. So when transforming a * vector v with the new matrix by using S * M * v, the * scaling will be applied last! * * @param x * the factor of the x component * @param y * the factor of the y component * @param z * the factor of the z component * @return this */ public Matrix3f scaleLocal(float x, float y, float z) { return scaleLocal(x, y, z, this); } /** * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor. *

* The resulting matrix can be multiplied against another transformation * matrix to obtain an additional scaling. *

* In order to post-multiply a scaling transformation directly to a * matrix, use {@link #scale(float) scale()} instead. * * @see #scale(float) * * @param factor * the scale factor in x, y and z * @return this */ public Matrix3f scaling(float factor) { MemUtil.INSTANCE.zero(this); m00 = factor; m11 = factor; m22 = factor; return this; } /** * Set this matrix to be a simple scale matrix. * * @param x * the scale in x * @param y * the scale in y * @param z * the scale in z * @return this */ public Matrix3f scaling(float x, float y, float z) { MemUtil.INSTANCE.zero(this); m00 = x; m11 = y; m22 = z; return this; } /** * Set this matrix to be a simple scale matrix which scales the base axes by xyz.x, xyz.y and xyz.z respectively. *

* The resulting matrix can be multiplied against another transformation * matrix to obtain an additional scaling. *

* In order to post-multiply a scaling transformation directly to a * matrix use {@link #scale(Vector3fc) scale()} instead. * * @see #scale(Vector3fc) * * @param xyz * the scale in x, y and z respectively * @return this */ public Matrix3f scaling(Vector3fc xyz) { return scaling(xyz.x(), xyz.y(), xyz.z()); } /** * Set this matrix to a rotation matrix which rotates the given radians about a given axis. *

* The axis described by the axis vector needs to be a unit vector. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* The resulting matrix can be multiplied against another transformation * matrix to obtain an additional rotation. *

* In order to post-multiply a rotation transformation directly to a * matrix, use {@link #rotate(float, Vector3fc) rotate()} instead. * * @see #rotate(float, Vector3fc) * * @param angle * the angle in radians * @param axis * the axis to rotate about (needs to be {@link Vector3f#normalize() normalized}) * @return this */ public Matrix3f rotation(float angle, Vector3fc axis) { return rotation(angle, axis.x(), axis.y(), axis.z()); } /** * Set this matrix to a rotation transformation using the given {@link AxisAngle4f}. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* The resulting matrix can be multiplied against another transformation * matrix to obtain an additional rotation. *

* In order to apply the rotation transformation to an existing transformation, * use {@link #rotate(AxisAngle4f) rotate()} instead. *

* Reference: http://en.wikipedia.org * * @see #rotate(AxisAngle4f) * * @param axisAngle * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized}) * @return this */ public Matrix3f rotation(AxisAngle4f axisAngle) { return rotation(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z); } /** * Set this matrix to a rotation matrix which rotates the given radians about a given axis. *

* The axis described by the three components needs to be a unit vector. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* The resulting matrix can be multiplied against another transformation * matrix to obtain an additional rotation. *

* In order to apply the rotation transformation to an existing transformation, * use {@link #rotate(float, float, float, float) rotate()} instead. *

* Reference: http://en.wikipedia.org * * @see #rotate(float, float, float, float) * * @param angle * the angle in radians * @param x * the x-component of the rotation axis * @param y * the y-component of the rotation axis * @param z * the z-component of the rotation axis * @return this */ public Matrix3f rotation(float angle, float x, float y, float z) { float sin = Math.sin(angle); float cos = Math.cosFromSin(sin, angle); float C = 1.0f - cos; float xy = x * y, xz = x * z, yz = y * z; m00 = cos + x * x * C; m10 = xy * C - z * sin; m20 = xz * C + y * sin; m01 = xy * C + z * sin; m11 = cos + y * y * C; m21 = yz * C - x * sin; m02 = xz * C - y * sin; m12 = yz * C + x * sin; m22 = cos + z * z * C; return this; } /** * Set this matrix to a rotation transformation about the X axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* Reference: http://en.wikipedia.org * * @param ang * the angle in radians * @return this */ public Matrix3f rotationX(float ang) { float sin, cos; sin = Math.sin(ang); cos = Math.cosFromSin(sin, ang); m00 = 1.0f; m01 = 0.0f; m02 = 0.0f; m10 = 0.0f; m11 = cos; m12 = sin; m20 = 0.0f; m21 = -sin; m22 = cos; return this; } /** * Set this matrix to a rotation transformation about the Y axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* Reference: http://en.wikipedia.org * * @param ang * the angle in radians * @return this */ public Matrix3f rotationY(float ang) { float sin, cos; sin = Math.sin(ang); cos = Math.cosFromSin(sin, ang); m00 = cos; m01 = 0.0f; m02 = -sin; m10 = 0.0f; m11 = 1.0f; m12 = 0.0f; m20 = sin; m21 = 0.0f; m22 = cos; return this; } /** * Set this matrix to a rotation transformation about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* Reference: http://en.wikipedia.org * * @param ang * the angle in radians * @return this */ public Matrix3f rotationZ(float ang) { float sin, cos; sin = Math.sin(ang); cos = Math.cosFromSin(sin, ang); m00 = cos; m01 = sin; m02 = 0.0f; m10 = -sin; m11 = cos; m12 = 0.0f; m20 = 0.0f; m21 = 0.0f; m22 = 1.0f; return this; } /** * Set this matrix to a rotation of angleX radians about the X axis, followed by a rotation * of angleY radians about the Y axis and followed by a rotation of angleZ radians about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ) * * @param angleX * the angle to rotate about X * @param angleY * the angle to rotate about Y * @param angleZ * the angle to rotate about Z * @return this */ public Matrix3f rotationXYZ(float angleX, float angleY, float angleZ) { float sinX = Math.sin(angleX); float cosX = Math.cosFromSin(sinX, angleX); float sinY = Math.sin(angleY); float cosY = Math.cosFromSin(sinY, angleY); float sinZ = Math.sin(angleZ); float cosZ = Math.cosFromSin(sinZ, angleZ); float m_sinX = -sinX; float m_sinY = -sinY; float m_sinZ = -sinZ; // rotateX float nm11 = cosX; float nm12 = sinX; float nm21 = m_sinX; float nm22 = cosX; // rotateY float nm00 = cosY; float nm01 = nm21 * m_sinY; float nm02 = nm22 * m_sinY; m20 = sinY; m21 = nm21 * cosY; m22 = nm22 * cosY; // rotateZ m00 = nm00 * cosZ; m01 = nm01 * cosZ + nm11 * sinZ; m02 = nm02 * cosZ + nm12 * sinZ; m10 = nm00 * m_sinZ; m11 = nm01 * m_sinZ + nm11 * cosZ; m12 = nm02 * m_sinZ + nm12 * cosZ; return this; } /** * Set this matrix to a rotation of angleZ radians about the Z axis, followed by a rotation * of angleY radians about the Y axis and followed by a rotation of angleX radians about the X axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX) * * @param angleZ * the angle to rotate about Z * @param angleY * the angle to rotate about Y * @param angleX * the angle to rotate about X * @return this */ public Matrix3f rotationZYX(float angleZ, float angleY, float angleX) { float sinX = Math.sin(angleX); float cosX = Math.cosFromSin(sinX, angleX); float sinY = Math.sin(angleY); float cosY = Math.cosFromSin(sinY, angleY); float sinZ = Math.sin(angleZ); float cosZ = Math.cosFromSin(sinZ, angleZ); float m_sinZ = -sinZ; float m_sinY = -sinY; float m_sinX = -sinX; // rotateZ float nm00 = cosZ; float nm01 = sinZ; float nm10 = m_sinZ; float nm11 = cosZ; // rotateY float nm20 = nm00 * sinY; float nm21 = nm01 * sinY; float nm22 = cosY; m00 = nm00 * cosY; m01 = nm01 * cosY; m02 = m_sinY; // rotateX m10 = nm10 * cosX + nm20 * sinX; m11 = nm11 * cosX + nm21 * sinX; m12 = nm22 * sinX; m20 = nm10 * m_sinX + nm20 * cosX; m21 = nm11 * m_sinX + nm21 * cosX; m22 = nm22 * cosX; return this; } /** * Set this matrix to a rotation of angleY radians about the Y axis, followed by a rotation * of angleX radians about the X axis and followed by a rotation of angleZ radians about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ) * * @param angleY * the angle to rotate about Y * @param angleX * the angle to rotate about X * @param angleZ * the angle to rotate about Z * @return this */ public Matrix3f rotationYXZ(float angleY, float angleX, float angleZ) { float sinX = Math.sin(angleX); float cosX = Math.cosFromSin(sinX, angleX); float sinY = Math.sin(angleY); float cosY = Math.cosFromSin(sinY, angleY); float sinZ = Math.sin(angleZ); float cosZ = Math.cosFromSin(sinZ, angleZ); float m_sinY = -sinY; float m_sinX = -sinX; float m_sinZ = -sinZ; // rotateY float nm00 = cosY; float nm02 = m_sinY; float nm20 = sinY; float nm22 = cosY; // rotateX float nm10 = nm20 * sinX; float nm11 = cosX; float nm12 = nm22 * sinX; m20 = nm20 * cosX; m21 = m_sinX; m22 = nm22 * cosX; // rotateZ m00 = nm00 * cosZ + nm10 * sinZ; m01 = nm11 * sinZ; m02 = nm02 * cosZ + nm12 * sinZ; m10 = nm00 * m_sinZ + nm10 * cosZ; m11 = nm11 * cosZ; m12 = nm02 * m_sinZ + nm12 * cosZ; return this; } /** * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaternionfc}. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* The resulting matrix can be multiplied against another transformation * matrix to obtain an additional rotation. *

* In order to apply the rotation transformation to an existing transformation, * use {@link #rotate(Quaternionfc) rotate()} instead. *

* Reference: http://en.wikipedia.org * * @see #rotate(Quaternionfc) * * @param quat * the {@link Quaternionfc} * @return this */ public Matrix3f rotation(Quaternionfc quat) { float w2 = quat.w() * quat.w(); float x2 = quat.x() * quat.x(); float y2 = quat.y() * quat.y(); float z2 = quat.z() * quat.z(); float zw = quat.z() * quat.w(), dzw = zw + zw; float xy = quat.x() * quat.y(), dxy = xy + xy; float xz = quat.x() * quat.z(), dxz = xz + xz; float yw = quat.y() * quat.w(), dyw = yw + yw; float yz = quat.y() * quat.z(), dyz = yz + yz; float xw = quat.x() * quat.w(), dxw = xw + xw; m00 = w2 + x2 - z2 - y2; m01 = dxy + dzw; m02 = dxz - dyw; m10 = -dzw + dxy; m11 = y2 - z2 + w2 - x2; m12 = dyz + dxw; m20 = dyw + dxz; m21 = dyz - dxw; m22 = z2 - y2 - x2 + w2; return this; } public Vector3f transform(Vector3f v) { return v.mul(this); } public Vector3f transform(Vector3fc v, Vector3f dest) { return v.mul(this, dest); } public Vector3f transform(float x, float y, float z, Vector3f dest) { return dest.set(Math.fma(m00, x, Math.fma(m10, y, m20 * z)), Math.fma(m01, x, Math.fma(m11, y, m21 * z)), Math.fma(m02, x, Math.fma(m12, y, m22 * z))); } public Vector3f transformTranspose(Vector3f v) { return v.mulTranspose(this); } public Vector3f transformTranspose(Vector3fc v, Vector3f dest) { return v.mulTranspose(this, dest); } public Vector3f transformTranspose(float x, float y, float z, Vector3f dest) { return dest.set(Math.fma(m00, x, Math.fma(m01, y, m02 * z)), Math.fma(m10, x, Math.fma(m11, y, m12 * z)), Math.fma(m20, x, Math.fma(m21, y, m22 * z))); } public void writeExternal(ObjectOutput out) throws IOException { out.writeFloat(m00); out.writeFloat(m01); out.writeFloat(m02); out.writeFloat(m10); out.writeFloat(m11); out.writeFloat(m12); out.writeFloat(m20); out.writeFloat(m21); out.writeFloat(m22); } public void readExternal(ObjectInput in) throws IOException { m00 = in.readFloat(); m01 = in.readFloat(); m02 = in.readFloat(); m10 = in.readFloat(); m11 = in.readFloat(); m12 = in.readFloat(); m20 = in.readFloat(); m21 = in.readFloat(); m22 = in.readFloat(); } public Matrix3f rotateX(float ang, Matrix3f dest) { float sin, cos; sin = Math.sin(ang); cos = Math.cosFromSin(sin, ang); float rm11 = cos; float rm21 = -sin; float rm12 = sin; float rm22 = cos; // add temporaries for dependent values float nm10 = m10 * rm11 + m20 * rm12; float nm11 = m11 * rm11 + m21 * rm12; float nm12 = m12 * rm11 + m22 * rm12; // set non-dependent values directly dest.m20 = m10 * rm21 + m20 * rm22; dest.m21 = m11 * rm21 + m21 * rm22; dest.m22 = m12 * rm21 + m22 * rm22; // set other values dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m00 = m00; dest.m01 = m01; dest.m02 = m02; return dest; } /** * Apply rotation about the X axis to this matrix by rotating the given amount of radians. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v * , the rotation will be applied first! *

* Reference: http://en.wikipedia.org * * @param ang * the angle in radians * @return this */ public Matrix3f rotateX(float ang) { return rotateX(ang, this); } public Matrix3f rotateY(float ang, Matrix3f dest) { float sin, cos; sin = Math.sin(ang); cos = Math.cosFromSin(sin, ang); float rm00 = cos; float rm20 = sin; float rm02 = -sin; float rm22 = cos; // add temporaries for dependent values float nm00 = m00 * rm00 + m20 * rm02; float nm01 = m01 * rm00 + m21 * rm02; float nm02 = m02 * rm00 + m22 * rm02; // set non-dependent values directly dest.m20 = m00 * rm20 + m20 * rm22; dest.m21 = m01 * rm20 + m21 * rm22; dest.m22 = m02 * rm20 + m22 * rm22; // set other values dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = m10; dest.m11 = m11; dest.m12 = m12; return dest; } /** * Apply rotation about the Y axis to this matrix by rotating the given amount of radians. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v * , the rotation will be applied first! *

* Reference: http://en.wikipedia.org * * @param ang * the angle in radians * @return this */ public Matrix3f rotateY(float ang) { return rotateY(ang, this); } public Matrix3f rotateZ(float ang, Matrix3f dest) { float sin, cos; sin = Math.sin(ang); cos = Math.cosFromSin(sin, ang); float rm00 = cos; float rm10 = -sin; float rm01 = sin; float rm11 = cos; // add temporaries for dependent values float nm00 = m00 * rm00 + m10 * rm01; float nm01 = m01 * rm00 + m11 * rm01; float nm02 = m02 * rm00 + m12 * rm01; // set non-dependent values directly dest.m10 = m00 * rm10 + m10 * rm11; dest.m11 = m01 * rm10 + m11 * rm11; dest.m12 = m02 * rm10 + m12 * rm11; // set other values dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m20 = m20; dest.m21 = m21; dest.m22 = m22; return dest; } /** * Apply rotation about the Z axis to this matrix by rotating the given amount of radians. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v * , the rotation will be applied first! *

* Reference: http://en.wikipedia.org * * @param ang * the angle in radians * @return this */ public Matrix3f rotateZ(float ang) { return rotateZ(ang, this); } /** * Apply rotation of angles.x radians about the X axis, followed by a rotation of angles.y radians about the Y axis and * followed by a rotation of angles.z radians about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * rotation will be applied first! *

* This method is equivalent to calling: rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z) * * @param angles * the Euler angles * @return this */ public Matrix3f rotateXYZ(Vector3f angles) { return rotateXYZ(angles.x, angles.y, angles.z); } /** * Apply rotation of angleX radians about the X axis, followed by a rotation of angleY radians about the Y axis and * followed by a rotation of angleZ radians about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * rotation will be applied first! *

* This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ) * * @param angleX * the angle to rotate about X * @param angleY * the angle to rotate about Y * @param angleZ * the angle to rotate about Z * @return this */ public Matrix3f rotateXYZ(float angleX, float angleY, float angleZ) { return rotateXYZ(angleX, angleY, angleZ, this); } public Matrix3f rotateXYZ(float angleX, float angleY, float angleZ, Matrix3f dest) { float sinX = Math.sin(angleX); float cosX = Math.cosFromSin(sinX, angleX); float sinY = Math.sin(angleY); float cosY = Math.cosFromSin(sinY, angleY); float sinZ = Math.sin(angleZ); float cosZ = Math.cosFromSin(sinZ, angleZ); float m_sinX = -sinX; float m_sinY = -sinY; float m_sinZ = -sinZ; // rotateX float nm10 = m10 * cosX + m20 * sinX; float nm11 = m11 * cosX + m21 * sinX; float nm12 = m12 * cosX + m22 * sinX; float nm20 = m10 * m_sinX + m20 * cosX; float nm21 = m11 * m_sinX + m21 * cosX; float nm22 = m12 * m_sinX + m22 * cosX; // rotateY float nm00 = m00 * cosY + nm20 * m_sinY; float nm01 = m01 * cosY + nm21 * m_sinY; float nm02 = m02 * cosY + nm22 * m_sinY; dest.m20 = m00 * sinY + nm20 * cosY; dest.m21 = m01 * sinY + nm21 * cosY; dest.m22 = m02 * sinY + nm22 * cosY; // rotateZ dest.m00 = nm00 * cosZ + nm10 * sinZ; dest.m01 = nm01 * cosZ + nm11 * sinZ; dest.m02 = nm02 * cosZ + nm12 * sinZ; dest.m10 = nm00 * m_sinZ + nm10 * cosZ; dest.m11 = nm01 * m_sinZ + nm11 * cosZ; dest.m12 = nm02 * m_sinZ + nm12 * cosZ; return dest; } /** * Apply rotation of angles.z radians about the Z axis, followed by a rotation of angles.y radians about the Y axis and * followed by a rotation of angles.x radians about the X axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * rotation will be applied first! *

* This method is equivalent to calling: rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x) * * @param angles * the Euler angles * @return this */ public Matrix3f rotateZYX(Vector3f angles) { return rotateZYX(angles.z, angles.y, angles.x); } /** * Apply rotation of angleZ radians about the Z axis, followed by a rotation of angleY radians about the Y axis and * followed by a rotation of angleX radians about the X axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * rotation will be applied first! *

* This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX) * * @param angleZ * the angle to rotate about Z * @param angleY * the angle to rotate about Y * @param angleX * the angle to rotate about X * @return this */ public Matrix3f rotateZYX(float angleZ, float angleY, float angleX) { return rotateZYX(angleZ, angleY, angleX, this); } public Matrix3f rotateZYX(float angleZ, float angleY, float angleX, Matrix3f dest) { float sinX = Math.sin(angleX); float cosX = Math.cosFromSin(sinX, angleX); float sinY = Math.sin(angleY); float cosY = Math.cosFromSin(sinY, angleY); float sinZ = Math.sin(angleZ); float cosZ = Math.cosFromSin(sinZ, angleZ); float m_sinZ = -sinZ; float m_sinY = -sinY; float m_sinX = -sinX; // rotateZ float nm00 = m00 * cosZ + m10 * sinZ; float nm01 = m01 * cosZ + m11 * sinZ; float nm02 = m02 * cosZ + m12 * sinZ; float nm10 = m00 * m_sinZ + m10 * cosZ; float nm11 = m01 * m_sinZ + m11 * cosZ; float nm12 = m02 * m_sinZ + m12 * cosZ; // rotateY float nm20 = nm00 * sinY + m20 * cosY; float nm21 = nm01 * sinY + m21 * cosY; float nm22 = nm02 * sinY + m22 * cosY; dest.m00 = nm00 * cosY + m20 * m_sinY; dest.m01 = nm01 * cosY + m21 * m_sinY; dest.m02 = nm02 * cosY + m22 * m_sinY; // rotateX dest.m10 = nm10 * cosX + nm20 * sinX; dest.m11 = nm11 * cosX + nm21 * sinX; dest.m12 = nm12 * cosX + nm22 * sinX; dest.m20 = nm10 * m_sinX + nm20 * cosX; dest.m21 = nm11 * m_sinX + nm21 * cosX; dest.m22 = nm12 * m_sinX + nm22 * cosX; return dest; } /** * Apply rotation of angles.y radians about the Y axis, followed by a rotation of angles.x radians about the X axis and * followed by a rotation of angles.z radians about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * rotation will be applied first! *

* This method is equivalent to calling: rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z) * * @param angles * the Euler angles * @return this */ public Matrix3f rotateYXZ(Vector3f angles) { return rotateYXZ(angles.y, angles.x, angles.z); } /** * Apply rotation of angleY radians about the Y axis, followed by a rotation of angleX radians about the X axis and * followed by a rotation of angleZ radians about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * rotation will be applied first! *

* This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ) * * @param angleY * the angle to rotate about Y * @param angleX * the angle to rotate about X * @param angleZ * the angle to rotate about Z * @return this */ public Matrix3f rotateYXZ(float angleY, float angleX, float angleZ) { return rotateYXZ(angleY, angleX, angleZ, this); } public Matrix3f rotateYXZ(float angleY, float angleX, float angleZ, Matrix3f dest) { float sinX = Math.sin(angleX); float cosX = Math.cosFromSin(sinX, angleX); float sinY = Math.sin(angleY); float cosY = Math.cosFromSin(sinY, angleY); float sinZ = Math.sin(angleZ); float cosZ = Math.cosFromSin(sinZ, angleZ); float m_sinY = -sinY; float m_sinX = -sinX; float m_sinZ = -sinZ; // rotateY float nm20 = m00 * sinY + m20 * cosY; float nm21 = m01 * sinY + m21 * cosY; float nm22 = m02 * sinY + m22 * cosY; float nm00 = m00 * cosY + m20 * m_sinY; float nm01 = m01 * cosY + m21 * m_sinY; float nm02 = m02 * cosY + m22 * m_sinY; // rotateX float nm10 = m10 * cosX + nm20 * sinX; float nm11 = m11 * cosX + nm21 * sinX; float nm12 = m12 * cosX + nm22 * sinX; dest.m20 = m10 * m_sinX + nm20 * cosX; dest.m21 = m11 * m_sinX + nm21 * cosX; dest.m22 = m12 * m_sinX + nm22 * cosX; // rotateZ dest.m00 = nm00 * cosZ + nm10 * sinZ; dest.m01 = nm01 * cosZ + nm11 * sinZ; dest.m02 = nm02 * cosZ + nm12 * sinZ; dest.m10 = nm00 * m_sinZ + nm10 * cosZ; dest.m11 = nm01 * m_sinZ + nm11 * cosZ; dest.m12 = nm02 * m_sinZ + nm12 * cosZ; return dest; } /** * Apply rotation to this matrix by rotating the given amount of radians * about the given axis specified as x, y and z components. *

* The axis described by the three components needs to be a unit vector. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v * , the rotation will be applied first! *

* Reference: http://en.wikipedia.org * * @param ang * the angle in radians * @param x * the x component of the axis * @param y * the y component of the axis * @param z * the z component of the axis * @return this */ public Matrix3f rotate(float ang, float x, float y, float z) { return rotate(ang, x, y, z, this); } public Matrix3f rotate(float ang, float x, float y, float z, Matrix3f dest) { float s = Math.sin(ang); float c = Math.cosFromSin(s, ang); float C = 1.0f - c; // rotation matrix elements: // m30, m31, m32, m03, m13, m23 = 0 float xx = x * x, xy = x * y, xz = x * z; float yy = y * y, yz = y * z; float zz = z * z; float rm00 = xx * C + c; float rm01 = xy * C + z * s; float rm02 = xz * C - y * s; float rm10 = xy * C - z * s; float rm11 = yy * C + c; float rm12 = yz * C + x * s; float rm20 = xz * C + y * s; float rm21 = yz * C - x * s; float rm22 = zz * C + c; // add temporaries for dependent values float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; // set non-dependent values directly dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22; dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22; dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22; // set other values dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; return dest; } /** * Pre-multiply a rotation to this matrix by rotating the given amount of radians * about the specified (x, y, z) axis and store the result in dest. *

* The axis described by the three components needs to be a unit vector. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotation(float, float, float, float) rotation()}. *

* Reference: http://en.wikipedia.org * * @see #rotation(float, float, float, float) * * @param ang * the angle in radians * @param x * the x component of the axis * @param y * the y component of the axis * @param z * the z component of the axis * @param dest * will hold the result * @return dest */ public Matrix3f rotateLocal(float ang, float x, float y, float z, Matrix3f dest) { float s = Math.sin(ang); float c = Math.cosFromSin(s, ang); float C = 1.0f - c; float xx = x * x, xy = x * y, xz = x * z; float yy = y * y, yz = y * z; float zz = z * z; float lm00 = xx * C + c; float lm01 = xy * C + z * s; float lm02 = xz * C - y * s; float lm10 = xy * C - z * s; float lm11 = yy * C + c; float lm12 = yz * C + x * s; float lm20 = xz * C + y * s; float lm21 = yz * C - x * s; float lm22 = zz * C + c; float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Pre-multiply a rotation to this matrix by rotating the given amount of radians * about the specified (x, y, z) axis. *

* The axis described by the three components needs to be a unit vector. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotation(float, float, float, float) rotation()}. *

* Reference: http://en.wikipedia.org * * @see #rotation(float, float, float, float) * * @param ang * the angle in radians * @param x * the x component of the axis * @param y * the y component of the axis * @param z * the z component of the axis * @return this */ public Matrix3f rotateLocal(float ang, float x, float y, float z) { return rotateLocal(ang, x, y, z, this); } /** * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians * about the X axis and store the result in dest. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotationX(float) rotationX()}. *

* Reference: http://en.wikipedia.org * * @see #rotationX(float) * * @param ang * the angle in radians to rotate about the X axis * @param dest * will hold the result * @return dest */ public Matrix3f rotateLocalX(float ang, Matrix3f dest) { float sin = Math.sin(ang); float cos = Math.cosFromSin(sin, ang); float nm01 = cos * m01 - sin * m02; float nm02 = sin * m01 + cos * m02; float nm11 = cos * m11 - sin * m12; float nm12 = sin * m11 + cos * m12; float nm21 = cos * m21 - sin * m22; float nm22 = sin * m21 + cos * m22; dest.m00 = m00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = m10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = m20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotationX(float) rotationX()}. *

* Reference: http://en.wikipedia.org * * @see #rotationX(float) * * @param ang * the angle in radians to rotate about the X axis * @return this */ public Matrix3f rotateLocalX(float ang) { return rotateLocalX(ang, this); } /** * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians * about the Y axis and store the result in dest. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotationY(float) rotationY()}. *

* Reference: http://en.wikipedia.org * * @see #rotationY(float) * * @param ang * the angle in radians to rotate about the Y axis * @param dest * will hold the result * @return dest */ public Matrix3f rotateLocalY(float ang, Matrix3f dest) { float sin = Math.sin(ang); float cos = Math.cosFromSin(sin, ang); float nm00 = cos * m00 + sin * m02; float nm02 = -sin * m00 + cos * m02; float nm10 = cos * m10 + sin * m12; float nm12 = -sin * m10 + cos * m12; float nm20 = cos * m20 + sin * m22; float nm22 = -sin * m20 + cos * m22; dest.m00 = nm00; dest.m01 = m01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = m11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = m21; dest.m22 = nm22; return dest; } /** * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotationY(float) rotationY()}. *

* Reference: http://en.wikipedia.org * * @see #rotationY(float) * * @param ang * the angle in radians to rotate about the Y axis * @return this */ public Matrix3f rotateLocalY(float ang) { return rotateLocalY(ang, this); } /** * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians * about the Z axis and store the result in dest. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotationZ(float) rotationZ()}. *

* Reference: http://en.wikipedia.org * * @see #rotationZ(float) * * @param ang * the angle in radians to rotate about the Z axis * @param dest * will hold the result * @return dest */ public Matrix3f rotateLocalZ(float ang, Matrix3f dest) { float sin = Math.sin(ang); float cos = Math.cosFromSin(sin, ang); float nm00 = cos * m00 - sin * m01; float nm01 = sin * m00 + cos * m01; float nm10 = cos * m10 - sin * m11; float nm11 = sin * m10 + cos * m11; float nm20 = cos * m20 - sin * m21; float nm21 = sin * m20 + cos * m21; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = m02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = m12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = m22; return dest; } /** * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and R the rotation matrix, * then the new matrix will be R * M. So when transforming a * vector v with the new matrix by using R * M * v, the * rotation will be applied last! *

* In order to set the matrix to a rotation matrix without pre-multiplying the rotation * transformation, use {@link #rotationZ(float) rotationY()}. *

* Reference: http://en.wikipedia.org * * @see #rotationY(float) * * @param ang * the angle in radians to rotate about the Z axis * @return this */ public Matrix3f rotateLocalZ(float ang) { return rotateLocalZ(ang, this); } /** * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and Q the rotation matrix obtained from the given quaternion, * then the new matrix will be M * Q. So when transforming a * vector v with the new matrix by using M * Q * v, * the quaternion rotation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying, * use {@link #rotation(Quaternionfc)}. *

* Reference: http://en.wikipedia.org * * @see #rotation(Quaternionfc) * * @param quat * the {@link Quaternionfc} * @return this */ public Matrix3f rotate(Quaternionfc quat) { return rotate(quat, this); } /** * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store * the result in dest. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and Q the rotation matrix obtained from the given quaternion, * then the new matrix will be M * Q. So when transforming a * vector v with the new matrix by using M * Q * v, * the quaternion rotation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying, * use {@link #rotation(Quaternionfc)}. *

* Reference: http://en.wikipedia.org * * @see #rotation(Quaternionfc) * * @param quat * the {@link Quaternionfc} * @param dest * will hold the result * @return dest */ public Matrix3f rotate(Quaternionfc quat, Matrix3f dest) { float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x(); float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z(); float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy; float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw; float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw; float rm00 = w2 + x2 - z2 - y2; float rm01 = dxy + dzw; float rm02 = dxz - dyw; float rm10 = dxy - dzw; float rm11 = y2 - z2 + w2 - x2; float rm12 = dyz + dxw; float rm20 = dyw + dxz; float rm21 = dyz - dxw; float rm22 = z2 - y2 - x2 + w2; float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22; dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22; dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; return dest; } /** * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store * the result in dest. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and Q the rotation matrix obtained from the given quaternion, * then the new matrix will be Q * M. So when transforming a * vector v with the new matrix by using Q * M * v, * the quaternion rotation will be applied last! *

* In order to set the matrix to a rotation transformation without pre-multiplying, * use {@link #rotation(Quaternionfc)}. *

* Reference: http://en.wikipedia.org * * @see #rotation(Quaternionfc) * * @param quat * the {@link Quaternionfc} * @param dest * will hold the result * @return dest */ public Matrix3f rotateLocal(Quaternionfc quat, Matrix3f dest) { float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x(); float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z(); float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy; float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw; float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw; float lm00 = w2 + x2 - z2 - y2; float lm01 = dxy + dzw; float lm02 = dxz - dyw; float lm10 = dxy - dzw; float lm11 = y2 - z2 + w2 - x2; float lm12 = dyz + dxw; float lm20 = dyw + dxz; float lm21 = dyz - dxw; float lm22 = z2 - y2 - x2 + w2; float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02; float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02; float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02; float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12; float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12; float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12; float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22; float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22; float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and Q the rotation matrix obtained from the given quaternion, * then the new matrix will be Q * M. So when transforming a * vector v with the new matrix by using Q * M * v, * the quaternion rotation will be applied last! *

* In order to set the matrix to a rotation transformation without pre-multiplying, * use {@link #rotation(Quaternionfc)}. *

* Reference: http://en.wikipedia.org * * @see #rotation(Quaternionfc) * * @param quat * the {@link Quaternionfc} * @return this */ public Matrix3f rotateLocal(Quaternionfc quat) { return rotateLocal(quat, this); } /** * Apply a rotation transformation, rotating about the given {@link AxisAngle4f}, to this matrix. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and A the rotation matrix obtained from the given {@link AxisAngle4f}, * then the new matrix will be M * A. So when transforming a * vector v with the new matrix by using M * A * v, * the {@link AxisAngle4f} rotation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying, * use {@link #rotation(AxisAngle4f)}. *

* Reference: http://en.wikipedia.org * * @see #rotate(float, float, float, float) * @see #rotation(AxisAngle4f) * * @param axisAngle * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized}) * @return this */ public Matrix3f rotate(AxisAngle4f axisAngle) { return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z); } /** * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and A the rotation matrix obtained from the given {@link AxisAngle4f}, * then the new matrix will be M * A. So when transforming a * vector v with the new matrix by using M * A * v, * the {@link AxisAngle4f} rotation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying, * use {@link #rotation(AxisAngle4f)}. *

* Reference: http://en.wikipedia.org * * @see #rotate(float, float, float, float) * @see #rotation(AxisAngle4f) * * @param axisAngle * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized}) * @param dest * will hold the result * @return dest */ public Matrix3f rotate(AxisAngle4f axisAngle, Matrix3f dest) { return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest); } /** * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and A the rotation matrix obtained from the given angle and axis, * then the new matrix will be M * A. So when transforming a * vector v with the new matrix by using M * A * v, * the axis-angle rotation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying, * use {@link #rotation(float, Vector3fc)}. *

* Reference: http://en.wikipedia.org * * @see #rotate(float, float, float, float) * @see #rotation(float, Vector3fc) * * @param angle * the angle in radians * @param axis * the rotation axis (needs to be {@link Vector3f#normalize() normalized}) * @return this */ public Matrix3f rotate(float angle, Vector3fc axis) { return rotate(angle, axis.x(), axis.y(), axis.z()); } /** * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest. *

* When used with a right-handed coordinate system, the produced rotation will rotate a vector * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin. * When used with a left-handed coordinate system, the rotation is clockwise. *

* If M is this matrix and A the rotation matrix obtained from the given angle and axis, * then the new matrix will be M * A. So when transforming a * vector v with the new matrix by using M * A * v, * the axis-angle rotation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying, * use {@link #rotation(float, Vector3fc)}. *

* Reference: http://en.wikipedia.org * * @see #rotate(float, float, float, float) * @see #rotation(float, Vector3fc) * * @param angle * the angle in radians * @param axis * the rotation axis (needs to be {@link Vector3f#normalize() normalized}) * @param dest * will hold the result * @return dest */ public Matrix3f rotate(float angle, Vector3fc axis, Matrix3f dest) { return rotate(angle, axis.x(), axis.y(), axis.z(), dest); } /** * Apply a rotation transformation to this matrix to make -z point along dir. *

* If M is this matrix and L the lookalong rotation matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, the * lookalong rotation transformation will be applied first! *

* In order to set the matrix to a lookalong transformation without post-multiplying it, * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}. * * @see #lookAlong(float, float, float, float, float, float) * @see #setLookAlong(Vector3fc, Vector3fc) * * @param dir * the direction in space to look along * @param up * the direction of 'up' * @return this */ public Matrix3f lookAlong(Vector3fc dir, Vector3fc up) { return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this); } /** * Apply a rotation transformation to this matrix to make -z point along dir * and store the result in dest. *

* If M is this matrix and L the lookalong rotation matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, the * lookalong rotation transformation will be applied first! *

* In order to set the matrix to a lookalong transformation without post-multiplying it, * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}. * * @see #lookAlong(float, float, float, float, float, float) * @see #setLookAlong(Vector3fc, Vector3fc) * * @param dir * the direction in space to look along * @param up * the direction of 'up' * @param dest * will hold the result * @return dest */ public Matrix3f lookAlong(Vector3fc dir, Vector3fc up, Matrix3f dest) { return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest); } /** * Apply a rotation transformation to this matrix to make -z point along dir * and store the result in dest. *

* If M is this matrix and L the lookalong rotation matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, the * lookalong rotation transformation will be applied first! *

* In order to set the matrix to a lookalong transformation without post-multiplying it, * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()} * * @see #setLookAlong(float, float, float, float, float, float) * * @param dirX * the x-coordinate of the direction to look along * @param dirY * the y-coordinate of the direction to look along * @param dirZ * the z-coordinate of the direction to look along * @param upX * the x-coordinate of the up vector * @param upY * the y-coordinate of the up vector * @param upZ * the z-coordinate of the up vector * @param dest * will hold the result * @return dest */ public Matrix3f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix3f dest) { // Normalize direction float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); dirX *= -invDirLength; dirY *= -invDirLength; dirZ *= -invDirLength; // left = up x direction float leftX, leftY, leftZ; leftX = upY * dirZ - upZ * dirY; leftY = upZ * dirX - upX * dirZ; leftZ = upX * dirY - upY * dirX; // normalize left float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); leftX *= invLeftLength; leftY *= invLeftLength; leftZ *= invLeftLength; // up = direction x left float upnX = dirY * leftZ - dirZ * leftY; float upnY = dirZ * leftX - dirX * leftZ; float upnZ = dirX * leftY - dirY * leftX; // calculate right matrix elements float rm00 = leftX; float rm01 = upnX; float rm02 = dirX; float rm10 = leftY; float rm11 = upnY; float rm12 = dirY; float rm20 = leftZ; float rm21 = upnZ; float rm22 = dirZ; // perform optimized matrix multiplication // introduce temporaries for dependent results float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22; dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22; dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22; // set the rest of the matrix elements dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; return dest; } /** * Apply a rotation transformation to this matrix to make -z point along dir. *

* If M is this matrix and L the lookalong rotation matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, the * lookalong rotation transformation will be applied first! *

* In order to set the matrix to a lookalong transformation without post-multiplying it, * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()} * * @see #setLookAlong(float, float, float, float, float, float) * * @param dirX * the x-coordinate of the direction to look along * @param dirY * the y-coordinate of the direction to look along * @param dirZ * the z-coordinate of the direction to look along * @param upX * the x-coordinate of the up vector * @param upY * the y-coordinate of the up vector * @param upZ * the z-coordinate of the up vector * @return this */ public Matrix3f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) { return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this); } /** * Set this matrix to a rotation transformation to make -z * point along dir. *

* In order to apply the lookalong transformation to any previous existing transformation, * use {@link #lookAlong(Vector3fc, Vector3fc)}. * * @see #setLookAlong(Vector3fc, Vector3fc) * @see #lookAlong(Vector3fc, Vector3fc) * * @param dir * the direction in space to look along * @param up * the direction of 'up' * @return this */ public Matrix3f setLookAlong(Vector3fc dir, Vector3fc up) { return setLookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z()); } /** * Set this matrix to a rotation transformation to make -z * point along dir. *

* In order to apply the lookalong transformation to any previous existing transformation, * use {@link #lookAlong(float, float, float, float, float, float) lookAlong()} * * @see #setLookAlong(float, float, float, float, float, float) * @see #lookAlong(float, float, float, float, float, float) * * @param dirX * the x-coordinate of the direction to look along * @param dirY * the y-coordinate of the direction to look along * @param dirZ * the z-coordinate of the direction to look along * @param upX * the x-coordinate of the up vector * @param upY * the y-coordinate of the up vector * @param upZ * the z-coordinate of the up vector * @return this */ public Matrix3f setLookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) { // Normalize direction float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); dirX *= -invDirLength; dirY *= -invDirLength; dirZ *= -invDirLength; // left = up x direction float leftX, leftY, leftZ; leftX = upY * dirZ - upZ * dirY; leftY = upZ * dirX - upX * dirZ; leftZ = upX * dirY - upY * dirX; // normalize left float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); leftX *= invLeftLength; leftY *= invLeftLength; leftZ *= invLeftLength; // up = direction x left float upnX = dirY * leftZ - dirZ * leftY; float upnY = dirZ * leftX - dirX * leftZ; float upnZ = dirX * leftY - dirY * leftX; m00 = leftX; m01 = upnX; m02 = dirX; m10 = leftY; m11 = upnY; m12 = dirY; m20 = leftZ; m21 = upnZ; m22 = dirZ; return this; } public Vector3f getRow(int row, Vector3f dest) throws IndexOutOfBoundsException { switch (row) { case 0: return dest.set(m00, m10, m20); case 1: return dest.set(m01, m11, m21); case 2: return dest.set(m02, m12, m22); default: throw new IndexOutOfBoundsException(); } } /** * Set the row at the given row index, starting with 0. * * @param row * the row index in [0..2] * @param src * the row components to set * @return this * @throws IndexOutOfBoundsException if row is not in [0..2] */ public Matrix3f setRow(int row, Vector3fc src) throws IndexOutOfBoundsException { return setRow(row, src.x(), src.y(), src.z()); } /** * Set the row at the given row index, starting with 0. * * @param row * the row index in [0..2] * @param x * the first element in the row * @param y * the second element in the row * @param z * the third element in the row * @return this * @throws IndexOutOfBoundsException if row is not in [0..2] */ public Matrix3f setRow(int row, float x, float y, float z) throws IndexOutOfBoundsException { switch (row) { case 0: this.m00 = x; this.m10 = y; this.m20 = z; break; case 1: this.m01 = x; this.m11 = y; this.m21 = z; break; case 2: this.m02 = x; this.m12 = y; this.m22 = z; break; default: throw new IndexOutOfBoundsException(); } return this; } public Vector3f getColumn(int column, Vector3f dest) throws IndexOutOfBoundsException { switch (column) { case 0: return dest.set(m00, m01, m02); case 1: return dest.set(m10, m11, m12); case 2: return dest.set(m20, m21, m22); default: throw new IndexOutOfBoundsException(); } } /** * Set the column at the given column index, starting with 0. * * @param column * the column index in [0..2] * @param src * the column components to set * @return this * @throws IndexOutOfBoundsException if column is not in [0..2] */ public Matrix3f setColumn(int column, Vector3fc src) throws IndexOutOfBoundsException { return setColumn(column, src.x(), src.y(), src.z()); } /** * Set the column at the given column index, starting with 0. * * @param column * the column index in [0..2] * @param x * the first element in the column * @param y * the second element in the column * @param z * the third element in the column * @return this * @throws IndexOutOfBoundsException if column is not in [0..2] */ public Matrix3f setColumn(int column, float x, float y, float z) throws IndexOutOfBoundsException { switch (column) { case 0: this.m00 = x; this.m01 = y; this.m02 = z; break; case 1: this.m10 = x; this.m11 = y; this.m12 = z; break; case 2: this.m20 = x; this.m21 = y; this.m22 = z; break; default: throw new IndexOutOfBoundsException(); } return this; } public float get(int column, int row) { return MemUtil.INSTANCE.get(this, column, row); } /** * Set the matrix element at the given column and row to the specified value. * * @param column * the colum index in [0..2] * @param row * the row index in [0..2] * @param value * the value * @return this */ public Matrix3f set(int column, int row, float value) { return MemUtil.INSTANCE.set(this, column, row, value); } public float getRowColumn(int row, int column) { return MemUtil.INSTANCE.get(this, column, row); } /** * Set the matrix element at the given row and column to the specified value. * * @param row * the row index in [0..2] * @param column * the colum index in [0..2] * @param value * the value * @return this */ public Matrix3f setRowColumn(int row, int column, float value) { return MemUtil.INSTANCE.set(this, column, row, value); } /** * Set this matrix to its own normal matrix. *

* The normal matrix of m is the transpose of the inverse of m. *

* Please note that, if this is an orthogonal matrix or a matrix whose columns are orthogonal vectors, * then this method need not be invoked, since in that case this itself is its normal matrix. * In this case, use {@link #set(Matrix3fc)} to set a given Matrix3f to this matrix. * * @see #set(Matrix3fc) * * @return this */ public Matrix3f normal() { return normal(this); } /** * Compute a normal matrix from this matrix and store it into dest. *

* The normal matrix of m is the transpose of the inverse of m. *

* Please note that, if this is an orthogonal matrix or a matrix whose columns are orthogonal vectors, * then this method need not be invoked, since in that case this itself is its normal matrix. * In this case, use {@link #set(Matrix3fc)} to set a given Matrix3f to this matrix. * * @see #set(Matrix3fc) * * @param dest * will hold the result * @return dest */ public Matrix3f normal(Matrix3f dest) { float m00m11 = m00 * m11; float m01m10 = m01 * m10; float m02m10 = m02 * m10; float m00m12 = m00 * m12; float m01m12 = m01 * m12; float m02m11 = m02 * m11; float det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20; float s = 1.0f / det; /* Invert and transpose in one go */ float nm00 = (m11 * m22 - m21 * m12) * s; float nm01 = (m20 * m12 - m10 * m22) * s; float nm02 = (m10 * m21 - m20 * m11) * s; float nm10 = (m21 * m02 - m01 * m22) * s; float nm11 = (m00 * m22 - m20 * m02) * s; float nm12 = (m20 * m01 - m00 * m21) * s; float nm20 = (m01m12 - m02m11) * s; float nm21 = (m02m10 - m00m12) * s; float nm22 = (m00m11 - m01m10) * s; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } /** * Compute the cofactor matrix of this. *

* The cofactor matrix can be used instead of {@link #normal()} to transform normals * when the orientation of the normals with respect to the surface should be preserved. * * @return this */ public Matrix3f cofactor() { return cofactor(this); } /** * Compute the cofactor matrix of this and store it into dest. *

* The cofactor matrix can be used instead of {@link #normal(Matrix3f)} to transform normals * when the orientation of the normals with respect to the surface should be preserved. * * @param dest * will hold the result * @return dest */ public Matrix3f cofactor(Matrix3f dest) { float nm00 = m11 * m22 - m21 * m12; float nm01 = m20 * m12 - m10 * m22; float nm02 = m10 * m21 - m20 * m11; float nm10 = m21 * m02 - m01 * m22; float nm11 = m00 * m22 - m20 * m02; float nm12 = m20 * m01 - m00 * m21; float nm20 = m01 * m12 - m11 * m02; float nm21 = m02 * m10 - m12 * m00; float nm22 = m00 * m11 - m10 * m01; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; dest.m20 = nm20; dest.m21 = nm21; dest.m22 = nm22; return dest; } public Vector3f getScale(Vector3f dest) { return dest.set(Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02), Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12), Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22)); } public Vector3f positiveZ(Vector3f dir) { dir.x = m10 * m21 - m11 * m20; dir.y = m20 * m01 - m21 * m00; dir.z = m00 * m11 - m01 * m10; return dir.normalize(dir); } public Vector3f normalizedPositiveZ(Vector3f dir) { dir.x = m02; dir.y = m12; dir.z = m22; return dir; } public Vector3f positiveX(Vector3f dir) { dir.x = m11 * m22 - m12 * m21; dir.y = m02 * m21 - m01 * m22; dir.z = m01 * m12 - m02 * m11; return dir.normalize(dir); } public Vector3f normalizedPositiveX(Vector3f dir) { dir.x = m00; dir.y = m10; dir.z = m20; return dir; } public Vector3f positiveY(Vector3f dir) { dir.x = m12 * m20 - m10 * m22; dir.y = m00 * m22 - m02 * m20; dir.z = m02 * m10 - m00 * m12; return dir.normalize(dir); } public Vector3f normalizedPositiveY(Vector3f dir) { dir.x = m01; dir.y = m11; dir.z = m21; return dir; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Float.floatToIntBits(m00); result = prime * result + Float.floatToIntBits(m01); result = prime * result + Float.floatToIntBits(m02); result = prime * result + Float.floatToIntBits(m10); result = prime * result + Float.floatToIntBits(m11); result = prime * result + Float.floatToIntBits(m12); result = prime * result + Float.floatToIntBits(m20); result = prime * result + Float.floatToIntBits(m21); result = prime * result + Float.floatToIntBits(m22); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Matrix3f other = (Matrix3f) obj; if (Float.floatToIntBits(m00) != Float.floatToIntBits(other.m00)) return false; if (Float.floatToIntBits(m01) != Float.floatToIntBits(other.m01)) return false; if (Float.floatToIntBits(m02) != Float.floatToIntBits(other.m02)) return false; if (Float.floatToIntBits(m10) != Float.floatToIntBits(other.m10)) return false; if (Float.floatToIntBits(m11) != Float.floatToIntBits(other.m11)) return false; if (Float.floatToIntBits(m12) != Float.floatToIntBits(other.m12)) return false; if (Float.floatToIntBits(m20) != Float.floatToIntBits(other.m20)) return false; if (Float.floatToIntBits(m21) != Float.floatToIntBits(other.m21)) return false; if (Float.floatToIntBits(m22) != Float.floatToIntBits(other.m22)) return false; return true; } public boolean equals(Matrix3fc m, float delta) { if (this == m) return true; if (m == null) return false; if (!(m instanceof Matrix3f)) return false; if (!Runtime.equals(m00, m.m00(), delta)) return false; if (!Runtime.equals(m01, m.m01(), delta)) return false; if (!Runtime.equals(m02, m.m02(), delta)) return false; if (!Runtime.equals(m10, m.m10(), delta)) return false; if (!Runtime.equals(m11, m.m11(), delta)) return false; if (!Runtime.equals(m12, m.m12(), delta)) return false; if (!Runtime.equals(m20, m.m20(), delta)) return false; if (!Runtime.equals(m21, m.m21(), delta)) return false; if (!Runtime.equals(m22, m.m22(), delta)) return false; return true; } /** * Exchange the values of this matrix with the given other matrix. * * @param other * the other matrix to exchange the values with * @return this */ public Matrix3f swap(Matrix3f other) { MemUtil.INSTANCE.swap(this, other); return this; } /** * Component-wise add this and other. * * @param other * the other addend * @return this */ public Matrix3f add(Matrix3fc other) { return add(other, this); } public Matrix3f add(Matrix3fc other, Matrix3f dest) { dest.m00 = m00 + other.m00(); dest.m01 = m01 + other.m01(); dest.m02 = m02 + other.m02(); dest.m10 = m10 + other.m10(); dest.m11 = m11 + other.m11(); dest.m12 = m12 + other.m12(); dest.m20 = m20 + other.m20(); dest.m21 = m21 + other.m21(); dest.m22 = m22 + other.m22(); return dest; } /** * Component-wise subtract subtrahend from this. * * @param subtrahend * the subtrahend * @return this */ public Matrix3f sub(Matrix3fc subtrahend) { return sub(subtrahend, this); } public Matrix3f sub(Matrix3fc subtrahend, Matrix3f dest) { dest.m00 = m00 - subtrahend.m00(); dest.m01 = m01 - subtrahend.m01(); dest.m02 = m02 - subtrahend.m02(); dest.m10 = m10 - subtrahend.m10(); dest.m11 = m11 - subtrahend.m11(); dest.m12 = m12 - subtrahend.m12(); dest.m20 = m20 - subtrahend.m20(); dest.m21 = m21 - subtrahend.m21(); dest.m22 = m22 - subtrahend.m22(); return dest; } /** * Component-wise multiply this by other. * * @param other * the other matrix * @return this */ public Matrix3f mulComponentWise(Matrix3fc other) { return mulComponentWise(other, this); } public Matrix3f mulComponentWise(Matrix3fc other, Matrix3f dest) { dest.m00 = m00 * other.m00(); dest.m01 = m01 * other.m01(); dest.m02 = m02 * other.m02(); dest.m10 = m10 * other.m10(); dest.m11 = m11 * other.m11(); dest.m12 = m12 * other.m12(); dest.m20 = m20 * other.m20(); dest.m21 = m21 * other.m21(); dest.m22 = m22 * other.m22(); return dest; } /** * Set this matrix to a skew-symmetric matrix using the following layout: *

     *  0,  a, -b
     * -a,  0,  c
     *  b, -c,  0
     * 
* * Reference: https://en.wikipedia.org * * @param a * the value used for the matrix elements m01 and m10 * @param b * the value used for the matrix elements m02 and m20 * @param c * the value used for the matrix elements m12 and m21 * @return this */ public Matrix3f setSkewSymmetric(float a, float b, float c) { m00 = m11 = m22 = 0; m01 = -a; m02 = b; m10 = a; m12 = -c; m20 = -b; m21 = c; return this; } /** * Linearly interpolate this and other using the given interpolation factor t * and store the result in this. *

* If t is 0.0 then the result is this. If the interpolation factor is 1.0 * then the result is other. * * @param other * the other matrix * @param t * the interpolation factor between 0.0 and 1.0 * @return this */ public Matrix3f lerp(Matrix3fc other, float t) { return lerp(other, t, this); } public Matrix3f lerp(Matrix3fc other, float t, Matrix3f dest) { dest.m00 = Math.fma(other.m00() - m00, t, m00); dest.m01 = Math.fma(other.m01() - m01, t, m01); dest.m02 = Math.fma(other.m02() - m02, t, m02); dest.m10 = Math.fma(other.m10() - m10, t, m10); dest.m11 = Math.fma(other.m11() - m11, t, m11); dest.m12 = Math.fma(other.m12() - m12, t, m12); dest.m20 = Math.fma(other.m20() - m20, t, m20); dest.m21 = Math.fma(other.m21() - m21, t, m21); dest.m22 = Math.fma(other.m22() - m22, t, m22); return dest; } /** * Apply a model transformation to this matrix for a right-handed coordinate system, * that aligns the local +Z axis with direction * and store the result in dest. *

* If M is this matrix and L the lookat matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, * the lookat transformation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying it, * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}. *

* This method is equivalent to calling: mul(new Matrix3f().lookAlong(new Vector3f(dir).negate(), up).invert(), dest) * * @see #rotateTowards(float, float, float, float, float, float, Matrix3f) * @see #rotationTowards(Vector3fc, Vector3fc) * * @param direction * the direction to rotate towards * @param up * the model's up vector * @param dest * will hold the result * @return dest */ public Matrix3f rotateTowards(Vector3fc direction, Vector3fc up, Matrix3f dest) { return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), dest); } /** * Apply a model transformation to this matrix for a right-handed coordinate system, * that aligns the local +Z axis with direction. *

* If M is this matrix and L the lookat matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, * the lookat transformation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying it, * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}. *

* This method is equivalent to calling: mul(new Matrix3f().lookAlong(new Vector3f(dir).negate(), up).invert()) * * @see #rotateTowards(float, float, float, float, float, float) * @see #rotationTowards(Vector3fc, Vector3fc) * * @param direction * the direction to orient towards * @param up * the up vector * @return this */ public Matrix3f rotateTowards(Vector3fc direction, Vector3fc up) { return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), this); } /** * Apply a model transformation to this matrix for a right-handed coordinate system, * that aligns the local +Z axis with direction. *

* If M is this matrix and L the lookat matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, * the lookat transformation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying it, * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}. *

* This method is equivalent to calling: mul(new Matrix3f().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert()) * * @see #rotateTowards(Vector3fc, Vector3fc) * @see #rotationTowards(float, float, float, float, float, float) * * @param dirX * the x-coordinate of the direction to rotate towards * @param dirY * the y-coordinate of the direction to rotate towards * @param dirZ * the z-coordinate of the direction to rotate towards * @param upX * the x-coordinate of the up vector * @param upY * the y-coordinate of the up vector * @param upZ * the z-coordinate of the up vector * @return this */ public Matrix3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) { return rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this); } /** * Apply a model transformation to this matrix for a right-handed coordinate system, * that aligns the local +Z axis with dir * and store the result in dest. *

* If M is this matrix and L the lookat matrix, * then the new matrix will be M * L. So when transforming a * vector v with the new matrix by using M * L * v, * the lookat transformation will be applied first! *

* In order to set the matrix to a rotation transformation without post-multiplying it, * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}. *

* This method is equivalent to calling: mul(new Matrix3f().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest) * * @see #rotateTowards(Vector3fc, Vector3fc) * @see #rotationTowards(float, float, float, float, float, float) * * @param dirX * the x-coordinate of the direction to rotate towards * @param dirY * the y-coordinate of the direction to rotate towards * @param dirZ * the z-coordinate of the direction to rotate towards * @param upX * the x-coordinate of the up vector * @param upY * the y-coordinate of the up vector * @param upZ * the z-coordinate of the up vector * @param dest * will hold the result * @return dest */ public Matrix3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix3f dest) { // Normalize direction float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); float ndirX = dirX * invDirLength; float ndirY = dirY * invDirLength; float ndirZ = dirZ * invDirLength; // left = up x direction float leftX, leftY, leftZ; leftX = upY * ndirZ - upZ * ndirY; leftY = upZ * ndirX - upX * ndirZ; leftZ = upX * ndirY - upY * ndirX; // normalize left float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); leftX *= invLeftLength; leftY *= invLeftLength; leftZ *= invLeftLength; // up = direction x left float upnX = ndirY * leftZ - ndirZ * leftY; float upnY = ndirZ * leftX - ndirX * leftZ; float upnZ = ndirX * leftY - ndirY * leftX; float rm00 = leftX; float rm01 = leftY; float rm02 = leftZ; float rm10 = upnX; float rm11 = upnY; float rm12 = upnZ; float rm20 = ndirX; float rm21 = ndirY; float rm22 = ndirZ; float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22; dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22; dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22; dest.m00 = nm00; dest.m01 = nm01; dest.m02 = nm02; dest.m10 = nm10; dest.m11 = nm11; dest.m12 = nm12; return dest; } /** * Set this matrix to a model transformation for a right-handed coordinate system, * that aligns the local -z axis with center - eye. *

* In order to apply the rotation transformation to a previous existing transformation, * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}. *

* This method is equivalent to calling: setLookAlong(new Vector3f(dir).negate(), up).invert() * * @see #rotationTowards(Vector3fc, Vector3fc) * @see #rotateTowards(float, float, float, float, float, float) * * @param dir * the direction to orient the local -z axis towards * @param up * the up vector * @return this */ public Matrix3f rotationTowards(Vector3fc dir, Vector3fc up) { return rotationTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z()); } /** * Set this matrix to a model transformation for a right-handed coordinate system, * that aligns the local -z axis with center - eye. *

* In order to apply the rotation transformation to a previous existing transformation, * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}. *

* This method is equivalent to calling: setLookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert() * * @see #rotateTowards(Vector3fc, Vector3fc) * @see #rotationTowards(float, float, float, float, float, float) * * @param dirX * the x-coordinate of the direction to rotate towards * @param dirY * the y-coordinate of the direction to rotate towards * @param dirZ * the z-coordinate of the direction to rotate towards * @param upX * the x-coordinate of the up vector * @param upY * the y-coordinate of the up vector * @param upZ * the z-coordinate of the up vector * @return this */ public Matrix3f rotationTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) { // Normalize direction float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); float ndirX = dirX * invDirLength; float ndirY = dirY * invDirLength; float ndirZ = dirZ * invDirLength; // left = up x direction float leftX, leftY, leftZ; leftX = upY * ndirZ - upZ * ndirY; leftY = upZ * ndirX - upX * ndirZ; leftZ = upX * ndirY - upY * ndirX; // normalize left float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); leftX *= invLeftLength; leftY *= invLeftLength; leftZ *= invLeftLength; // up = direction x left float upnX = ndirY * leftZ - ndirZ * leftY; float upnY = ndirZ * leftX - ndirX * leftZ; float upnZ = ndirX * leftY - ndirY * leftX; this.m00 = leftX; this.m01 = leftY; this.m02 = leftZ; this.m10 = upnX; this.m11 = upnY; this.m12 = upnZ; this.m20 = ndirX; this.m21 = ndirY; this.m22 = ndirZ; return this; } /** * Extract the Euler angles from the rotation represented by this matrix and store the extracted Euler angles in dest. *

* This method assumes that this matrix only represents a rotation without scaling. *

* Note that the returned Euler angles must be applied in the order Z * Y * X to obtain the identical matrix. * This means that calling {@link Matrix3f#rotateZYX(float, float, float)} using the obtained Euler angles will yield * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix * m2 should be identical to m (disregarding possible floating-point inaccuracies). *

     * Matrix3f m = ...; // <- matrix only representing rotation
     * Matrix3f n = new Matrix3f();
     * n.rotateZYX(m.getEulerAnglesZYX(new Vector3f()));
     * 
*

* Reference: http://nghiaho.com/ * * @param dest * will hold the extracted Euler angles * @return dest */ public Vector3f getEulerAnglesZYX(Vector3f dest) { dest.x = Math.atan2(m12, m22); dest.y = Math.atan2(-m02, Math.sqrt(m12 * m12 + m22 * m22)); dest.z = Math.atan2(m01, m00); return dest; } /** * Apply an oblique projection transformation to this matrix with the given values for a and * b. *

* If M is this matrix and O the oblique transformation matrix, * then the new matrix will be M * O. So when transforming a * vector v with the new matrix by using M * O * v, the * oblique transformation will be applied first! *

* The oblique transformation is defined as: *

     * x' = x + a*z
     * y' = y + a*z
     * z' = z
     * 
* or in matrix form: *
     * 1 0 a
     * 0 1 b
     * 0 0 1
     * 
* * @param a * the value for the z factor that applies to x * @param b * the value for the z factor that applies to y * @return this */ public Matrix3f obliqueZ(float a, float b) { this.m20 = m00 * a + m10 * b + m20; this.m21 = m01 * a + m11 * b + m21; this.m22 = m02 * a + m12 * b + m22; return this; } /** * Apply an oblique projection transformation to this matrix with the given values for a and * b and store the result in dest. *

* If M is this matrix and O the oblique transformation matrix, * then the new matrix will be M * O. So when transforming a * vector v with the new matrix by using M * O * v, the * oblique transformation will be applied first! *

* The oblique transformation is defined as: *

     * x' = x + a*z
     * y' = y + a*z
     * z' = z
     * 
* or in matrix form: *
     * 1 0 a
     * 0 1 b
     * 0 0 1
     * 
* * @param a * the value for the z factor that applies to x * @param b * the value for the z factor that applies to y * @param dest * will hold the result * @return dest */ public Matrix3f obliqueZ(float a, float b, Matrix3f dest) { dest.m00 = m00; dest.m01 = m01; dest.m02 = m02; dest.m10 = m10; dest.m11 = m11; dest.m12 = m12; dest.m20 = m00 * a + m10 * b + m20; dest.m21 = m01 * a + m11 * b + m21; dest.m22 = m02 * a + m12 * b + m22; return dest; } public Matrix3f reflect(float nx, float ny, float nz, Matrix3f dest) { float da = nx + nx, db = ny + ny, dc = nz + nz; float rm00 = 1.0f - da * nx; float rm01 = -da * ny; float rm02 = -da * nz; float rm10 = -db * nx; float rm11 = 1.0f - db * ny; float rm12 = -db * nz; float rm20 = -dc * nx; float rm21 = -dc * ny; float rm22 = 1.0f - dc * nz; float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02; float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02; float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02; float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12; float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12; float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12; return dest ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22) ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22) ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22) ._m00(nm00) ._m01(nm01) ._m02(nm02) ._m10(nm10) ._m11(nm11) ._m12(nm12); } /** * Apply a mirror/reflection transformation to this matrix that reflects through the given plane * specified via the plane normal. *

* If M is this matrix and R the reflection matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * reflection will be applied first! * * @param nx * the x-coordinate of the plane normal * @param ny * the y-coordinate of the plane normal * @param nz * the z-coordinate of the plane normal * @return this */ public Matrix3f reflect(float nx, float ny, float nz) { return reflect(nx, ny, nz, this); } /** * Apply a mirror/reflection transformation to this matrix that reflects through the given plane * specified via the plane normal. *

* If M is this matrix and R the reflection matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * reflection will be applied first! * * @param normal * the plane normal * @return this */ public Matrix3f reflect(Vector3fc normal) { return reflect(normal.x(), normal.y(), normal.z()); } /** * Apply a mirror/reflection transformation to this matrix that reflects about a plane * specified via the plane orientation. *

* This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. * It is assumed that the default mirror plane's normal is (0, 0, 1). So, if the given {@link Quaternionfc} is * the identity (does not apply any additional rotation), the reflection plane will be z=0. *

* If M is this matrix and R the reflection matrix, * then the new matrix will be M * R. So when transforming a * vector v with the new matrix by using M * R * v, the * reflection will be applied first! * * @param orientation * the plane orientation * @return this */ public Matrix3f reflect(Quaternionfc orientation) { return reflect(orientation, this); } public Matrix3f reflect(Quaternionfc orientation, Matrix3f dest) { float num1 = orientation.x() + orientation.x(); float num2 = orientation.y() + orientation.y(); float num3 = orientation.z() + orientation.z(); float normalX = orientation.x() * num3 + orientation.w() * num2; float normalY = orientation.y() * num3 - orientation.w() * num1; float normalZ = 1.0f - (orientation.x() * num1 + orientation.y() * num2); return reflect(normalX, normalY, normalZ, dest); } public Matrix3f reflect(Vector3fc normal, Matrix3f dest) { return reflect(normal.x(), normal.y(), normal.z(), dest); } /** * Set this matrix to a mirror/reflection transformation that reflects through the given plane * specified via the plane normal. * * @param nx * the x-coordinate of the plane normal * @param ny * the y-coordinate of the plane normal * @param nz * the z-coordinate of the plane normal * @return this */ public Matrix3f reflection(float nx, float ny, float nz) { float da = nx + nx, db = ny + ny, dc = nz + nz; this._m00(1.0f - da * nx); this._m01(-da * ny); this._m02(-da * nz); this._m10(-db * nx); this._m11(1.0f - db * ny); this._m12(-db * nz); this._m20(-dc * nx); this._m21(-dc * ny); this._m22(1.0f - dc * nz); return this; } /** * Set this matrix to a mirror/reflection transformation that reflects through the given plane * specified via the plane normal. * * @param normal * the plane normal * @return this */ public Matrix3f reflection(Vector3fc normal) { return reflection(normal.x(), normal.y(), normal.z()); } /** * Set this matrix to a mirror/reflection transformation that reflects through a plane * specified via the plane orientation. *

* This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene. * It is assumed that the default mirror plane's normal is (0, 0, 1). So, if the given {@link Quaternionfc} is * the identity (does not apply any additional rotation), the reflection plane will be z=0, offset by the given point. * * @param orientation * the plane orientation * @return this */ public Matrix3f reflection(Quaternionfc orientation) { float num1 = orientation.x() + orientation.x(); float num2 = orientation.y() + orientation.y(); float num3 = orientation.z() + orientation.z(); float normalX = orientation.x() * num3 + orientation.w() * num2; float normalY = orientation.y() * num3 - orientation.w() * num1; float normalZ = 1.0f - (orientation.x() * num1 + orientation.y() * num2); return reflection(normalX, normalY, normalZ); } public boolean isFinite() { return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) && Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) && Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy