【问题标题】:Trouble with Simple Triangle in OpenGL ES 2.0OpenGL ES 2.0 中简单三角形的问题
【发布时间】:2015-07-16 17:22:31
【问题描述】:

我在绘制简单三角形时遇到问题。我在 Android Native 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;\
    }\
";

这是我编译它们和链接程序的地方。我没有包括我的检查,但着色器编译成功,程序链接成功:

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);          

}

【问题讨论】:

    标签: android opengl-es android-ndk opengl-es-2.0


    【解决方案1】:

    此调用无效:

    glDrawElements(GL_TRIANGLES, 3, GL_FLOAT, (void*)0 );
    

    参数GL_FLOAT不是索引数据的有效数据类型,GLES 2.x只支持GL_UNSIGNED_BYTEGL_UNSIGNED_SHORT

    但是,我认为您根本不打算使用glDrawElements()。那是给indexed rendering。在您的代码中,您不需要准备任何GL_ELEMENT_ARRAY_BUFFER,也不需要。

    你可能想要使用

    glDrawArrays(GL_TRIANGLES, 0, 3);
    

    还要确保triVertBufferIDglVertexAttribPointer() 调用drawTriangle() 时仍然是当前绑定的GL_ARRAY_BUFFER。目前,您只在程序初始化时绑定它setTriangle()。只要您从不将任何其他内容绑定到该缓冲区目标(或明确取消绑定),这将起作用。如果您想稍后添加不同的对象,这将导致问题。

    【讨论】:

    • 感谢您的提示,您说得对,我确实想使用 glDrawArrays(GL_TRIANGLES, 0, 3);但这立即崩溃,没有任何解释。我在模拟器上运行它,通常当发生崩溃时,它会说“应用程序已停止工作”,但是这个 glDrawArrays() 崩溃完全使模拟器崩溃。所以我的问题是为什么 glDrawArrays() 崩溃如此“暴力”
    【解决方案2】:

    简而言之,您没有索引和颜色数据,也没有绑定您作为顶点缓冲区制作的 VBO。如果您在 Frag Shader 代码中取消颜色,则不需要颜色。把 gl_FragColor = vec(1.0,0.0,0.0,1.0);而是测试它是否运行良好。

    更新)

    1. 使局部顶点数组成为全局数组。

      GLfloat triVerts[] = { 0.0f, 0.5f, 0.0f, -0.5f,-0.5f,0.0f, 0.5f, -0.5f, 0.0f };

    2. 在渲染循环的函数中使用变量 triVertBufferID 绑定 vbo

    3. 当你使用 VBO 并且它是静态的(永不改变)时,不要每次都调用 glVertexAttribPointer()、glEnableVertexAttribArray()。你可以在 setTriangle() 中设置一次,你不确定它的句柄 id 是否为 '0'。你应该调用 glGetAttribLocation() 来了解它。

      当你不使用 VBO 时,每次使用顶点数组的指针调用这些函数。

    【讨论】:

    • VAO 不是 ES 2 规范的一部分。它们可能作为扩展提供,但不是强制性的。
    • 我想说的是VBO。
    • 我正在绑定它。你能澄清你的意思吗? GLuint triVertBufferID; glGenBuffers(1, &triVertBufferID); glBindBuffer(GL_ARRAY_BUFFER, triVertBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(triVerts), triVerts, GL_STATIC_DRAW);
    • 一般情况下,每一帧,你都要重新绑定一次。每个 VBO(如颜色、顶点和索引)都必须在 render() 函数中绑定,以便弹出 VAO 以帮助它变得简单(但 Android 并未正式支持它)
    • gl_FragColor = vec4(1.0,0.0,0.0,1.0);什么都没做
    【解决方案3】:

    我可以看到一些小问题导致您的应用无法呈现:

    您已将 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()了!

    【讨论】:

    • 这里列出的前两项不是问题。使用比指定属性更多的组件在着色器中声明属性变量是完全有效的(例如,参见最近的这个问题:stackoverflow.com/q/31319081/3530129)。在属性位置上,OP调用glBindAttribLocation()将其设置为0,所以没有问题。
    • 感谢您的回复,我实际上已经基本上达到了您所说的内容,然后看到了您的回复 - 我能够看到绿屏而没有任何崩溃。无论如何,我只是在片段着色器中硬编码了红色,但我把它改成了你说的。我完全按照您所说的那样更改了其他所有内容,但仍然得到相同的结果:绿屏。这显然比崩溃要好,但仍然不是预期的效果。仍然没有渲染三角形。我已经用 glGetError 语句乱扔了整个文件,并且所有内容都返回 0(无错误)。无论如何,然后我发现了我的愚蠢错误
    • 我在做 glDrawArrays(GL_TRIANGLES, 0, 1);只是想看看我是否在崩溃期间越过了缓冲区。我忘记换回来了。现在我得到一个三角形!非常感谢您,我将把解决方案归功于您。还有另一个问题......来自谷歌的本机活动代码正在执行glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);,但不推荐使用 GL_PERSPECTIVE_CORRECTION!在尝试调试时,它一直给我错误的 0x500 错误(对于每个 gl 调用),并让我大吃一惊。以后有机会我会用我的发现更新主帖。
    • @RetoKoradi - 感谢您提供的好信息 - 我错过了对 bindAttribLocation 的调用,我不知道 GL 会为 vec4 属性填充缺失的数据。我将更新答案以删除不正确的信息。 Smokenstein - 很高兴你发现了这个问题!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多