OpenGL ES 2.0 中简单三角形的问题
Trouble with Simple Triangle in OpenGL ES 2.0
我在绘制简单的三角形时遇到了问题。我在 Android 本机 Activity 中正确设置了 OpenGL ES 2.0,因为我可以执行 glClear() 并且它有效。
当我尝试绘制具有 3 个顶点的三角形时,它要么在调用 glDrawArrays 时崩溃,要么在我尝试执行 glDrawElements 时崩溃,但没有任何反应,但我收到以下消息:GLES_V2//GLESv2Imp.cpp:glDrawElements:669 错误 0x500
我查了一下,但我不认为我有任何无效的枚举,我已经检查了我的代码并试验了几天,但绘制调用不起作用。我还读到如果 glDrawArrays 试图访问错误的内存块,它会崩溃,但据我所知,我的设置是正确的。谁能帮我理解为什么它可能会崩溃?
这就是我的三角函数的调用方式。这部分只是一个模型
start()
{
setTriangle();
}
renderLoop()
{
drawTriangle();
}
这是我的着色器:
static const std::string triVertShader = "\
attribute vec4 vPosition;\
void main()\
{\
gl_Position = vPosition;\
}\
";
static const std::string triFragShader = "\
precision mediump float;\
uniform vec4 vColor;\
void main()\
{\
gl_FragColor = vColor;\
}\
";
这是我编译它们和Link程序的地方。我没有包括我的检查,但着色器编译成功,程序链接成功:
GLuint LoadShaders(const std::string &vertexShader, const std::string &fragmentShader)
{
GLint result = GL_TRUE;
int infoLogLength;
//Create the shaders
GLuint vertShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint fragShaderID = glCreateShader(GL_FRAGMENT_SHADER);
const char * vertShaderSource = vertexShader.data();
const char * fragShaderSource = fragmentShader.data();
//Compile Vertex Shader
glShaderSource(vertShaderID, 1, &vertShaderSource, NULL);
glCompileShader(vertShaderID);
//Compile Fragment Shader
glShaderSource(fragShaderID, 1, &fragShaderSource, NULL);
glCompileShader(fragShaderID);
//Link the program
GLuint programID = glCreateProgram();
glAttachShader(programID, vertShaderID);
glAttachShader(programID, fragShaderID);
glBindAttribLocation(programID, 0, "vPosition");
glLinkProgram(programID);
// glDeleteShader(vertShaderID);
// glDeleteShader(fragShaderID);
return programID;
}
这是我设置缓冲区对象的地方:
void setTriangle()
{
glClearColor(0, 1, 0, 1);
GLfloat triVerts[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f };
GLuint triVertBufferID;
glGenBuffers(1, &triVertBufferID);
glBindBuffer(GL_ARRAY_BUFFER, triVertBufferID);
glBufferData(GL_ARRAY_BUFFER,
sizeof(triVerts),
triVerts,
GL_STATIC_DRAW);
program = LoadShaders(triVertShader, triFragShader); //note: "program" is a global variable of type GLuint
}
这是绘图调用:
void drawTriangle()
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
//glDrawElements(GL_TRIANGLES, 3, GL_FLOAT, (void*)0 );
//glDrawArrays always crashes immediately
glDrawArrays(GL_TRIANGLES, 0, 3);
}
此调用无效:
glDrawElements(GL_TRIANGLES, 3, GL_FLOAT, (void*)0 );
参数GL_FLOAT
不是索引数据的有效数据类型,GLES 2.x仅支持GL_UNSIGNED_BYTE
和GL_UNSIGNED_SHORT
。
但是,我认为您根本不打算使用 glDrawElements()
。那是 indexed rendering。在您的代码中,您没有准备任何 GL_ELEMENT_ARRAY_BUFFER
,也不需要。
您可能想使用
glDrawArrays(GL_TRIANGLES, 0, 3);
还要确保 triVertBufferID
在 drawTriangle()
中调用 glVertexAttribPointer()
时仍然是当前绑定的 GL_ARRAY_BUFFER
。目前,您只能在程序初始化时绑定它 setTriangle()
。只要您从不将任何其他内容绑定到该缓冲区目标(或明确取消绑定),这就会起作用。如果您想稍后添加不同的对象,这将导致问题。
简而言之,您没有索引和颜色数据,也没有绑定作为顶点缓冲区制作的 VBO。如果您在片段着色器代码中取消颜色,则不需要颜色。放 gl_FragColor = vec(1.0,0.0,0.0,1.0);而是为了测试它是否运作良好。
已更新)
使局部顶点数组成为全局数组。
GLfloat triVerts[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f };
在渲染循环中的函数中使用变量 triVertBufferID 绑定 vbo
当你使用 VBO 并且它是静态的(永远不会改变)时,不要每次都调用 glVertexAttribPointer(), glEnableVertexAttribArray()。你可以在setTriangle()中设置一次,你不确定它的handle id是否为'0'。你应该调用 glGetAttribLocation() 来了解它。
当你不使用VBO时,每次用顶点数组的指针调用那些函数。
我发现有一些小问题导致您的应用无法呈现:
您已将 vPosition 属性声明为 vec4,但您正在使用没有足够的数据对其进行初始化。 OpenGL 将使用默认值填充缺失的数据,但这仍可能导致意外行为。
//call me after programID = loadShaders(...)
int vPosLoc = GLES20.getAttributeLocation(programID,"vPosition"); //pass me to EnableVertexAttribArray()!
正如您在初始化数据时所做的那样,在渲染时您需要绑定一个缓冲区以将其连接到着色器输入 - 所以:
glUseProgram(program);
glEnableVertexAttribArray(vPosLoc); //you use 0 for vPosLoc, which only works because you called glBindAttributeLocation()
glBindBuffer(GL_ARRAY_BUFFER, triVertBufferID); //triVertBufferID - make it a class member?
glVertexAttribPointer(vPosLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); //you might need to change the second argument from 3 to 4, if you're gonna stick with vec4 for vPosition in the shader.
请注意,我将 vertexAttribPointer 和 enableVertexAttribArray() 中的 0 更改为 vPosLoc,只是为了使用变量而不是常量。
您(在您显示的代码中)从未设置 vColor 统一变量 - 您需要这样做,并且您需要查找其着色器位置:
//set me up right after loadShaders()
int vColorLoc = glGetUniformLocation(programID,"vColor");
//and later, in draw
glUniform4f(vColorLoc,1.0,0.0,0.0,1.0); //red!
现在,您应该可以调用 glDrawArrays() 了!
我在绘制简单的三角形时遇到了问题。我在 Android 本机 Activity 中正确设置了 OpenGL ES 2.0,因为我可以执行 glClear() 并且它有效。
当我尝试绘制具有 3 个顶点的三角形时,它要么在调用 glDrawArrays 时崩溃,要么在我尝试执行 glDrawElements 时崩溃,但没有任何反应,但我收到以下消息:GLES_V2//GLESv2Imp.cpp:glDrawElements:669 错误 0x500
我查了一下,但我不认为我有任何无效的枚举,我已经检查了我的代码并试验了几天,但绘制调用不起作用。我还读到如果 glDrawArrays 试图访问错误的内存块,它会崩溃,但据我所知,我的设置是正确的。谁能帮我理解为什么它可能会崩溃?
这就是我的三角函数的调用方式。这部分只是一个模型
start()
{
setTriangle();
}
renderLoop()
{
drawTriangle();
}
这是我的着色器:
static const std::string triVertShader = "\
attribute vec4 vPosition;\
void main()\
{\
gl_Position = vPosition;\
}\
";
static const std::string triFragShader = "\
precision mediump float;\
uniform vec4 vColor;\
void main()\
{\
gl_FragColor = vColor;\
}\
";
这是我编译它们和Link程序的地方。我没有包括我的检查,但着色器编译成功,程序链接成功:
GLuint LoadShaders(const std::string &vertexShader, const std::string &fragmentShader)
{
GLint result = GL_TRUE;
int infoLogLength;
//Create the shaders
GLuint vertShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint fragShaderID = glCreateShader(GL_FRAGMENT_SHADER);
const char * vertShaderSource = vertexShader.data();
const char * fragShaderSource = fragmentShader.data();
//Compile Vertex Shader
glShaderSource(vertShaderID, 1, &vertShaderSource, NULL);
glCompileShader(vertShaderID);
//Compile Fragment Shader
glShaderSource(fragShaderID, 1, &fragShaderSource, NULL);
glCompileShader(fragShaderID);
//Link the program
GLuint programID = glCreateProgram();
glAttachShader(programID, vertShaderID);
glAttachShader(programID, fragShaderID);
glBindAttribLocation(programID, 0, "vPosition");
glLinkProgram(programID);
// glDeleteShader(vertShaderID);
// glDeleteShader(fragShaderID);
return programID;
}
这是我设置缓冲区对象的地方:
void setTriangle()
{
glClearColor(0, 1, 0, 1);
GLfloat triVerts[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f };
GLuint triVertBufferID;
glGenBuffers(1, &triVertBufferID);
glBindBuffer(GL_ARRAY_BUFFER, triVertBufferID);
glBufferData(GL_ARRAY_BUFFER,
sizeof(triVerts),
triVerts,
GL_STATIC_DRAW);
program = LoadShaders(triVertShader, triFragShader); //note: "program" is a global variable of type GLuint
}
这是绘图调用:
void drawTriangle()
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
//glDrawElements(GL_TRIANGLES, 3, GL_FLOAT, (void*)0 );
//glDrawArrays always crashes immediately
glDrawArrays(GL_TRIANGLES, 0, 3);
}
此调用无效:
glDrawElements(GL_TRIANGLES, 3, GL_FLOAT, (void*)0 );
参数GL_FLOAT
不是索引数据的有效数据类型,GLES 2.x仅支持GL_UNSIGNED_BYTE
和GL_UNSIGNED_SHORT
。
但是,我认为您根本不打算使用 glDrawElements()
。那是 indexed rendering。在您的代码中,您没有准备任何 GL_ELEMENT_ARRAY_BUFFER
,也不需要。
您可能想使用
glDrawArrays(GL_TRIANGLES, 0, 3);
还要确保 triVertBufferID
在 drawTriangle()
中调用 glVertexAttribPointer()
时仍然是当前绑定的 GL_ARRAY_BUFFER
。目前,您只能在程序初始化时绑定它 setTriangle()
。只要您从不将任何其他内容绑定到该缓冲区目标(或明确取消绑定),这就会起作用。如果您想稍后添加不同的对象,这将导致问题。
简而言之,您没有索引和颜色数据,也没有绑定作为顶点缓冲区制作的 VBO。如果您在片段着色器代码中取消颜色,则不需要颜色。放 gl_FragColor = vec(1.0,0.0,0.0,1.0);而是为了测试它是否运作良好。
已更新)
使局部顶点数组成为全局数组。
GLfloat triVerts[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f };
在渲染循环中的函数中使用变量 triVertBufferID 绑定 vbo
当你使用 VBO 并且它是静态的(永远不会改变)时,不要每次都调用 glVertexAttribPointer(), glEnableVertexAttribArray()。你可以在setTriangle()中设置一次,你不确定它的handle id是否为'0'。你应该调用 glGetAttribLocation() 来了解它。
当你不使用VBO时,每次用顶点数组的指针调用那些函数。
我发现有一些小问题导致您的应用无法呈现:
您已将 vPosition 属性声明为 vec4,但您正在使用没有足够的数据对其进行初始化。 OpenGL 将使用默认值填充缺失的数据,但这仍可能导致意外行为。
//call me after programID = loadShaders(...)
int vPosLoc = GLES20.getAttributeLocation(programID,"vPosition"); //pass me to EnableVertexAttribArray()!
正如您在初始化数据时所做的那样,在渲染时您需要绑定一个缓冲区以将其连接到着色器输入 - 所以:
glUseProgram(program);
glEnableVertexAttribArray(vPosLoc); //you use 0 for vPosLoc, which only works because you called glBindAttributeLocation()
glBindBuffer(GL_ARRAY_BUFFER, triVertBufferID); //triVertBufferID - make it a class member?
glVertexAttribPointer(vPosLoc, 3, GL_FLOAT, GL_FALSE, 0, 0); //you might need to change the second argument from 3 to 4, if you're gonna stick with vec4 for vPosition in the shader.
请注意,我将 vertexAttribPointer 和 enableVertexAttribArray() 中的 0 更改为 vPosLoc,只是为了使用变量而不是常量。
您(在您显示的代码中)从未设置 vColor 统一变量 - 您需要这样做,并且您需要查找其着色器位置:
//set me up right after loadShaders()
int vColorLoc = glGetUniformLocation(programID,"vColor");
//and later, in draw
glUniform4f(vColorLoc,1.0,0.0,0.0,1.0); //red!
现在,您应该可以调用 glDrawArrays() 了!