2
votes

I'm attempting to use VAO's+VBO's+IBO's with shaders, but no object gets drawn. I am not sure what I am missing. I am pretty new to C++, and GLSL, so I am not sure if I am screwing something up with the C++ in general, or if I am failing to handle the OpenGL context correctly?

The main function (code for handling window creation is missing. If you think you may need to review it as well, just let me know.):

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;

}

::The shader code::

Vertex shader:

#version 400

in vec3 in_Position;
in vec3 in_Normal;

void main()
{

gl_Position = vec4(in_Position, 1.0);

}

Fragment shader:

#version 400

out vec4 FragColor;

void main()
{

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

 }

I did look at similar questions on here already, and they did help me fix a few possible issues, but so far, they obviously haven't proven useful in helping me get my code up and running. I also asked some other people in real time chat on gamedev.net, but they couldn't seem to see where I went wrong either. I fixed a possible issue with declaring glDoubles rather than floats, but that was actually working without the vao and shaders, so that is not (and unlikely ever was) the issue, in whole or part.

3

3 Answers

2
votes

I don't know if any of the following will solve your problem, but I do see some issues in your code:

glEnableClientState(GL_VERTEX_ARRAY);

You are mixing here old and deprecated builtin vertex atttributes with the generic vertex attributes. You don't need any of these glEnableClientState calls - your shader doesn't use the builtin attributes. The same goes for the glLoadIdentity which is also totally unneeded and would be invalid in a core profile context.

The second thing I see is that you do not specify your attribute indices, so the GL is free to map them. You also don't query them, but just assume them to be 0 for in_Position and 1 for in_Normal - which is by no means guaranteed to be the case. Use the layout(location=) qualifiers when declaring your input attributes in your vertex shader to actually define the mapping, or use glBindAttribLocation.

1
votes

quickly looking over your code I am struggling to find where you are sending the BufferData to the GPU.

  1. Generate and Bind new buffer

  2. Initialise Buffers to take data.

  3. Send data using glBufferSubData...

  4. Repeat steps 1 through 3 for Element Arrays.

  5. Generate and Bind Vertex Array Object.

  6. Setup VertexAttribArray Pointers and bind them to your shader.

  7. Bind Element Buffer once again.

  8. Unbind Vertex Array using glBindVertexArray(0)

This is how I setup my buffers using OpenTK, the code should be fairly understandable and useful in any case:

// 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);
1
votes

Well, after sitting down and reading the docs for version 4.0, I learned that I had screwed up on my attrib pointers by passing incorrect stride and pointers to the start of the buffer data. My thought was that the stride was the size of the element type multiplied by the number of attribute elements, so you'd get the next attribute you were looking for. Obviously that is not what you are supposed to do. I changed that to zero since my attribs are back to back:

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

-->

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

Then the pointer I tried handling almost the same exact way. Should have been a null pointer to the first buffer attrib location:

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

-->

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

Once I actually sat down and read the docs closely, I understood what actually belonged there. Now the shaders are working and I can work on the cool stuff... :P Thanks for the efforts to answer my question anyways everyone. :)