将VAO + IBO与GLSL着色器一起使用

时间:2014-02-23 04:58:55

标签: c++ opengl glsl

我正在尝试使用VAO的+ VBO的+ IBO和着色器,但没有绘制对象。我不确定我错过了什么。我对C ++和GLSL很陌生,所以我不确定我是否通常使用C ++搞错了,或者我是否无法正确处理OpenGL上下文?

主要功能(缺少处理窗口创建的代码。如果您认为您可能需要查看它,请告诉我。):

int main(int argc, char *argv[])
{

    //INIT SDL
    SDL_Init(SDL_INIT_VIDEO);
    SDL_CreateWindowAndRenderer(400, 300, SDL_WINDOW_OPENGL, &displayWindow, &displayRenderer);
    SDL_GetRendererInfo(displayRenderer, &displayRendererInfo);

    /*TODO: Check that we have OpenGL */
    if ((displayRendererInfo.flags & SDL_RENDERER_ACCELERATED) == 0 || (displayRendererInfo.flags & SDL_RENDERER_TARGETTEXTURE) == 0) {}

    SDL_GL_CreateContext(displayWindow);
    //SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    glewInit();
    int error = glGetError();
    if (error != GL_NO_ERROR){ std::cout << "Error during glewInit call: " << error << "\n"; };

    //glEnable(GL_DEBUG_OUTPUT);

    Display_InitGL();
    error = glGetError();
    if (error != GL_NO_ERROR){ std::cout << "Error during Display init: " << error << "\n"; };

    Display_SetViewport(400, 300);
    error = glGetError();
    if (error != GL_NO_ERROR){ std::cout << "Error during Display Set Viewport Issue: " << error << "\n"; };

    // SET UP TEST OBJ
    MainChar *player = new MainChar();
    player->MainChar_VBO_Func();
    GLushort size = player->MainChar_VBO_IndexBuffer_Func();
    float count = 0.0;
    // END SET UP OF TEST OBJ

    GLint *length = new GLint;
    const char* vertShdr = readFile("C:\\Users\\JRFerrell\\Documents\\Visual Studio 2013\\Projects\\GLEW Practice\\vertShader.vs", *length);

    std::cout << vertShdr;

    GLuint vertShaderId = glCreateShader(GL_VERTEX_SHADER);

    glShaderSource(vertShaderId, 1, &vertShdr, length);
    std::cout << "\n\nLength: " << *length;

    glCompileShader(vertShaderId);

    GLint *length2 = new GLint;
    const char* fragShdr = readFile("C:\\Users\\JRFerrell\\Documents\\Visual Studio 2013\\Projects\\GLEW Practice\\fragShader.fs", *length2);

    GLint fragShaderId = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(fragShaderId, 1, &fragShdr, length2);

    glCompileShader(fragShaderId);

    GLuint shaderProgram = glCreateProgram();

    glAttachShader(shaderProgram, vertShaderId);
        error = glGetError();
        if (error != GL_NO_ERROR){ std::cout << "Error during glAttachShader: " << error << "\n"; };

    glAttachShader(shaderProgram, fragShaderId);
        error = glGetError();
        if (error != GL_NO_ERROR){ std::cout << "Error during glAttachShader: " << error << "\n"; };

    glBindAttribLocation(shaderProgram, 0, "in_Position");
    glBindAttribLocation(shaderProgram, 1, "in_Normal");

    glLinkProgram(shaderProgram);
        error = glGetError();
        if (error != GL_NO_ERROR){ std::cout << "Error during glLinkProgram: " << error << "\n"; };

    // END SHADER PROGRAM DEFINITION

    //Check info log for errors:

    int Len = 0;

    char *Buffer = nullptr;
    glGetShaderiv(vertShaderId, GL_INFO_LOG_LENGTH, &Len);
    Buffer = new char[Len];
    glGetShaderInfoLog(vertShaderId, Len, &Len, Buffer);
    std::cout << "Vertex Log:" << std::endl << Buffer << std::endl;
    delete[] Buffer;

    glGetShaderiv(fragShaderId, GL_INFO_LOG_LENGTH, &Len);
    Buffer = new char[Len];
    glGetShaderInfoLog(fragShaderId, Len, &Len, Buffer);
    std::cout << "Fragment Log:" << std::endl << Buffer << std::endl;
    delete[] Buffer;

    glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &Len);
    Buffer = new char[Len];
    glGetProgramInfoLog(shaderProgram, Len, &Len, Buffer);
    std::cout << "Shader Log:" << std::endl << Buffer << std::endl;
    delete[] Buffer;

    // Create VAO. Don't forget to enable all necessary states because the VAO starts with default state, cleaning all states prev called to do so.
    GLuint VaoId;
    glGenVertexArrays(1, &VaoId);
    glBindVertexArray(VaoId);

    // Bind buffers & set-up VAO vertex pointers
    glBindBuffer(GL_ARRAY_BUFFER, player->vboID);
    error = glGetError();
    if (error != GL_NO_ERROR){ std::cout << "Error glBindBuffer-vboID: " << error << "\n"; }
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * GL_FLOAT, (const GLvoid *)0);
    glEnableVertexAttribArray(0);

    // Set-up VAO normal pointers
    error = glGetError();
    if (error != GL_NO_ERROR){ std::cout << "Error glBindBuffer-vbo init: " << error << "\n"; }
    glEnableClientState(GL_NORMAL_ARRAY);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * GL_FLOAT, (void*)(3 * sizeof(GL_FLOAT)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, player->vboIndexID);

    GLint maxLength, nAttribs;
    glGetProgramiv(shaderProgram, GL_ACTIVE_ATTRIBUTES, &nAttribs);
    glGetProgramiv(shaderProgram, GL_ACTIVE_ATTRIBUTES, &maxLength);

    //std::cout << "\nmax length: " << maxLength << "\nnAttribs: " << nAttribs;

    glBindVertexArray(0);
    error = glGetError();
    if (error != GL_NO_ERROR){ std::cout << "Error glBindVertexArray: " << error << "\n"; };
    // End VAO init

    while (1){

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        error = glGetError();
        if (error != GL_NO_ERROR){ std::cout << "Error glClearColor: " << error << "\n"; };

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        error = glGetError();
        if (error != GL_NO_ERROR){ std::cout << "Error in glClear: " << error << "\n"; };

        glLoadIdentity();

        glUseProgram(shaderProgram);
        glBindVertexArray(VaoId);

        glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_SHORT, 0);

                    glUseProgram(0);
        glBindVertexArray(0);

        SDL_GL_SwapWindow(displayWindow);

        count -= .1;

    }

    SDL_Delay(5000);

    SDL_Quit();

    return 0;

}

::着色器代码::

顶点着色器:

#version 400

in vec3 in_Position;
in vec3 in_Normal;

void main()
{

gl_Position = vec4(in_Position, 1.0);

}

片段着色器:

#version 400

out vec4 FragColor;

void main()
{

 FragColor = vec4(0.0f, 0.5f, 1.0f, 1.0f);

 }

我确实在这里看过类似的问题,他们确实帮我解决了一些可能的问题,但到目前为止,他们显然没有证明有助于我启动和运行代码。我还在gamedev.net上实时询问了其他一些人,但他们似乎也看不出我错在哪里。我修正了一个可能的问题,即声明glDoubles而不是浮点数,但这实际上是在没有vao和着色器的情况下工作,所以这不是(也不可能是)整个或部分问题。

3 个答案:

答案 0 :(得分:1)

我不知道以下任何一项是否能解决您的问题,但我确实在您的代码中看到了一些问题:

  

glEnableClientState(GL_VERTEX_ARRAY);

您在这里将旧的和已弃用的内置顶点atttributes与通用顶点属性混合在一起。您不需要任何这些glEnableClientState调用 - 您的着色器不使用内置属性。同样适用于glLoadIdentity,这也是完全不需要的,并且在核心配置文件上下文中无效。

我看到的第二件事是您没有指定属性索引,因此GL可以自由地映射它们。您也不会查询它们,但只假设in_Position为0,in_Normal为1 - 这绝不是保证。在顶点着色器中声明输入属性以实际定义映射时,请使用layout(location=)限定符,或使用glBindAttribLocation

答案 1 :(得分:1)

快速查看代码我很难找到将BufferData发送到GPU的位置。

  1. 生成并绑定新缓冲区

  2. 初始化缓冲区以获取数据。

  3. 使用glBufferSubData发送数据......

  4. 对Element Arrays重复步骤1到3.

  5. 生成并绑定顶点数组对象。

  6. 设置VertexAttribArray指针并将它们绑定到着色器。

  7. 再次绑定元素缓冲区。

  8. 使用glBindVertexArray(0)取消绑定顶点数组

  9. 这就是我使用OpenTK设置缓冲区的方法,代码在任何情况下都应该是可以理解和有用的:

    // Generate Vertex Buffer Object and bind it so it is current.
    GL.GenBuffers(1, out bufferHandle);         
    GL.BindBuffer(BufferTarget.ArrayBuffer, bufferHandle);
    
    
    // Initialise storage space for the Vertex Buffer.
    GL.BufferData(BufferTarget.ArrayBuffer, bufferSize, IntPtr.Zero, BufferUsageHint.StaticDraw);
    // Send Position data.
    GL.BufferSubData<Vector3>(
                BufferTarget.ArrayBuffer, noOffset, new IntPtr(sizeOfPositionData), bufferObject.PositionData);
    // Send Normals data, offset by size of Position data.
    GL.BufferSubData<Vector3>(
                BufferTarget.ArrayBuffer, new IntPtr(sizeOfPositionData), new IntPtr(sizeOfNormalsData), bufferObject.NormalsData);
    
    // Generate Element Buffer Object and bind it so it is current.        
    GL.GenBuffers(1, out bufferHandle);
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, bufferHandle);
    GL.BufferData(
                BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(uint) *     bufferObject.IndicesData.Length), bufferObject.IndicesData, BufferUsageHint.StaticDraw);
    
    GL.BindBuffer(BufferTarget.ArrayBuffer, bufferObject.VboID);
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, bufferObject.IboID);
    
    // Generate Vertex Array Object and bind it so it is current.
    GL.GenVertexArrays(1, out bufferHandle);
    GL.BindVertexArray(bufferHandle);
    
    bufferHandle = GL.GetAttribLocation(program, "in_position");
    GL.EnableVertexAttribArray(bufferHandle); 
    GL.BindBuffer(BufferTarget.ArrayBuffer, bufferObject.VboID);
    GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
    GL.BindAttribLocation(program, bufferHandle, "in_position");
    
    bufferHandle = GL.GetAttribLocation(program, "in_normal");
    GL.EnableVertexAttribArray(bufferHandle);
    GL.BindBuffer(BufferTarget.ArrayBuffer, bufferObject.VboID);
    GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, sizeOfPositionData);
    GL.BindAttribLocation(program, bufferHandle, "in_normal");
    
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, bufferObject.IboID);
    
    // IMPORTANT: vertex array needs unbinding here to avoid rendering incorrectly
    GL.BindVertexArray(0);
    

答案 2 :(得分:0)

好吧,在坐下来阅读4.0版的文档之后,我了解到我通过向缓冲区数据的开头传递不正确的步幅和指针搞砸了我的attrib指针。我的想法是,步幅是元素类型的大小乘以属性元素的数量,因此您将获得您正在寻找的下一个属性。显然这不是你应该做的。我将其改为零,因为我的attribs背靠背:

“glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,6 * GL_FLOAT,(void *)(3 * sizeof(GL_FLOAT)));”

- &GT;

“glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void *)(3 * sizeof(GL_FLOAT)));”

然后我尝试处理的指针几乎完全相同。应该是指向第一个缓冲区attrib位置的空指针:

“glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void *)(3 * sizeof(GL_FLOAT)));”

- &GT;

“glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(GLubyte *)NULL);”

一旦我真正坐下来仔细阅读文档,我就明白了那里真正属于什么。现在着色器正在工作,我可以处理很酷的东西...:P感谢你们努力回答我的问题。 :)