无法渲染简单的顶点数组
Unable to render simple vertex array
我正在将一款 2D 游戏从旧版 -> 现代 OpenGL 迁移过来。对我来说,这意味着使用着色器和顶点数组而不是 glProjection
、glOrtho
和 glBegin
/ glEnd
.
我已将相关代码精简为一个非常基本的示例。相机在 (0, 0, -1) 处看着 (0, 0, 0),我正在尝试绘制一个带点的三角形:
(0, 0, 0)
X
| '
| '
| '
X-------X
(0, 1, 0) (1, 1, 0)
即使使用将所有片段渲染为白色的非常简单的着色器,我也看不到这个三角形,只看到闪烁的背景颜色。
代码
package client.render.opengl;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import client.res.gfx.ScreenShader;
public class RenderingTest {
private static final int NUM_VERTICES = 3;
private static long window;
private static int shaderProgram;
private static int vao;
private static int uniformLoc;
private static Matrix4f viewProjMatrix = new Matrix4f();
private static FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);
public static void main(String[] args) throws IOException {
init();
while (!GLFW.glfwWindowShouldClose(window)) {
GLFW.glfwPollEvents();
render();
GLFW.glfwSwapBuffers(window);
}
}
private static void init() throws IOException {
// Setup an error callback
GLFW.glfwSetErrorCallback(
GLFWErrorCallback.createPrint(System.err)
);
// Initialise GLFW
if (!GLFW.glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
// Create window
window = GLFW.glfwCreateWindow(800, 600, "test", 0, 0);
GLFW.glfwMakeContextCurrent(window);
GL.createCapabilities();
GLFW.glfwShowWindow(window);
// Load shader
// Assume this code is good for now, it's too long to post here
ScreenShader.initialise();
shaderProgram = ScreenShader.shader.getProgram();
uniformLoc = ScreenShader.shader.getUniformLoc(ScreenShader.UNIFORM_VIEW_PROJ_MATRIX);
// Define our vertices
ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(NUM_VERTICES * 2 * Float.BYTES);
vertexBuffer.putFloat(0).putFloat(0); // Vertex 1
vertexBuffer.putFloat(0).putFloat(1); // Vertex 2
vertexBuffer.putFloat(1).putFloat(1); // Vertex 3
vertexBuffer.flip();
// Create VAO
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
// Create VBO and fill it with vertex positions
int vboIdPositions = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboIdPositions);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexBuffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); // Deselect
// Unbind the VAO
GL30.glBindVertexArray(0);
}
public static void render() {
// Render a random background to prove the loop is working
GL11.glClearColor(
(float) (Math.random() * 0.2f),
(float) (Math.random() * 0.2f),
(float) (Math.random() * 0.2f),
1.0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
// Use shader
GL20.glUseProgram(shaderProgram);
// Get camera position
float cameraX = 0;
float cameraY = 0;
// Set view and projection
viewProjMatrix
.setOrtho(
0,
800,
600,
0,
0.01f,
10
).lookAt(
cameraX, cameraY, -1, // Camera position
cameraX, cameraY, 0, // Camera "look" vector
0, 1, 0 // Camera "up" vector
);
// Pass this matrix to our shader
GL20.glUniformMatrix4fv(uniformLoc, false, viewProjMatrix.get(fb16));
// Bind our vertex array
GL30.glBindVertexArray(vao);
// Enable vertex attributes
GL20.glEnableVertexAttribArray(0);
// Draw the vertices
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, NUM_VERTICES);
// Disable vertex attributes
GL20.glDisableVertexAttribArray(0);
// Unbind vertex array
GL30.glBindVertexArray(0);
// Release shader
GL20.glUseProgram(0);
}
}
顶点着色器
#version 330
uniform mat4 view_proj_matrix;
layout(location = 0) in vec2 in_vertex;
void main(void) {
gl_Position = view_proj_matrix * vec4(in_vertex, 0, 1);
}
片段着色器
#version 330
out vec4 frag_colour;
void main(void) {
frag_colour = vec4(1, 1, 1, 1);
}
我不知道如何进步,因为我什至无法让这个玩具示例工作。任何人都可以看到我做错了什么,或者给我指出一个使用 JOML 与 LWJGL2 和着色器的工作示例吗?
您的着色器需要 OpenGL 3.3 版。要使用 GLFW
使用此版本创建核心配置文件,您可以调用:
GLFW.glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFW.glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = GLFW.glfwCreateWindow(800, 600, "test", 0, 0);
此外,您似乎按逆时针顺序传递顶点。因为glCullFace
的默认值是back
,这意味着你想看到的一面没有被渲染。更改顶点顺序或使用 glCullFace
、
使用您的视图和投影矩阵,三角形的大小为 1 个像素,并且在左侧超出屏幕范围。
如果您的三角形的坐标为 (0, 0, 0), (0, 1, 0), (1, 1, 0),则您的 window 的大小为 (800, 600)然后你设置了一个正射投影链接:
viewProjMatrix.setOrtho(0, 800, 600, 0, 0.01f, 10)
三角形在屏幕上的大小为 1 个像素。
您必须更改正交投影:
float aspect = 800.0f/600.0f;
viewProjMatrix.setOrtho(-aspect, aspect, 1, -1, 0.01f, 10)
注意,投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。在正交投影中,视图 space 中的坐标线性映射到剪辑 space 坐标。
Made it 100x bigger, still no sign of it!
如果你只是将三角形三角形缩放到 (0, 0, 0), (0, 100, 0), (100, 100, 0),你也不会看到三角形,因为视图矩阵:
lookAt(0, 0, -1, 0, 0, 0, 0, 1, 0 );
使用此视图矩阵,x 轴在 Right-handed 坐标系中反转。视图坐标系描述了观察场景的方向和位置。视图矩阵从世界 space 转换为视图(眼睛)space。在视图 space 中,X 轴指向左侧,Y 轴指向上方,Z 轴指向视图外(请注意,在右手系统中,Z 轴是 X 轴的叉积轴和 Y 轴)。
您的视图定义如下
position = (0, 0, -1)
center = (0, 0, 0)
up = (0, 1, 0)
y轴和z轴是这样的:
y-axis = up = (0, 1, 0)
z-axis = position - center = (0, 0, -1)
x轴是y轴和z轴的叉积:
x-axis = cross(y-axis, z-axis) = (-1, 0, 0)
这意味着,你看三角形的背面。这会导致三角形 "flipped" 超出视口。它被画在屏幕的左边,所以你看不到它:
(0, 0)
X---------------------------x
/ | |
/ | |
X-----X |
(-100, 100) | viewport |
| |
| |
| |
x---------------------------x
(800, 600)
反转视线解决问题:
lookAt(0, 0, 1, 0, 0, 0, 0, 1, 0 );
我正在将一款 2D 游戏从旧版 -> 现代 OpenGL 迁移过来。对我来说,这意味着使用着色器和顶点数组而不是 glProjection
、glOrtho
和 glBegin
/ glEnd
.
我已将相关代码精简为一个非常基本的示例。相机在 (0, 0, -1) 处看着 (0, 0, 0),我正在尝试绘制一个带点的三角形:
(0, 0, 0)
X
| '
| '
| '
X-------X
(0, 1, 0) (1, 1, 0)
即使使用将所有片段渲染为白色的非常简单的着色器,我也看不到这个三角形,只看到闪烁的背景颜色。
代码
package client.render.opengl;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import client.res.gfx.ScreenShader;
public class RenderingTest {
private static final int NUM_VERTICES = 3;
private static long window;
private static int shaderProgram;
private static int vao;
private static int uniformLoc;
private static Matrix4f viewProjMatrix = new Matrix4f();
private static FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);
public static void main(String[] args) throws IOException {
init();
while (!GLFW.glfwWindowShouldClose(window)) {
GLFW.glfwPollEvents();
render();
GLFW.glfwSwapBuffers(window);
}
}
private static void init() throws IOException {
// Setup an error callback
GLFW.glfwSetErrorCallback(
GLFWErrorCallback.createPrint(System.err)
);
// Initialise GLFW
if (!GLFW.glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
// Create window
window = GLFW.glfwCreateWindow(800, 600, "test", 0, 0);
GLFW.glfwMakeContextCurrent(window);
GL.createCapabilities();
GLFW.glfwShowWindow(window);
// Load shader
// Assume this code is good for now, it's too long to post here
ScreenShader.initialise();
shaderProgram = ScreenShader.shader.getProgram();
uniformLoc = ScreenShader.shader.getUniformLoc(ScreenShader.UNIFORM_VIEW_PROJ_MATRIX);
// Define our vertices
ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(NUM_VERTICES * 2 * Float.BYTES);
vertexBuffer.putFloat(0).putFloat(0); // Vertex 1
vertexBuffer.putFloat(0).putFloat(1); // Vertex 2
vertexBuffer.putFloat(1).putFloat(1); // Vertex 3
vertexBuffer.flip();
// Create VAO
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
// Create VBO and fill it with vertex positions
int vboIdPositions = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboIdPositions);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexBuffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); // Deselect
// Unbind the VAO
GL30.glBindVertexArray(0);
}
public static void render() {
// Render a random background to prove the loop is working
GL11.glClearColor(
(float) (Math.random() * 0.2f),
(float) (Math.random() * 0.2f),
(float) (Math.random() * 0.2f),
1.0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
// Use shader
GL20.glUseProgram(shaderProgram);
// Get camera position
float cameraX = 0;
float cameraY = 0;
// Set view and projection
viewProjMatrix
.setOrtho(
0,
800,
600,
0,
0.01f,
10
).lookAt(
cameraX, cameraY, -1, // Camera position
cameraX, cameraY, 0, // Camera "look" vector
0, 1, 0 // Camera "up" vector
);
// Pass this matrix to our shader
GL20.glUniformMatrix4fv(uniformLoc, false, viewProjMatrix.get(fb16));
// Bind our vertex array
GL30.glBindVertexArray(vao);
// Enable vertex attributes
GL20.glEnableVertexAttribArray(0);
// Draw the vertices
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, NUM_VERTICES);
// Disable vertex attributes
GL20.glDisableVertexAttribArray(0);
// Unbind vertex array
GL30.glBindVertexArray(0);
// Release shader
GL20.glUseProgram(0);
}
}
顶点着色器
#version 330
uniform mat4 view_proj_matrix;
layout(location = 0) in vec2 in_vertex;
void main(void) {
gl_Position = view_proj_matrix * vec4(in_vertex, 0, 1);
}
片段着色器
#version 330
out vec4 frag_colour;
void main(void) {
frag_colour = vec4(1, 1, 1, 1);
}
我不知道如何进步,因为我什至无法让这个玩具示例工作。任何人都可以看到我做错了什么,或者给我指出一个使用 JOML 与 LWJGL2 和着色器的工作示例吗?
您的着色器需要 OpenGL 3.3 版。要使用 GLFW
使用此版本创建核心配置文件,您可以调用:
GLFW.glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFW.glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = GLFW.glfwCreateWindow(800, 600, "test", 0, 0);
此外,您似乎按逆时针顺序传递顶点。因为glCullFace
的默认值是back
,这意味着你想看到的一面没有被渲染。更改顶点顺序或使用 glCullFace
、
使用您的视图和投影矩阵,三角形的大小为 1 个像素,并且在左侧超出屏幕范围。
如果您的三角形的坐标为 (0, 0, 0), (0, 1, 0), (1, 1, 0),则您的 window 的大小为 (800, 600)然后你设置了一个正射投影链接:
viewProjMatrix.setOrtho(0, 800, 600, 0, 0.01f, 10)
三角形在屏幕上的大小为 1 个像素。
您必须更改正交投影:
float aspect = 800.0f/600.0f;
viewProjMatrix.setOrtho(-aspect, aspect, 1, -1, 0.01f, 10)
注意,投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。在正交投影中,视图 space 中的坐标线性映射到剪辑 space 坐标。
Made it 100x bigger, still no sign of it!
如果你只是将三角形三角形缩放到 (0, 0, 0), (0, 100, 0), (100, 100, 0),你也不会看到三角形,因为视图矩阵:
lookAt(0, 0, -1, 0, 0, 0, 0, 1, 0 );
使用此视图矩阵,x 轴在 Right-handed 坐标系中反转。视图坐标系描述了观察场景的方向和位置。视图矩阵从世界 space 转换为视图(眼睛)space。在视图 space 中,X 轴指向左侧,Y 轴指向上方,Z 轴指向视图外(请注意,在右手系统中,Z 轴是 X 轴的叉积轴和 Y 轴)。
您的视图定义如下
position = (0, 0, -1)
center = (0, 0, 0)
up = (0, 1, 0)
y轴和z轴是这样的:
y-axis = up = (0, 1, 0)
z-axis = position - center = (0, 0, -1)
x轴是y轴和z轴的叉积:
x-axis = cross(y-axis, z-axis) = (-1, 0, 0)
这意味着,你看三角形的背面。这会导致三角形 "flipped" 超出视口。它被画在屏幕的左边,所以你看不到它:
(0, 0)
X---------------------------x
/ | |
/ | |
X-----X |
(-100, 100) | viewport |
| |
| |
| |
x---------------------------x
(800, 600)
反转视线解决问题:
lookAt(0, 0, 1, 0, 0, 0, 0, 1, 0 );