英文:
OpenGL send me a Stack Underflow error when i am trying to use shaders (Java)
问题
以下是您要翻译的内容:
我正在使用Java中的lwjgl 3开发游戏,一切正常,但当我想使用着色器时,OpenGL发送了一个STACK_UNDERFLOW错误(1284)。
我正在使用3个缓冲区:顶点缓冲区、颜色缓冲区、索引缓冲区。
我的旧代码:
// 代码部分已略过
在添加着色器后的新代码:
// 代码部分已略过
我的着色器:
顶点着色器:
#version 410
layout (location=0) in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
}
片段着色器:
#version 410
out vec4 vertColor;
void main(){
gl_FragColor = vertColor;
}
请注意,这里只返回翻译的代码部分,不包含问题的回答或其他内容。
英文:
I am developping a game with lwjgl 3 in java and it was working fine but when i want to use shaders, OpenGL send a STACK_UNDERFLOW error (1284).
I am using 3 buffers: vertex buffer, color buffer, index buffer;
My old code:
private int vbo;
private int cbo;
private int ibo;
private FloatBuffer buffer;
private FloatBuffer colorBuffer;
private IntBuffer indexBuffer;
private IcoSphere sphere;
int radius = 200;
@Override
public void init() {
sphere = new IcoSphere(9, radius);
sphere.generate();
generateBuffer();
}
private void generateBuffer() {
buffer = BufferUtils.createFloatBuffer(sphere.getVertexCount() * 3);
colorBuffer = BufferUtils.createFloatBuffer(sphere.getFacesCount() * 4 * 4);
indexBuffer = BufferUtils.createIntBuffer(sphere.getFacesCount());
Random r = new Random();
OpenSimplexNoise noise = new OpenSimplexNoise();
ArrayList<Vector3f> vertex = sphere.getVertex();
float[] v = new float[vertex.size() * 3];
for (int i = 0; i < vertex.size(); i++) {
vertex.get(i).normalize();
vertex.get(i).mul(sphere.getRadius() + (float) noise.eval(
vertex.get(i).x * 8,
vertex.get(i).y * 8,
vertex.get(i).z * 8
) * 12);
v[i * 3 + 0] = vertex.get(i).x;
v[i * 3 + 1] = vertex.get(i).y;
v[i * 3 + 2] = vertex.get(i).z;
}
buffer.put(sphere.getVertexArray());
indexBuffer.put(sphere.getIndexArray());
for (int i = 0; i < sphere.getFacesCount(); i++) {
colorBuffer.put(new float[] {
r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
r.nextFloat(), r.nextFloat(), r.nextFloat(), 1
});
}
buffer.flip();
colorBuffer.flip();
indexBuffer.flip();
createBuffer();
}
private void createBuffer() {
vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
@Override
public void update() {
}
@Override
public void render() {
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
My new code after adding shaders:
GlUtils.glCall(() -> ..);
is for catching opengl errors.
private int vbo;
private int cbo;
private int ibo;
private FloatBuffer buffer;
private FloatBuffer colorBuffer;
private IntBuffer indexBuffer;
private IcoSphere sphere;
int radius = 200;
@Override
public void init() {
sphere = new IcoSphere(9, radius);
sphere.generate();
generateBuffer();
}
private void generateBuffer() {
buffer = BufferUtils.createFloatBuffer(sphere.getVertexCount() * 3);
colorBuffer = BufferUtils.createFloatBuffer(sphere.getFacesCount() * 4 * 4);
indexBuffer = BufferUtils.createIntBuffer(sphere.getFacesCount());
Random r = new Random();
OpenSimplexNoise noise = new OpenSimplexNoise();
ArrayList<Vector3f> vertex = sphere.getVertex();
float[] v = new float[vertex.size() * 3];
for (int i = 0; i < vertex.size(); i++) {
vertex.get(i).normalize();
vertex.get(i).mul(sphere.getRadius() + (float) noise.eval(
vertex.get(i).x * 8,
vertex.get(i).y * 8,
vertex.get(i).z * 8
) * 12);
v[i * 3 + 0] = vertex.get(i).x;
v[i * 3 + 1] = vertex.get(i).y;
v[i * 3 + 2] = vertex.get(i).z;
}
buffer.put(sphere.getVertexArray());
indexBuffer.put(sphere.getIndexArray());
for (int i = 0; i < sphere.getFacesCount(); i++) {
colorBuffer.put(new float[] {
r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
r.nextFloat(), r.nextFloat(), r.nextFloat(), 1,
r.nextFloat(), r.nextFloat(), r.nextFloat(), 1
});
}
buffer.flip();
colorBuffer.flip();
indexBuffer.flip();
createBuffer();
}
private void createBuffer() {
vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();
GlUtils.glCall(() -> glBindBuffer(GL_ARRAY_BUFFER, vbo));
GlUtils.glCall(() -> glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW));
GlUtils.glCall(() -> glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0));
GlUtils.glCall(() -> glBindBuffer(GL_ARRAY_BUFFER, cbo));
GlUtils.glCall(() -> glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW));
GlUtils.glCall(() -> glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0));
GlUtils.glCall(() -> glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo));
GlUtils.glCall(() -> glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW));
GlUtils.glCall(() -> glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
GlUtils.glCall(() -> glBindBuffer(GL_ARRAY_BUFFER, 0));
}
@Override
public void update() {
}
@Override
public void render() {
Shader.MAIN.bind();
GlUtils.glCall(() -> glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0));
GlUtils.glCall(() -> glEnableVertexAttribArray(0));
GlUtils.glCall(() -> glEnableVertexAttribArray(1));
GlUtils.glCall(() -> glDrawElements(GL_TRIANGLES, indexBuffer));
GlUtils.glCall(() -> glDisableVertexAttribArray(0));
GlUtils.glCall(() -> glDisableVertexAttribArray(1));
Shader.MAIN.unbind();
}
My shaders:
Frag
#version 410
out vec4 vertColor;
void main(){
gl_FragColor = vertColor;
}
Vert
#version 410
layout (location=0) in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
}
答案1
得分: 0
以下是翻译好的部分:
当您使用着色器程序时,您可以通过使用客户端功能来绘制网格,与之前的方式相同。
您所需要做的就是使用glEnableVertexAttribArray
和glVertexAttribPointer
,而不是glEnableClientState
、glVertexPointer
和glColorPointer
:
创建缓冲区:
vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);
绘制网格:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
您实际上所做的是使用默认的顶点数组对象(0)来进行规范。请注意,默认的VAO(0)仅在兼容性配置OpenGL上下文中有效。
通过使用一个命名的顶点数组对象,可以改进此过程。请注意,在核心配置OpenGL上下文中必须使用命名的VAO:
private int vao;
vao = glGenVertexArrays();
vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);
glBindVertexArray(0);
顶点数组的规范已在顶点数组对象中声明。因此,无需使用glDisableVertexAttribArray
。
此外,索引缓冲区(GL_ELEMENT_ARRAY_BUFFER
)也在VAO中声明。glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
将会中断绑定。
现在,只需要在绘制网格时绑定VAO即可:
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
您有两个颜色属性,顶点坐标和颜色。这两个属性是顶点着色器的输入。顶点坐标用于设置gl_Position
。颜色必须传递给片段着色器。它是顶点着色器的输出和片段着色器的输入。在片段着色器中,颜色写入输出fragColor
。片段着色器的输出被写入帧缓冲:
顶点着色器:
layout (location=0) in vec3 position;
layout (location=1) in vec4 color;
out vec4 vertColor;
void main()
{
vertColor = color;
gl_Position = vec4(position, 1.0);
}
片段着色器:
#version 410
in vec4 vertColor;
out vec4 fragColor;
void main()
{
fragColor = vertColor;
}
英文:
When you use a shader program, then you can draw the mesh the same way as you did it before, by using the client side capabilities.
All you have to do is to use glEnableVertexAttribArray
and glVertexAttribPointer
instead of glEnableClientState
, glVertexPointer
and glColorPointer
:
Create the buffers:
vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);
Draw the mesh
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
What you actually do is to use default Vertex Array Object (0) for the specification. Note, the default VAO (0) is just valid in a compatibility profile OpenGL Context.
That can be improved by using a named Vertex Array Object. Note, you have to use a named VAO in a core profile OpenGL Context:
private int vao;
vao = glGenVertexArrays();
vbo = glGenBuffers();
cbo = glGenBuffers();
ibo = glGenBuffers();
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, colorBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);
glBindVertexArray(0);
The vertex array specification is stated in the vertex array object. Thus there is no need ofglDisableVertexAttribArray
.
Furthermore the Index buffers (GL_ELEMENT_ARRAY_BUFFER
) is stated in the VAO, too. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
would break the binding.
Now it is sufficient to bind the VAO when the mesh is drawn:
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, sphere.getFacesCount() * 3, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
You have 2 color attributes, the vertex coordinate and the color. This 2 attributes are the input to the Vertex Shader. The vertex coordinate is used to set gl_Position
. The color has to be passed to the Fragment Shader. It is an output of the vertex shader and an input to the fragment shader. In the fragment shader the color is written to the output fragColor
. The output of the fragment shader is written to the frambuffer:
Vertex Shader:
layout (location=0) in vec3 position;
layout (location=1) in vec4 color;
out vec4 vertColor;
void main()
{
vertColor = color;
gl_Position = vec4(position, 1.0);
}
Fragment Shader:
#version 410
in vec4 vertColor;
out vec4 fragColor;
void main()
{
fragColor = vertColor;
}
专注分享java语言的经验与见解,让所有开发者获益!
评论