LWJGL教程09 - 世界

世界矩阵

$$
M = M_p(M_tM_rM_s)
= M_pM_w
$$

创建一个Transformation类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[imports ...]

public class Transformation {
private Matrix4f projectionMatrix;
private Matrix4f worldMatrix;

public Transformation() {
worldMatrix = new Matrix4f();
projectionMatrix = new Matrix4f();
}

public Matrix4f getProjectionMatrix(float fov, float width, float height, float zNear, float zFar) {
float aspectRatio = width / height;
projectionMatrix.identity();
projectionMatrix.perspective(fov, aspectRatio, zNear, zFar);
return projectionMatrix;
}

public Matrix4f getWorldMatrix(Vector3f offset, Vector3f rotation, float scale) {
worldMatrix.identity().translate(offset).
rotateX((float)Math.toRadians(rotation.x)).
rotateY((float)Math.toRadians(rotation.y)).
rotateZ((float)Math.toRadians(rotation.z)).
scale(scale);
return worldMatrix;
}
}

在创建一个Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[imports ...]

public class Entity {
private Mesh mesh;
private Vector3f position;
private Vector3f rotation;
private float scale;

public Entity(Mesh mesh) {
this.mesh = mesh;
position = new Vector3f();
rotation = new Vector3f();
scale = 1;
}
[Getter & Setter ...]
}

然后在SceneRender中实例化Transformation和添加Uniforms

1
2
3
4
5
6
public SceneRender() {
shaderProgram = new ShaderProgram();
transformation = new Transformation();
[...]
uniforms.createUniform("worldMatrix");
}

在修改一下Scene.render()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void render(Scene scene) {
shaderProgram.bind();

// 更新投影矩阵
Matrix4f projectionMatrix = transformation.getProjectionMatrix(Projection.FOV, Window.getWidth(), Window.getHeight(), Projection.Z_NEAR, Projection.Z_FAR);
uniforms.setUniform("projectionMatrix", projectionMatrix);

scene.getEntities().forEach(entity -> {
Matrix4f worldMatrix =
transformation.getWorldMatrix(
entity.getPosition(),
entity.getRotation(),
entity.getScale());
uniforms.setUniform("worldMatrix", worldMatrix);
// 为该游戏项渲染网格
entity.getMesh().render();
});

// 还原状态
glBindVertexArray(0);

shaderProgram.unbind();
}

Mesh中添加render()

1
2
3
4
5
6
7
public void render() {
// 绑定VAO
glBindVertexArray(getVaoId());

// 绘制顶点
glDrawElements(GL_TRIANGLES, getVerticesCount(), GL_UNSIGNED_INT, 0);
}

再修改一下顶点着色器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#version 330

layout (location=0) in vec3 position;
layout (location=1) in vec3 inColour;

out vec3 exColour;

uniform mat4 worldMatrix;
uniform mat4 projectionMatrix;

void main()
{
gl_Position = projectionMatrix * worldMatrix * vec4(position, 1.0);
exColour = inColour;
}

最后再ILogic中添加update(),并在渲染前调用。

测试一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import com.game.*;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.system.MemoryUtil;

import java.nio.FloatBuffer;

import static org.lwjgl.opengl.GL30.*;

public class TestLogic implements ILogic {

Entity entity;

@Override
public void init() {
float[] vertices = new float[] {
// VO
-0.5f, 0.5f, 0.5f,
// V1
-0.5f, -0.5f, 0.5f,
// V2
0.5f, -0.5f, 0.5f,
// V3
0.5f, 0.5f, 0.5f,
// V4
-0.5f, 0.5f, -0.5f,
// V5
0.5f, 0.5f, -0.5f,
// V6
-0.5f, -0.5f, -0.5f,
// V7
0.5f, -0.5f, -0.5f,
};

float[] colors = new float[]{
0.5f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.5f,
0.0f, 0.5f, 0.5f,
0.5f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.5f,
0.0f, 0.5f, 0.5f,
};
int[] indices = new int[] {
// 前面
0, 1, 3, 3, 1, 2,
// 上面
4, 0, 3, 5, 4, 3,
// 右面
3, 2, 7, 5, 3, 7,
// 左面
6, 1, 0, 6, 0, 4,
// 下面
2, 1, 6, 2, 6, 7,
// 后面
7, 6, 4, 7, 4, 5,
};

Mesh mesh = new Mesh(vertices, colors, indices);
entity = new Entity(mesh);
entity.setPosition(0, 0, -2);
Engine.scene.addEntity(entity);
}

@Override
public void update() {
// 更新旋转角
float rotation = entity.getRotation().x + 1.5f;
if ( rotation > 360 ) {
rotation = 0;
}
entity.setRotation(rotation, rotation, rotation);
}

[...]
}

运行结果

WTF???

立方体之所以出现这个现象,是因为组成立方体的三角形是以一种随机顺序绘制的。事实上距离较远的像素应该在距离较近的像素之前绘制,而不是现在这样。为了修复它,必须启用深度测试(Depth Test)。

Window.init()中添加glEnable(GL_DEPTH_TEST);

运行结果

旋转的时候会发现速度随帧数变化而变化,循环还需改进。


LWJGL教程09 - 世界
https://panxy02.github.io/2024/07/19/lwjgl-09/
作者
52Hertz
发布于
2024年7月19日
许可协议