Commit 10508066 authored by Matthias Betz's avatar Matthias Betz
Browse files

Add column-major Mat4 matrix helpers

parent 13767682
package de.hft.stuttgart.citydoctor2.gui.gl;
/**
* Minimal column-major 4x4 float matrix helpers, layout-compatible with OpenGL uniform uploads
* (element index = column*4 + row).
*/
public final class Mat4 {
private Mat4() {}
public static float[] identity() {
float[] m = new float[16];
m[0] = m[5] = m[10] = m[15] = 1f;
return m;
}
public static float[] translation(float x, float y, float z) {
float[] m = identity();
m[12] = x;
m[13] = y;
m[14] = z;
return m;
}
/** Returns a * b (column-major). */
public static float[] multiply(float[] a, float[] b) {
float[] r = new float[16];
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 4; row++) {
float sum = 0f;
for (int k = 0; k < 4; k++) {
sum += a[k * 4 + row] * b[col * 4 + k];
}
r[col * 4 + row] = sum;
}
}
return r;
}
/** Returns m * (x,y,z,w) as a length-4 array. */
public static float[] transform(float[] m, float x, float y, float z, float w) {
return new float[] {
m[0] * x + m[4] * y + m[8] * z + m[12] * w,
m[1] * x + m[5] * y + m[9] * z + m[13] * w,
m[2] * x + m[6] * y + m[10] * z + m[14] * w,
m[3] * x + m[7] * y + m[11] * z + m[15] * w
};
}
public static float[] rotationX(float rad) {
float c = (float) Math.cos(rad);
float s = (float) Math.sin(rad);
float[] m = identity();
m[5] = c; m[9] = -s;
m[6] = s; m[10] = c;
return m;
}
public static float[] rotationZ(float rad) {
float c = (float) Math.cos(rad);
float s = (float) Math.sin(rad);
float[] m = identity();
m[0] = c; m[4] = -s;
m[1] = s; m[5] = c;
return m;
}
/** Right-handed perspective projection (camera looks down -Z). */
public static float[] perspective(float fovyRad, float aspect, float near, float far) {
float f = (float) (1.0 / Math.tan(fovyRad / 2.0));
float[] m = new float[16];
m[0] = f / aspect;
m[5] = f;
m[10] = (far + near) / (near - far);
m[11] = -1f;
m[14] = (2f * far * near) / (near - far);
return m;
}
}
package de.hft.stuttgart.citydoctor2.gui.gl;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class Mat4Test {
@Test
public void identityTimesVectorIsUnchanged() {
float[] v = Mat4.transform(Mat4.identity(), 2, 3, 4, 1);
assertArrayEquals(new float[]{2, 3, 4, 1}, v, 1e-6f);
}
@Test
public void translationMovesPoint() {
float[] m = Mat4.translation(5, -2, 1);
float[] v = Mat4.transform(m, 1, 1, 1, 1);
assertArrayEquals(new float[]{6, -1, 2, 1}, v, 1e-6f);
}
@Test
public void multiplyIsIdentityNeutral() {
float[] t = Mat4.translation(1, 2, 3);
assertArrayEquals(t, Mat4.multiply(Mat4.identity(), t), 1e-6f);
assertArrayEquals(t, Mat4.multiply(t, Mat4.identity()), 1e-6f);
}
@Test
public void rotationZ90MapsXAxisToYAxis() {
float[] m = Mat4.rotationZ((float) (Math.PI / 2));
float[] v = Mat4.transform(m, 1, 0, 0, 1);
assertEquals(0f, v[0], 1e-6f);
assertEquals(1f, v[1], 1e-6f);
}
@Test
public void perspectiveHasExpectedDiagonalStructure() {
float[] p = Mat4.perspective((float) Math.toRadians(60), 1.0f, 1f, 100f);
float f = (float) (1.0 / Math.tan(Math.toRadians(60) / 2));
assertEquals(f, p[0], 1e-5f);
assertEquals(f, p[5], 1e-5f);
assertEquals(-1f, p[11], 1e-6f);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment