OpenGL ES 2.0中的简单三角形问题

时间:2015-07-16 17:22:32

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

我在绘制一个简单的三角形时遇到问题。我在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);          

}

3 个答案:

答案 0 :(得分:0)

此通话无效:

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

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

答案 1 :(得分:0)

简而言之,您没有索引和颜色数据,也没有绑定作为顶点缓冲区的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. 使用渲染循环中func中的变量 triVertBufferID 来绑定vbo

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

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

答案 2 :(得分:-1)

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

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