Search code examples
openglshader3d-model

can not draw my car correctly in opengl


This is my main.cpp,I want to draw a car,I got data from obj file,and then put in the shader.I put my obj file into meshlab,it draw correctly ->Image,but in my c++ will like this-> Image

#include "..\tinyobjloader\tiny_obj_loader.h"
#include <algorithm>
#include <iostream>
#include<glew.h>
#include <glut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <chrono>
#include<SOIL.h>
#include<math.h>
#include"Shader.h"

GLuint programHandle;
GLuint vShader, fShader;   
static GLuint g_TexName;
GLuint vaoHandle;
std::vector<GLfloat> vertices;
std::vector<GLfloat>  colorData;
std::vector<GLfloat> texCoords;
std::vector<unsigned int> elements;

tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;

GLuint vboHandles[4];
GLuint elementbuffer;

GLuint positionBufferHandle = vboHandles[0];    
GLuint colorBufferHandle = vboHandles[1];
GLuint textureBufferHandle = vboHandles[2];
GLuint mvphandle = vboHandles[3];

unsigned char * data;
using namespace std;

float t = 0.0;
float maxs = 0;

void  initShader(const char  *VShaderFile, const char  *FShaderFile)
{
    //1、查看GLSL和OpenGL的版本  
    const  GLubyte *renderer = glGetString(GL_RENDERER);
    const  GLubyte *vendor = glGetString(GL_VENDOR);
    const  GLubyte *version = glGetString(GL_VERSION);
    const  GLubyte *glslVersion =
        glGetString(GL_SHADING_LANGUAGE_VERSION);
    GLint major, minor;
    glGetIntegerv(GL_MAJOR_VERSION, &major);
    glGetIntegerv(GL_MINOR_VERSION, &minor);
    //cout << "GL Vendor :" << vendor << endl;
    //cout << "GL Renderer : " << renderer << endl;
    //cout << "GL Version (string) : " << version << endl;
    //cout << "GL Version (integer) : " << major << "." << minor << endl;
    //cout << "GLSL Version : " << glslVersion << endl;

            vShader = glCreateShader(GL_VERTEX_SHADER);

    if (0 == vShader)
    {
        cerr << "ERROR : Create vertex shader failed" << endl;
        exit(1);
    }

    const  GLchar *vShaderCode = textFileRead(VShaderFile);
    const  GLchar *vCodeArray[1] = { vShaderCode };
    glShaderSource(vShader, 1, vCodeArray, NULL);

    glCompileShader(vShader);



    GLint compileResult;
    glGetShaderiv(vShader, GL_COMPILE_STATUS, &compileResult);
    if (GL_FALSE == compileResult)
    {
        GLint logLen;

        glGetShaderiv(vShader, GL_INFO_LOG_LENGTH, &logLen);
        if (logLen > 0)
        {
            char  *log = (char  *)malloc(logLen);
            GLsizei written;

            glGetShaderInfoLog(vShader, logLen, &written, log);
            cerr << "vertex shader compile log : " << endl;
            cerr << log << endl;
            free(log); 
        }
    }


    fShader = glCreateShader(GL_FRAGMENT_SHADER);

    if (0 == fShader)
    {
        cerr << "ERROR : Create fragment shader failed" << endl;
        exit(1);
    }


    const  GLchar *fShaderCode = textFileRead(FShaderFile);
    const  GLchar *fCodeArray[1] = { fShaderCode };
    glShaderSource(fShader, 1, fCodeArray, NULL);


    glCompileShader(fShader);


    glGetShaderiv(fShader, GL_COMPILE_STATUS, &compileResult);
    if (GL_FALSE == compileResult)
    {
        GLint logLen;

        glGetShaderiv(fShader, GL_INFO_LOG_LENGTH, &logLen);
        if (logLen > 0)
        {
            char  *log = (char  *)malloc(logLen);
            GLsizei written;

            glGetShaderInfoLog(fShader, logLen, &written, log);
            cerr << "fragment shader compile log : " << endl;
            cerr << log << endl;
            free(log);  
        }
    }


    //GLuint programHandle = glCreateProgram();
    programHandle = glCreateProgram();
    if (!programHandle)
    {
        cerr << "ERROR : create program failed" << endl;
        exit(1);
    }

    glAttachShader(programHandle, vShader);
    glAttachShader(programHandle, fShader);

    glLinkProgram(programHandle);

    GLint linkStatus;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus);
    if (GL_FALSE == linkStatus)
    {
        cerr << "ERROR : link shader program failed" << endl;
        GLint logLen;
        glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH,
            &logLen);
        if (logLen > 0)
        {
            char  *log = (char  *)malloc(logLen);
            GLsizei written;
            glGetProgramInfoLog(programHandle, logLen,
                &written, log);
            cerr << "Program log : " << endl;
            cerr << log << endl;
        }
    }
    else   
    {
        glUseProgram(programHandle);
    }
}
void LoadTexture(){
    // Load texture
    errno_t err;
    // Data read from the header of the BMP file
    unsigned char header[54];
    unsigned int dataPos;
    unsigned int imageSize;
    //unsigned int width, height;
    // Actual RGB data


    int width, height, nrChannels;
    //data = SOIL_load_image("wall.bmp", &width, &height, 0, SOIL_LOAD_RGB);

    FILE *  file;
    const char imagepath[] = "Van.bmp";
    if (err = fopen_s(&file, imagepath, "rb")){ printf("%s could not be opened. Are you in the right directory ? Don't forget to read the FAQ !\n", imagepath); }
    if (fread(header, 1, 54, file) != 54){
        printf("Not a correct BMP file\n");
    }
    // A BMP files always begins with "BM"
    if (header[0] != 'B' || header[1] != 'M'){
        printf("Not a correct BMP file\n");
    }
    // Make sure this is a 24bpp file
    if (*(int*)&(header[0x1E]) != 0)         { printf("Not a correct BMP file\n"); }
    if (*(int*)&(header[0x1C]) != 24)         { printf("Not a correct BMP file\n"); }

    dataPos = *(int*)&(header[0x0A]);
    imageSize = *(int*)&(header[0x22]);
    width = *(int*)&(header[0x12]);
    height = *(int*)&(header[0x16]);
    printf("width : %d   hight : %d\n", width, height);
    data = new unsigned char[imageSize];
    cout << imageSize << endl;

    // Read the actual data from the file into the buffer
    fread(data, 1, imageSize, file);

    // Everything is in memory now, the file wan be closed
    fclose(file);

    GLuint textureID;
    glGenTextures(1, &textureID);

    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, textureID);

    // Give the image to OpenGL
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);


    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    glUniform1i(glGetUniformLocation(programHandle, "tex"), 0);


    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void  initVBO()
{
    glGenVertexArrays(1, &vaoHandle);
    glBindVertexArray(vaoHandle);
    glGenBuffers(3, vboHandles);
    GLuint positionBufferHandle = vboHandles[0];
    GLuint colorBufferHandle = vboHandles[1];
    GLuint textureBufferHandle = vboHandles[2];


    glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
    glBufferData(GL_ARRAY_BUFFER, attrib.vertices.size(),&vertices[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle); 
    glBufferData(GL_ARRAY_BUFFER, attrib.colors.size(),&colorData[0], GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, textureBufferHandle);
    if (texCoords.size()>0)
        glBufferData(GL_ARRAY_BUFFER, attrib.texcoords.size(),&texCoords[0], GL_STATIC_DRAW);

    glGenBuffers(1, &elementbuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

    //glBufferData(GL_ELEMENT_ARRAY_BUFFER, shapes[0].mesh.num_face_vertices.size() , &elements[0], GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements.size()*sizeof(unsigned int), &elements[0], GL_STATIC_DRAW);
    cout << "element*sizeof(unsigned int) = " << elements.size()*sizeof(unsigned int) << endl;

    glEnableVertexAttribArray(0); //頂點坐標  
    glEnableVertexAttribArray(1); //頂點顏色 
    glEnableVertexAttribArray(2); //texture

    glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, textureBufferHandle);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

}
void  init()
{
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        std::cout << "Error initializing GLEW: " << glewGetErrorString(err) << std::endl;
    }

    initShader("vert.txt", "frag.txt");

    initVBO();
    LoadTexture();
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glShadeModel(GL_SMOOTH);

}
void  display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //cout << "display--> " << endl;
    //cout << vertices[0] << endl << vertices[1] << endl << vertices[2] << endl;



    t += 0.0001f;
    if (t >= 1)
        t = 0;
    // Set the camera
    glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 1.0f, 100.0f);
    //glm::mat4 Projection = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 0.0f, 10.0f); 
    glm::mat4 View = glm::lookAt(
        glm::vec3(2.5f, 2.0f, 3.0f),
        glm::vec3(0.0f, 0.0f, 0.0f),
        glm::vec3(0.0f, 0.0f, 1.0f)
        );

    glm::mat4 Model = glm::mat4(1.0f);
    Model = glm::rotate(
        Model,
        glm::radians(360.0f*t),
        glm::vec3(0.0f, 0.0f, 1.0f)
        );
    /*Model = glm::scale(
        glm::translate(Model, glm::vec3(0, 0, 0)),
        glm::vec3(2 / maxs, 2 / maxs, 2 / maxs)
        );*/

    GLuint MVP = glGetUniformLocation(programHandle, "mvp");
    glm::mat4 mvp = Projection*View*Model;
    glUniformMatrix4fv(MVP, 1, GL_FALSE, &mvp[0][0]);

    glBindVertexArray(vaoHandle);
    //glDrawArrays(GL_TRIANGLES, 0, attrib.vertices.size());

    //glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
    //glDrawElements(GL_TRIANGLES, attrib.vertices.size(), GL_UNSIGNED_INT, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
    //glBindVertexArray(0);
    //cout << shapes[0].mesh.num_face_vertices.size() << endl;
    glDrawElements(GL_TRIANGLES, elements.size() , GL_UNSIGNED_INT, (void*)0);
    //glDrawElements(GL_QUADS, elements.size(), GL_UNSIGNED_INT, (void*)0);

    glutSwapBuffers();
}
void Reshape(int w, int h)
{
    if (h == 0)
        h = 1;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, (GLfloat)w / (GLfloat)h, 0.1, 1000.0);
    //glOrtho(-25,25,-2,2,0.1,100);
    glMatrixMode(GL_MODELVIEW);
}
void  keyboard(unsigned  char  key, int  x, int  y)
{
    switch (key)
    {
    case  27:
        glDeleteShader(vShader);
        glUseProgram(0);
        exit(0);
        break;
    }

}

void normalize(){

    std::vector<float> xVector, yVector, zVector;
    float minX = 0, maxX = 0, minY = 0, maxY = 0, minZ = 0, maxZ = 0;

    // find out min and max value of X, Y and Z axis
    for (int i = 0; i < attrib.vertices.size(); i++)
    {
        maxs = max(maxs, attrib.vertices.at(i));
        if (i % 3 == 0)
        {

            xVector.push_back(attrib.vertices.at(i));

            if (attrib.vertices.at(i) < minX)
            {
                minX = attrib.vertices.at(i);
            }

            if (attrib.vertices.at(i) > maxX)
            {
                maxX = attrib.vertices.at(i);
            }
        }
        else if (i % 3 == 1)
        {
            yVector.push_back(attrib.vertices.at(i));

            if (attrib.vertices.at(i) < minY)
            {
                minY = attrib.vertices.at(i);
            }

            if (attrib.vertices.at(i) > maxY)
            {
                maxY = attrib.vertices.at(i);
            }
        }
        else if (i % 3 == 2)
        {
            zVector.push_back(attrib.vertices.at(i));

            if (attrib.vertices.at(i) < minZ)
            {
                minZ = attrib.vertices.at(i);
            }

            if (attrib.vertices.at(i) > maxZ)
            {
                maxZ = attrib.vertices.at(i);
            }
        }*/

    }

    float offsetX = (maxX + minX) / 2;
    float offsetY = (maxY + minY) / 2;
    float offsetZ = (maxZ + minZ) / 2;

    /*for (int i = 0; i < attrib.vertices.size(); i++)
    {
        if (offsetX != 0 && i % 3 == 0)
        {
            attrib.vertices.at(i) = attrib.vertices.at(i) - offsetX;
        }
        else if (offsetY != 0 && i % 3 == 1)
        {
            attrib.vertices.at(i) = attrib.vertices.at(i) - offsetY;
        }
        else if (offsetZ != 0 && i % 3 == 2)
        {
            attrib.vertices.at(i) = attrib.vertices.at(i) - offsetZ;
        }
    }


    // Find out the greatest distance of three axis
    float greatestAxis = maxX - minX;
    float distanceOfYAxis = maxY - minY;
    float distanceOfZAxis = maxZ - minZ;

    if (distanceOfYAxis > greatestAxis)
    {
        greatestAxis = distanceOfYAxis;
    }

    if (distanceOfZAxis > greatestAxis)
    {
        greatestAxis = distanceOfZAxis;
    }

    greatestAxis = greatestAxis / 2;



        for (int i = 0; i < attrib.vertices.size(); i++)
        {
            //std::cout << i << " = " << (double)(attrib.vertices.at(i) / greatestAxis) << std::endl;
            attrib.vertices.at(i) = attrib.vertices.at(i) / greatestAxis;
            vertices.push_back(attrib.vertices.at(i));
        }
        for (int i = 0; i < attrib.colors.size(); i++)
            colorData.push_back(attrib.colors.at(i));
        for (int i = 0; i < attrib.texcoords.size(); i++)
            texCoords.push_back(attrib.texcoords.at(i));

        for (int k = 0; k < shapes.size(); k++){
            for (int i = 0; i < shapes[k].mesh.indices.size(); i++){
            elements.push_back(shapes[k].mesh.indices[i].vertex_index);
            //cout << i << " = " << shapes[0].mesh.indices[i].vertex_index<<endl;
            //elements.push_back(shapes[0].mesh.indices[i].texcoord_index);
            //elements.push_back(shapes[0].mesh.indices[i].normal_index);
        }
    }
    cout << "shapes[0].mesh.indices.size() = " << shapes[0].mesh.indices.size() << endl;
    //cout << "elements = " << elements[4750] << endl;
}
int main()
{
    std::string err;
    bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "..//tinyobjloader//models//Van.obj",
        NULL, false);
    normalize();
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB |GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("GLSL Test : Draw a triangle");
    glutReshapeFunc(Reshape);
    init();
    glEnable(GL_DEPTH_TEST);

    //glDepthFunc(GL_LESS);
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(display);
    glutMainLoop();

    return  0;
}

This is my vertex.shader,I use shader compiler,there are no error.

#version 400  
in vec3 Color;  
in vec2 texcoord;
out vec4 FragColor;  
uniform sampler2D tex;

void  main()  
{  
    FragColor =  texture(tex, vec2(texcoord.x,texcoord.y))*vec4(Color, 1.0);
    //FragColor = vec4(1, 0, 0, 1);
    //if(Color.x>=0)FragColor = vec4(Color, 1.0);
}  

This is my fragment.shader,I use shader compiler,there are no error.

#version 400  
in vec3 Color;  
in vec2 texcoord;
out vec4 FragColor;  
uniform sampler2D tex;

void  main()  
{  
    FragColor =  texture(tex, vec2(texcoord.x,texcoord.y))*vec4(Color, 1.0);
}  

Solution

  • I cite the comment from kevin su above:

    finally,I find the answer. attrib.vertices.size() should be change to sizeof(vertices). attrib.vertices.size() is number of points,and sizeof(vertices) is number of (points * sizeof(unsign int)).