我试图做一些非常简单的事情,我感到非常沮丧。我已经设置了一个简单的顶点着色器,因为显然你现在需要一个让OpenGL做任何事情或者可怕的弃用神对你皱眉的东西:
#version 110
uniform mat4 scene_matrix;
attribute vec4 a_position;
void main()
{
gl_Position = scene_matrix * a_position;
}
奇妙。在捣乱10个小时以创建一个合适的矩阵后,我将其传递到着色器glUniformMatrix4
并且它的工作非常好。也就是说,直到我想渲染多个THING。
所以我的目标是:对于场景中的每个对象,我根据对象的坐标计算适当的世界矩阵,调用glUniformMatrix4
告诉顶点着色器关于矩阵,调用glBegin()
,然后绘制愚蠢的对象,并调用glEnd()
。不幸的是,它可怜地在同一个愚蠢的地方(最后一个物体的位置)绘制所有物体。显然它是懒惰的缓冲事物,并且直到最后都没有运行顶点着色器,因为它已经忘记了以前的矩阵。但是我怎么告诉它不要这样做?
FloatBuffer matrixBuf = ByteBuffer.allocateDirect(16 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
for (int i = 0; i < 500; i++) {
matrixBuf.rewind();
matrices.world.translate(0.1, 0.1, 0.5);
matrices.calc();
matrices.combined.put(matrixBuf);
matrixBuf.rewind();
glUniformMatrix4(glGetUniformLocation(programId, "scene_matrix"), false, matrixBuf);
glBegin(GL_TRIANGLES);
{
//final int T = 1;
final float z = 0f;
final float R = 0.5f;
//glVertexAttrib2f(T, 0, 1);
glVertex3f(-R, -R, z);
//glVertexAttrib2f(T, 1, 0);
glVertex3f(R, R, z);
//glVertexAttrib2f(T, 0, 0);
glVertex3f(-R, R, z);
/*//glVertexAttrib2f(T, 0, 1);
glVertex3f(-R, -R, z);
//glVertexAttrib2f(T, 1, 1);
glVertex3f(R, -R, z);
//glVertexAttrib2f(T, 1, 0);
glVertex3f(R, R, z);*/
}
glEnd();
//glFlush(); // without this, all the triangles are in the same place
}
我发现在每个glFlush()
之后调用glEnd()
可以解决问题。但是,这会导致性能问题。我只绘制了500个物体(每个物体都是一个可怜的三角形)并且它已经最大化了CPU并且电脑中出现了电容器呜呜声。感觉不对。我确定glFlush()
必须是矫枉过正。
我发现在glLinkProgram(programId);
之后用glUniformMatrix4
重新安排程序也可以解决问题,但它仍然会慢一个数量级。
我到处都看。我只想知道用于告诉它的函数的名称是什么,然后运行顶点着色器 ,然后我可以重新配置下一个对象的制服。
或者这不是我应该做的事情?我应该放弃顶点管道,在Java端进行顶点的所有矩阵变换并传入已经变换的顶点吗?我应该屈服于弃用恶魔并使用传统的OpenGL矩阵堆栈来判断它是否更合作?任何帮助表示赞赏。
答案 0 :(得分:4)
您犯的第一个重大错误就是使用glBegin
/ glEnd
。这已经与固定功能管道一起弃用。
为什么你看到所有对象都被绘制在同一个地方的原因:因为你的变换矩阵在循环变量下是不变的,即循环的迭代对你的变换矩阵的值没有影响:这个块在这里:
matrixBuf.rewind();
matrices.world.translate(0.1, 0.1, 0.5);
matrices.calc();
matrices.combined.put(matrixBuf);
matrixBuf.rewind();
必须依赖于i
某种方式,或 matrices.combined
实际上会与翻译结合使用,但是方法名称.put
会明确表示,它只是被替换了。
答案 1 :(得分:1)
许多状态更改要求您在对象对渲染管道可见之前对其进行绑定。
对于着色器绑定意味着glUseProgram。我不记得什么规范说制服和重复使用着色器。
使用glDrawArrays很简单。您只需将顶点数据设置为数组即可。启用并设置glVertexAttribPointer。在简单的示例情况下,您甚至不必使用缓冲区对象。您可以将glEnableVertexAttribArray视为glBegin。然后将数据放入顶点数组作为对glVertex *()的调用。 glVertexAttribPointer和glDraw *()可以像glEnd一样强硬。
对简单DrawArrays的优化是使用带有DrawElements的索引来避免数据中的重复顶点。然后将顶点和索引放到缓冲对象中会使一切变得快速。
奖励:这个案例看起来有点像你可以跳过矩阵来简化你的制服到翻译矢量。
答案 2 :(得分:0)
所以根据评论的答案是:没有这样的函数调用;这应该是自然而然的。
那为什么不呢?主知道。可能是一个有缺陷的司机,可能是我的傻瓜,可能两者兼而有之。在任何情况下,如果我使用glDrawArrays
或glDrawElements
而不是像glVertex3
这样的固定功能管道调用,问题会立即完全消失。 (是的,这绝对是我改变在工作和不工作之间切换它的唯一方法。)对于那些在淹没之前一直试图从浅薄的事物开始的人来说,这不是一个很好的体验除非你已经知道他们做什么API,否则所有记录不佳的人的权重。
我发现这个很好的Stack Overflow帖子总结了这些顶点规范函数的功能:https://stackoverflow.com/a/8705304
以下是此处参考的图纸代码:
顶点着色器:
#version 110
uniform mat4 scene_matrix;
attribute vec4 a_position;
attribute vec2 a_texcoord;
varying vec2 v_texcoord;
void main()
{
gl_Position = scene_matrix * a_position;
// pass texture coordinates on to fragment shader
v_texcoord = a_texcoord;
}
片段着色器:
#version 110
uniform sampler2D texture;
varying vec2 v_texcoord;
void main()
{
gl_FragColor = texture2D(texture, v_texcoord);
//gl_FragColor = vec4(1, 0, 0, 1);
}
绘制一个东西的代码:
// Define a shape (a square)
// First 3 numbers on each line are vertex coords, next 2 are corresponding tex coords
final float R = 0.5f;
float[] vertices = {
-R, -R, 0, 0, 1,
+R, +R, 0, 1, 0,
-R, +R, 0, 0, 0,
-R, -R, 0, 0, 1,
+R, -R, 0, 1, 1,
+R, +R, 0, 1, 0,
};
// Create and bind a buffer object
int bufferId = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, bufferId);
// Just Java fluff: local buffer used for transferring data to the native method
FloatBuffer vertices1 = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertices1.put(vertices);
vertices1.rewind();
// Load the vertices into the proper buffer
glBufferData(GL_ARRAY_BUFFER, vertices1, GL_STREAM_DRAW);
// Define layout of data in buffer:
// First, vertex coords (attrib "0"):
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 5 * 4, 0 * 4);
// The last 2 params to glVertexAttribPointer are stride and offset.
// Stride tells the total number of bytes between the start of one vertex
// and the start of the next, 5 * 4 because the data rows above have 5 elements
// and each element is a 4-byte float.
// Offset tells the byte offset of the start of the first element in the buffer,
// 0 * 4 because our coord data begins right at the beginning of the buffer.
// Now, tex coords (attrib "1"):
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 5 * 4, 3 * 4);
// Stride is the same as above, but need non-zero offset because the tex
// coords start after the 3 vertex coords in each row of data in the buffer.
// Call glDrawArrays as many times as you want to repeatedly,
// possibly with different uniform values, and with no need
// for glBegin(), glEnd(), or repeated glFlush().
glDrawArrays(GL_TRIANGLES, 0, vertices.length);
// Cleanup
glDeleteBuffers(bufferId);