element buffer problems

I’m trying to load a Wavefront .obj file of an icosahedron I found on the internet.

My problem is that its output is clearly not correct

I expect the problem is one of two things:

  1. I’m not interpreting the obj file correctly (I loaded it in an online .obj file renderer and it worked)
    or
  2. I didn’t set up the vertex/element buffer correctly

Incoming wall of code: (most of it isn’t important and I tried to make it visible what parts these are):


#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <chrono>
#include <cmath>


extern "C" {
#include "objReader.h"
}
typedef struct {
    GLuint program;
    GLuint frag;
    GLuint vert;
} shaders;
shaders compileShaders(){
    // Shader sources
    const GLchar* vertexSource =
        "#version 150 core
"
        "in vec3 position;"
        "uniform mat4 trans;"
        "uniform mat4 model;"
        "uniform mat4 view;"
        "uniform mat4 proj;"
        "void main()"
        "{"
         //   "gl_Position = vec4(position,1.0);"
            "gl_Position = proj * view * model * vec4(position, 1.0);"
        "}";

    const GLchar* fragmentSource =
        "#version 150 core
"
        "out vec4 outColor;"
        "void main()"
        "{"
        "outColor = vec4(0,1.0,1.0, 1.0);"
        "}";
        // Create and compile the vertex shader
    GLint status;

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSource, NULL);
    glCompileShader(vertexShader);

    char buffer[512];

    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
    glGetShaderInfoLog(vertexShader, 512, NULL, buffer);

    if(status == GL_TRUE){
        printf("vertex shader compiled.
");
    } else{
        printf("

%s

",buffer);
    }

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);

    glGetShaderInfoLog(fragmentShader, 512, NULL, buffer);

    if(status == GL_TRUE){
        printf("frag shader compiled.
");
    } else{
        printf("

%s

",buffer);
    }

    // Link the vertex and fragment shader into a shader program
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glBindFragDataLocation(shaderProgram, 0, "outColor");

    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);

    shaders ret;
    ret.frag = fragmentShader;
    ret.program = shaderProgram;
    ret.vert = vertexShader;

    return ret;
}


int main()
{
    // load the obj file
    obj iso = readObjFile("iso.obj");

    auto t_start = std::chrono::high_resolution_clock::now();

    // init window

    glfwInit();

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL",NULL,NULL); // Windowed
    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    glewInit();

    // compile shaders
    shaders programs = compileShaders();
    GLuint shaderProgram = programs.program;
    GLuint vertexShader = programs.vert;
    GLuint fragmentShader = programs.frag;
    
    //**********verifying that my problem isn't that the data read from the file isn't accurate (it is)*************

    // this is the exact data from the obj file I read
    float vertices[36] = {0,  -0.525731,  0.850651,
                0.850651,  0,  0.525731,
                0.850651,  0,  -0.525731,
                -0.850651,  0,  -0.525731,
                -0.850651,  0,  0.525731,
                -0.525731,  0.850651,  0,
                0.525731,  0.850651,  0,
                0.525731,  -0.850651,  0,
                -0.525731,  -0.850651,  0,
                0,  -0.525731,  -0.850651,
                0,  0.525731,  -0.850651,
                0,  0.525731,  0.850651};
                
    int elements[60] = {2,  3,  7,
                2,  8,  3,
                4,  5,  6,
                5,  4,  9,
                7,  6,  12,
                6,  7,  11,
                10,  11,  3,
                11,  10,  4,
                8,  9,  10,
                9,  8,  1,
                12,  1,  2,
                1,  12,  5,
                7,  3,  11,
                2,  7,  12,
                4,  6,  11,
                6,  5,  12,
                3,  8,  10,
                8,  2,  1,
                4,  10,  9,
                5,  9,  1};
    // comparing it to the data I read, getting the size of all elements in a fool-proof way
    int totalSize = 0;
    int totalTSize = 0;
    for (int i = 0; i < 36; i++){
        printf("%f:%f:%s
",vertices[i],iso.vertices[i],(vertices[i]==iso.vertices[i])?"true":"false");
        totalSize += sizeof(iso.vertices[i]);
    }
    
    for (int i = 0; i < 60; i++){
        printf("%i:%i:%s
",elements[i],iso.triangles[i],(elements[i]==iso.triangles[i])?"true":"false");
        totalTSize += sizeof(iso.triangles[i]);
    }
    printf("vcount:%i
vsize:%i",iso.verticeCount,totalSize);
    printf("
tcount:%i
tsize:%i
",iso.triangleCount,totalTSize);


    printf("

%i

",sizeof(vertices));
    printf("

%i

",sizeof(elements));
    // **************************************************************************************************************

    // Create Vertex Array Object
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Create a Vertex Buffer Object and copy the vertex data to it
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, totalSize, iso.vertices, GL_STATIC_DRAW);
    // Create a Element Buffer Object and copy the element data to it
    GLuint ebo;
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); // Useful because you could change which buffers are used on the fly
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, totalTSize, iso.triangles, GL_STATIC_DRAW);

    // Specify the layout of the vertex data
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); // the compiled program knows what inputs it has (IFAIK)
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GL_FLOAT), 0);

    // adding standard transforms, making it rotate

    GLint uniModel = glGetUniformLocation(shaderProgram, "model");
    // Set up projection
    glm::mat4 view = glm::lookAt(
        glm::vec3(1.2f, 1.2f, 1.2f),
        glm::vec3(0.0f, 0.0f, 0.0f),
        glm::vec3(0.0f, 0.0f, 1.0f)
    );
    GLint uniView = glGetUniformLocation(shaderProgram, "view");
    glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));

    glm::mat4 proj = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 1.0f, 10.0f);

    GLint uniProj = glGetUniformLocation(shaderProgram, "proj");
    glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));

    while(!glfwWindowShouldClose(window)){

        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_start).count();

        glClear(GL_COLOR_BUFFER_BIT);

        glm::mat4 trans;
        trans = glm::rotate(
            trans,
            time * glm::radians(180.0f),
            glm::vec3(0.0f, 0.0f, 1.0f)
        );
        glm::mat4 model;
        model = glm::scale(model, glm::vec3(.01, .01, .01));
        glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
        model = glm::rotate(
            model,
            time * glm::radians(180.0f),
            glm::vec3(0.0f, 0.0f, 1.0f)
        );
        glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // black

         glDrawElements(
             GL_LINES,      // mode
             iso.triangleCount,    // count
             GL_UNSIGNED_INT,   // type
             (void*)0           // element array buffer offset
        );

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteProgram(shaderProgram);
    glDeleteShader(fragmentShader);
    glDeleteShader(vertexShader);
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArrays(1, &vao);
    free(iso.vertices); // in order to know the data from my reader would be sequential I had to malloc it myself
    free(iso.triangles);
    return 0;
}


thanks

I suspect that you aren’t accounting for the fact that OBJ vertex indices start at one while OpenGL vertex indices start at zero.

I note that the [var]elements[/var] array contains values from 1 to 12 inclusive, but the [var]vertices[/var] array only contains 36 elements (so vertex indices should be in the range 0 to 11 inclusive).

[QUOTE=GClements;1284329]I suspect that you aren’t accounting for the fact that OBJ vertex indices start at one while OpenGL vertex indices start at zero.

I note that the [var]elements[/var] array contains values from 1 to 12 inclusive, but the [var]vertices[/var] array only contains 36 elements (so vertex indices should be in the range 0 to 11 inclusive).[/QUOTE]

I changed it to subtract 1 from each index, and that made it way more recognizable (although still missing a couple lines)

thank you

That’s because the “f” commands in the OBJ file describe faces, not edges.

Try using glDrawElements(GL_TRIANGLES,…) and glPolygonMode(GL_FRONT_AND_BACK, GL_LINE).

For filled triangles, you’ll need some form of lighting, otherwise you’ll just see a silhouette.

That worked as well, thank you