JOGL OpenGL 只在奇怪的条件下渲染
JOGL OpenGL only rendering under weird conditions
我目前正在尝试让一个非常简单的程序运行。它只是在黑色背景上显示一个白色十字。问题是我的十字架的渲染只在奇怪的条件下工作。这些是我到目前为止发现的所有条件:
- 顶点着色器位置输入的布局必须大于2
- 即使在调用
glBindVertexArray(array)
后,对 glBindVertexArray(0)
的任何调用都会导致十字不呈现
- 我必须在每次绘制调用之前调用
glUseProgram
如您所见,我不知道这里到底发生了什么。我该如何修复这个错误?
代码如下:
int axesVBO;
int axesVAO;
int vert, frag;
int program;
@Override
public void display(GLAutoDrawable drawable) {
System.out.println("Render");
GL4 gl = drawable.getGL().getGL4();
gl.glClear(GL4.GL_COLOR_BUFFER_BIT | GL4.GL_DEPTH_BUFFER_BIT);
gl.glBindVertexArray(axesVAO);
gl.glUseProgram(program); //Doesnt work without
gl.glDrawArrays(GL4.GL_LINES, 0, 2);
gl.glDrawArrays(GL4.GL_LINES, 2, 2);
gl.glBindVertexArray(0); //After this line the cross isn't renderd anymore
}
@Override
public void dispose(GLAutoDrawable drawable) {
GL4 gl = drawable.getGL().getGL4();
gl.glDeleteBuffers(1, IntBuffer.wrap(new int[]{axesVBO}));
gl.glDeleteVertexArrays(1, IntBuffer.wrap(new int[]{axesVAO}));
gl.glDeleteProgram(program);
gl.glDeleteShader(vert);
gl.glDeleteShader(frag);
}
@Override
public void init(GLAutoDrawable drawable) {
System.out.println("Init");
GL4 gl = drawable.getGL().getGL4();
IntBuffer buffer = Buffers.newDirectIntBuffer(2);
gl.glGenBuffers(1, buffer);
axesVBO = buffer.get(0);
vert = gl.glCreateShader(GL4.GL_VERTEX_SHADER);
frag = gl.glCreateShader(GL4.GL_FRAGMENT_SHADER);
gl.glShaderSource(vert, 1, new String[]{"#version 410\n in vec2 pos;void main() {gl_Position = vec4(pos, 0, 1);}"}, null);
gl.glShaderSource(frag, 1, new String[]{"#version 410\n out vec4 FragColor;void main() {FragColor = vec4(1, 1, 1, 1);}"}, null);
gl.glCompileShader(vert);
gl.glCompileShader(frag);
if(GLUtils.getShaderiv(gl, vert, GL4.GL_COMPILE_STATUS) == GL.GL_FALSE) {
System.out.println("Vertex shader compilation failed:");
System.out.println(GLUtils.getShaderInfoLog(gl, vert));
} else {
System.out.println("Vertex shader compilation sucessfull");
}
if(GLUtils.getShaderiv(gl, frag, GL4.GL_COMPILE_STATUS) == GL.GL_FALSE) {
System.out.println("Fragment shader compilation failed:");
System.out.println(GLUtils.getShaderInfoLog(gl, frag));
} else {
System.out.println("Fragment shader compilation sucessfull");
}
program = gl.glCreateProgram();
gl.glAttachShader(program, vert);
gl.glAttachShader(program, frag);
gl.glBindAttribLocation(program, 2, "pos"); //Only works when location is > 2
gl.glLinkProgram(program);
if(GLUtils.getProgramiv(gl, program, GL4.GL_LINK_STATUS) == GL.GL_FALSE) {
System.out.println("Program linking failed:");
System.out.println(GLUtils.getProgramInfoLog(gl, program));
} else {
System.out.println("Program linking sucessfull");
}
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, axesVBO);
gl.glBufferData(GL4.GL_ARRAY_BUFFER, Float.BYTES * 8, FloatBuffer.wrap(new float[]{-1f, 0, 1f, 0, 0, 1f, 0, -1f}), GL4.GL_STATIC_DRAW);
gl.glUseProgram(program);
buffer.clear();
gl.glGenVertexArrays(1, buffer);
axesVAO = buffer.get();
gl.glBindVertexArray(axesVAO);
int pos = gl.glGetAttribLocation(program, "pos");
gl.glEnableVertexAttribArray(pos);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, axesVBO);
gl.glVertexAttribPointer(pos, 2, GL4.GL_FLOAT, false, 0, 0);
//Commented out for testing reasons (doesnt work when active)
//gl.glBindVertexArray(0);
gl.glClearColor(0f, 0f, 0f, 1f);
}
你想出的条件看起来很奇怪。无论如何,总的来说,拥有干净简单的代码有助于避免讨厌的错误。从干净简单开始,然后逐步完善 :)
几个注意事项:
- 不要对 vbo 和 vao 使用
int
,直接使用直接缓冲区
- 不需要全局声明
vert
和 frag
如果它们仅在 init
中使用,请在方法中局部声明它们
- 更喜欢使用 jogl 实用程序生成直接缓冲区
GLBuffers.newDirect*Buffer(...)
- 至少在开始时,更喜欢使用 jogl 实用程序(
ShaderCode.create
和 ShaderProgram
)来编译您的着色器,它可以减轻您的工作和潜在错误的负担,并包括更深入的检查整个着色器创建过程中的任何步骤(有时甚至太多,但如今着色器编译速度如此之快并不重要)
- 如果你有
ARB_explicit_attrib_location
,你可以检查gl4.isExtensionAvailable("GL_ARB_explicit_attrib_location");
,在任何地方使用它,它会避免很多潜在的错误和任何类型的开销(例如glBindAttribLocation
和 glGetAttribLocation
)
- 最好将一个直接缓冲区传递给
glBufferData
,这样 jogl 就不必在下面自己创建它,您可以跟踪它以释放它
- 保持
init
干净且可读。你把很多东西混合在一起。例如你在开始时生成vbo,然后你创建程序,然后你上传数据到vbo。
gl.glUseProgram(program);
在 init
中毫无意义,除非您的想法是绑定它并使其保持绑定状态。无论如何,通常情况下,程序是渲染调用之前初始化阶段的一部分,因此最好将其移动到 display()
.
- 比
glClear
更喜欢glClearBuffer
gl.glDrawArrays(GL4.GL_LINES, 0, 2);
没有任何用处,因为您传递的顶点数为零
- 如果你需要灵感,看看这个Hello Triangle
我目前正在尝试让一个非常简单的程序运行。它只是在黑色背景上显示一个白色十字。问题是我的十字架的渲染只在奇怪的条件下工作。这些是我到目前为止发现的所有条件:
- 顶点着色器位置输入的布局必须大于2
- 即使在调用
glBindVertexArray(array)
后,对 - 我必须在每次绘制调用之前调用
glUseProgram
glBindVertexArray(0)
的任何调用都会导致十字不呈现
如您所见,我不知道这里到底发生了什么。我该如何修复这个错误?
代码如下:
int axesVBO;
int axesVAO;
int vert, frag;
int program;
@Override
public void display(GLAutoDrawable drawable) {
System.out.println("Render");
GL4 gl = drawable.getGL().getGL4();
gl.glClear(GL4.GL_COLOR_BUFFER_BIT | GL4.GL_DEPTH_BUFFER_BIT);
gl.glBindVertexArray(axesVAO);
gl.glUseProgram(program); //Doesnt work without
gl.glDrawArrays(GL4.GL_LINES, 0, 2);
gl.glDrawArrays(GL4.GL_LINES, 2, 2);
gl.glBindVertexArray(0); //After this line the cross isn't renderd anymore
}
@Override
public void dispose(GLAutoDrawable drawable) {
GL4 gl = drawable.getGL().getGL4();
gl.glDeleteBuffers(1, IntBuffer.wrap(new int[]{axesVBO}));
gl.glDeleteVertexArrays(1, IntBuffer.wrap(new int[]{axesVAO}));
gl.glDeleteProgram(program);
gl.glDeleteShader(vert);
gl.glDeleteShader(frag);
}
@Override
public void init(GLAutoDrawable drawable) {
System.out.println("Init");
GL4 gl = drawable.getGL().getGL4();
IntBuffer buffer = Buffers.newDirectIntBuffer(2);
gl.glGenBuffers(1, buffer);
axesVBO = buffer.get(0);
vert = gl.glCreateShader(GL4.GL_VERTEX_SHADER);
frag = gl.glCreateShader(GL4.GL_FRAGMENT_SHADER);
gl.glShaderSource(vert, 1, new String[]{"#version 410\n in vec2 pos;void main() {gl_Position = vec4(pos, 0, 1);}"}, null);
gl.glShaderSource(frag, 1, new String[]{"#version 410\n out vec4 FragColor;void main() {FragColor = vec4(1, 1, 1, 1);}"}, null);
gl.glCompileShader(vert);
gl.glCompileShader(frag);
if(GLUtils.getShaderiv(gl, vert, GL4.GL_COMPILE_STATUS) == GL.GL_FALSE) {
System.out.println("Vertex shader compilation failed:");
System.out.println(GLUtils.getShaderInfoLog(gl, vert));
} else {
System.out.println("Vertex shader compilation sucessfull");
}
if(GLUtils.getShaderiv(gl, frag, GL4.GL_COMPILE_STATUS) == GL.GL_FALSE) {
System.out.println("Fragment shader compilation failed:");
System.out.println(GLUtils.getShaderInfoLog(gl, frag));
} else {
System.out.println("Fragment shader compilation sucessfull");
}
program = gl.glCreateProgram();
gl.glAttachShader(program, vert);
gl.glAttachShader(program, frag);
gl.glBindAttribLocation(program, 2, "pos"); //Only works when location is > 2
gl.glLinkProgram(program);
if(GLUtils.getProgramiv(gl, program, GL4.GL_LINK_STATUS) == GL.GL_FALSE) {
System.out.println("Program linking failed:");
System.out.println(GLUtils.getProgramInfoLog(gl, program));
} else {
System.out.println("Program linking sucessfull");
}
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, axesVBO);
gl.glBufferData(GL4.GL_ARRAY_BUFFER, Float.BYTES * 8, FloatBuffer.wrap(new float[]{-1f, 0, 1f, 0, 0, 1f, 0, -1f}), GL4.GL_STATIC_DRAW);
gl.glUseProgram(program);
buffer.clear();
gl.glGenVertexArrays(1, buffer);
axesVAO = buffer.get();
gl.glBindVertexArray(axesVAO);
int pos = gl.glGetAttribLocation(program, "pos");
gl.glEnableVertexAttribArray(pos);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, axesVBO);
gl.glVertexAttribPointer(pos, 2, GL4.GL_FLOAT, false, 0, 0);
//Commented out for testing reasons (doesnt work when active)
//gl.glBindVertexArray(0);
gl.glClearColor(0f, 0f, 0f, 1f);
}
你想出的条件看起来很奇怪。无论如何,总的来说,拥有干净简单的代码有助于避免讨厌的错误。从干净简单开始,然后逐步完善 :)
几个注意事项:
- 不要对 vbo 和 vao 使用
int
,直接使用直接缓冲区 - 不需要全局声明
vert
和frag
如果它们仅在init
中使用,请在方法中局部声明它们 - 更喜欢使用 jogl 实用程序生成直接缓冲区
GLBuffers.newDirect*Buffer(...)
- 至少在开始时,更喜欢使用 jogl 实用程序(
ShaderCode.create
和ShaderProgram
)来编译您的着色器,它可以减轻您的工作和潜在错误的负担,并包括更深入的检查整个着色器创建过程中的任何步骤(有时甚至太多,但如今着色器编译速度如此之快并不重要) - 如果你有
ARB_explicit_attrib_location
,你可以检查gl4.isExtensionAvailable("GL_ARB_explicit_attrib_location");
,在任何地方使用它,它会避免很多潜在的错误和任何类型的开销(例如glBindAttribLocation
和glGetAttribLocation
) - 最好将一个直接缓冲区传递给
glBufferData
,这样 jogl 就不必在下面自己创建它,您可以跟踪它以释放它 - 保持
init
干净且可读。你把很多东西混合在一起。例如你在开始时生成vbo,然后你创建程序,然后你上传数据到vbo。 gl.glUseProgram(program);
在init
中毫无意义,除非您的想法是绑定它并使其保持绑定状态。无论如何,通常情况下,程序是渲染调用之前初始化阶段的一部分,因此最好将其移动到display()
.- 比
glClear
更喜欢glClearBuffer
gl.glDrawArrays(GL4.GL_LINES, 0, 2);
没有任何用处,因为您传递的顶点数为零- 如果你需要灵感,看看这个Hello Triangle