ivengine.view.MatrixHelper.java Source code

Java tutorial

Introduction

Here is the source code for ivengine.view.MatrixHelper.java

Source

package ivengine.view;

import static org.lwjgl.opengl.GL20.glUniformMatrix4;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL20;
import org.lwjgl.util.vector.Matrix3f;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;

import kubex.gui.Chunk;
import kubex.utils.Vector3d;

/**
 * This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.
 * 
 *  @author Vctor Arellano Vicente (Ivelate)
 *  
 *  Contains multiple helper methods to work with matrixes
 */
public class MatrixHelper {
    public static final Vector3f zAxis = new Vector3f(0, 0, 1);
    public static final Vector3f yAxis = new Vector3f(0, 1, 0);
    public static final Vector3f xAxis = new Vector3f(1, 0, 0);
    public static final Matrix4f identity = new Matrix4f();

    private static Matrix3f m3buf = new Matrix3f();
    private static Vector3f v3buf = new Vector3f();

    private static FloatBuffer matrix44Buffer = BufferUtils.createFloatBuffer(16);

    /**
     * Creates a perspective projection matrix with a z near point <znear> , z far point <zfar> , field of view <fov> and resolution ratio <arat>
     */
    public static Matrix4f createProjectionMatrix(float znear, float zfar, float fov, float arat) {
        // Setup projection matrix
        Matrix4f projectionMatrix = new Matrix4f();

        float y_scale = coTangent(degreesToRadians(fov / 2f));
        float x_scale = y_scale / arat;
        float frustum_length = zfar - znear;

        projectionMatrix.m00 = x_scale;
        projectionMatrix.m11 = y_scale;
        projectionMatrix.m22 = -((zfar + znear) / frustum_length);
        projectionMatrix.m23 = -1;
        projectionMatrix.m32 = -((2 * znear * zfar) / frustum_length);
        projectionMatrix.m33 = 0;

        return projectionMatrix;
    }

    /**
     * Creates a orthographic projection matrix going from x <xm> to <xp> , from y <ym> to <yp> and from z <zm> to <zp>
     */
    public static Matrix4f createOrthoMatix(float xp, float xm, float yp, float ym, float zp, float zm) {
        Matrix4f res = new Matrix4f();
        res.m00 = 2.0f / (xp - xm);
        res.m01 = 0.0f;
        res.m02 = 0.0f;
        res.m03 = 0.0f;

        res.m10 = 0.0f;
        res.m11 = 2.0f / (yp - ym);
        res.m12 = 0.0f;
        res.m13 = 0.0f;

        res.m20 = 0.0f;
        res.m21 = 0.0f;
        res.m22 = -2.0f / (zp - zm);
        res.m23 = 0.0f;

        res.m30 = -(xp + xm) / (xp - xm);
        res.m31 = -(yp + ym) / (yp - ym);
        res.m32 = (zp + zm) / (zp - zm); // With the - at the beginning, it doesn't work properly. Its confusing, because all written scientific literature makes clear that this - is 
        // neccesary, but my tests give wrong results if it's there. Anyways : It works.
        res.m33 = 1.0f;

        return res;
    }

    /**
     * Creates both a scale and a translation matrix on the same call. Scale will be equal to <scale> (On all axis), and the translation will be <xt> , <yt> , <zt>
     */
    public static Matrix4f createScaleTranslationMatrix(float scale, float xt, float yt, float zt) {
        Matrix4f res = new Matrix4f();
        res.m00 = scale;
        res.m01 = 0.0f;
        res.m02 = 0.0f;
        res.m03 = 0.0f;

        res.m10 = 0.0f;
        res.m11 = scale;
        res.m12 = 0.0f;
        res.m13 = 0.0f;

        res.m20 = 0.0f;
        res.m21 = 0.0f;
        res.m22 = scale;
        res.m23 = 0.0f;

        res.m30 = xt;
        res.m31 = yt;
        res.m32 = zt;
        res.m33 = 1.0f;

        return res;
    }

    /**
     * Multiplies a matrix by a vector
     */
    public static Vector4f multiply(Matrix4f op1, Vector4f op2) {
        return new Vector4f((op1.m00 * op2.x) + (op1.m10 * op2.y) + (op1.m20 * op2.z) + (op1.m30 * op2.w),
                (op1.m01 * op2.x) + (op1.m11 * op2.y) + (op1.m21 * op2.z) + (op1.m31 * op2.w),
                (op1.m02 * op2.x) + (op1.m12 * op2.y) + (op1.m22 * op2.z) + (op1.m32 * op2.w),
                (op1.m03 * op2.x) + (op1.m13 * op2.y) + (op1.m23 * op2.z) + (op1.m33 * op2.w));
    }

    /**
     * Uploads a matrix <mat> to the graphics card, to the uniform with location <dest>
     */
    public static void uploadMatrix(Matrix4f mat, int dest) {
        matrix44Buffer.rewind();
        mat.store(matrix44Buffer);
        matrix44Buffer.flip();
        glUniformMatrix4(dest, false, matrix44Buffer);
    }

    /**
     * Perfomance method. Reuses a matrix <mat>, so memory cost is 0: Translates that matrix <mat> using the vector - <trans>, uploads it to the graphics card
     * and retranslates it back to its initial position.
     * Due to some floating point operation errors, this operation can return a matrix not exactly equal to the original one. This method is fast but pottentially inaccurate, so
     * its marked as deprecate
     */
    @Deprecated
    public static void uploadTranslatedMatrix(Matrix4f mat, Vector3f trans, int dest) {
        mat.m30 -= trans.x;
        mat.m31 -= trans.y;
        mat.m32 -= trans.z;
        uploadMatrix(mat, dest);
        mat.m30 += trans.x;
        mat.m31 += trans.y;
        mat.m32 += trans.z;
    }

    /**
     * Perfomance method. Reuses a matrix <mat>, so memory cost is 0: Translates that matrix <mat> using the vector - <trans>, uploads it to the graphics card
     * and retranslates it back to its initial position.
     */
    public static void uploadTranslatedMatrix(Matrix4f mat, Vector3d trans, int dest) {
        float m30 = mat.m30;
        float m31 = mat.m31;
        float m32 = mat.m32;
        mat.m30 -= trans.x;
        mat.m31 -= trans.y;
        mat.m32 -= trans.z;
        uploadMatrix(mat, dest);
        mat.m30 = m30;
        mat.m31 = m31;
        mat.m32 = m32;
    }

    /**
     * Creates a translation matrix on-the-fly over the matrix <mat> and uploads it.
     * This method when centering the perspective in the player, so the translation will be equal to the
     * distance to the center point, being that <ix> , <iy> , <iz> , and the objective point being
     * described by the vector <trans>
     */
    public static void uploadTranslationMatrix(Matrix4f mat, double ix, double iy, double iz, Vector3d trans,
            int dest) {
        mat.m30 = (float) (ix - trans.x);
        mat.m31 = (float) (iy - trans.y);
        mat.m32 = (float) (iz - trans.z);
        uploadMatrix(mat, dest);
    }

    /**
     * Uploads a vector <vec> to the graphics card (Into the uniform location <dest> ) 
     */
    public static void uploadVector(Vector3f vec, int dest) {
        GL20.glUniform3f(dest, vec.x, vec.y, vec.z);
    }

    /**
     * Returns the inverted matrix of the rotation matrix contained in <mat>
     */
    public static Matrix4f getRotationAndInvert(Matrix4f mat) {
        Matrix4f toRet = new Matrix4f(mat);
        toRet.m30 = 0;
        toRet.m31 = 0;
        toRet.m32 = 0;
        Matrix4f.invert(toRet, toRet);
        return toRet;
    }

    private static float coTangent(float angle) {
        return (float) (1f / Math.tan(angle));
    }

    private static float degreesToRadians(float degrees) {
        return degrees * (float) (Math.PI / 180d);
    }

    /**
     * Fast affine inverse. Uses a static buffer, so this method is synchronized
     */
    public static synchronized Matrix4f getAffineInverse(Matrix4f m, Matrix4f dest) {
        m3buf.m00 = m.m00;
        m3buf.m01 = m.m01;
        m3buf.m02 = m.m02;
        m3buf.m10 = m.m10;
        m3buf.m11 = m.m11;
        m3buf.m12 = m.m12;
        m3buf.m20 = m.m20;
        m3buf.m21 = m.m21;
        m3buf.m22 = m.m22;

        Matrix3f.invert(m3buf, m3buf);

        v3buf.x = m.m30;
        v3buf.y = m.m31;
        v3buf.z = m.m32;

        Matrix4f d = dest == null ? new Matrix4f() : dest;

        d.m00 = m3buf.m00;
        d.m01 = m3buf.m01;
        d.m02 = m3buf.m02;
        d.m10 = m3buf.m10;
        d.m11 = m3buf.m11;
        d.m12 = m3buf.m12;
        d.m20 = m3buf.m20;
        d.m21 = m3buf.m21;
        d.m22 = m3buf.m22;

        Matrix3f.transform(m3buf, v3buf, v3buf);

        d.m30 = -v3buf.x;
        d.m31 = -v3buf.y;
        d.m32 = -v3buf.z;

        d.m03 = 0;
        d.m13 = 0;
        d.m23 = 0;
        d.m33 = 1;

        return d;
    }
}