简体   繁体   English

opengl不正确的模型渲染

[英]opengl incorrect model rendering

I am trying to render some stuff using openGL. 我正在尝试使用openGL渲染一些东西。 It "works" but is rendering my model incorrectly. 它“起作用”,但渲染模型不正确。 I have looked at several references, and have been unable to tell what is wrong. 我看了几篇参考文献,但无法分辨出什么地方出了问题。 Perhaps an openGL guru could point out my error? 也许一个openGL专家可以指出我的错误?

I am using several libraries such as tinyobjloader, GLM, GLFW, GLEW, etc. Only the parts related to rendering are presented here. 我正在使用几个库,例如tinyobjloader,GLM,GLFW,GLEW等。这里仅介绍与渲染有关的部分。 Some of the code is only developed to the point of rendering a single model. 有些代码仅开发到渲染单个模型的程度。

shader.vs shader.vs

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 norm;
layout (location = 2) in vec2 texCoord;

out vec3 normal;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(position, 2.0f);
    TexCoord = texCoord;
    normal = norm;
}

shader.frag shader.frag

#version 330 core

in vec3 normal;
in vec2 TexCoord;

out vec4 color;

uniform sampler2D ourTexture1;

void main()
{
    color = texture(ourTexture1, TexCoord);
}

graphics.h graphics.h中

#include <string>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

class Shader;

class Graphics{
    public:
        Graphics(std::string, uint, uint);
        ~Graphics();
        void render();
        void clearScreen();
        void draw();
        void loadTexture(std::string);
    private:
        GLFWwindow* window = NULL;
};

class Shader{
    public:
        Shader(std::string, std::string);
        void useShader();
        GLuint shaderprogram;
};

class Mesh{
    public:
        Mesh(std::vector<glm::vec3>, std::vector<glm::vec3>, std::vector<glm::vec2>, std::vector<uint>);
        void draw();
    private:
        GLuint VBO = 0;
        GLuint VBO_tex = 0;
        GLuint VBO_normal = 0;
        GLuint VAO = 0;
        GLuint EBO = 0;
        std::vector<glm::vec3> vertices;
        std::vector<glm::vec3> normals;
        std::vector<uint> indices;
        std::vector<glm::vec2> textures;
};

Mesh loadModel(std::string);

graphics.cpp graphics.cpp

#include <glog/logging.h>
#include "graphics.h"

#include <SOIL/SOIL.h>

#include "tiny_obj_loader.h"

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

Graphics::Graphics(std::string name, uint w, uint h){
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    window = glfwCreateWindow(w, h, name.c_str(), NULL, NULL);
    if(window == NULL){
        LOG(ERROR) << "Failed to create GLFW window";
        glfwTerminate();
    }
    glfwMakeContextCurrent(window);
    glewExperimental = GL_TRUE;
    if(glewInit() != GLEW_OK){
        LOG(ERROR) << "Failed to initialize GLEW";
    }
    glViewport(0, 0, w, h);
};

Graphics::~Graphics(){
    glfwTerminate();
};

void Graphics::render(){
    glfwSwapBuffers(window);
};

void Graphics::clearScreen(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
};

GLuint texture;
void Graphics::loadTexture(std::string path){
    glGenTextures(1, &texture);  
    glBindTexture(GL_TEXTURE_2D, texture);

    int width, height;
    unsigned char* image = SOIL_load_image(path.c_str(), &width, &height, 0, SOIL_LOAD_RGB);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    glGenerateMipmap(GL_TEXTURE_2D);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

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

    //SOIL_free_image_data(image);
    //glBindTexture(GL_TEXTURE_2D, 0);
}

Shader::Shader(std::string vertexstring, std::string fragmentstring){
    GLuint vertexshaderid = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentshaderid = glCreateShader(GL_FRAGMENT_SHADER);

    const char* vertercstring = vertexstring.c_str();
    const char* fragmentcstring = fragmentstring.c_str();

    GLint success; GLchar errordata[512];

    glShaderSource(vertexshaderid, 1, &vertercstring, NULL);
    glCompileShader(vertexshaderid);

    glGetShaderiv(vertexshaderid, GL_COMPILE_STATUS, &success);
    if(!success){
        glGetShaderInfoLog(vertexshaderid, 1024, NULL, errordata);
        LOG(ERROR) << "Vertex Shader Error: " << errordata;
    };

    glShaderSource(fragmentshaderid, 1, &fragmentcstring, NULL);
    glCompileShader(fragmentshaderid);

    glGetShaderiv(fragmentshaderid, GL_COMPILE_STATUS, &success);
    if(!success){
        glGetShaderInfoLog(fragmentshaderid, 1024, NULL, errordata);
        LOG(ERROR) << "fragment Shader Error: " << errordata;
    };

    shaderprogram = glCreateProgram();
    glAttachShader(shaderprogram, vertexshaderid);
    glAttachShader(shaderprogram, fragmentshaderid);
    glLinkProgram(shaderprogram);

    glDeleteShader(vertexshaderid);
    glDeleteShader(fragmentshaderid);
};

void Shader::useShader(){
    glUseProgram(shaderprogram);
};

Mesh::Mesh(std::vector<glm::vec3> v, std::vector<glm::vec3> n, std::vector<glm::vec2> t, std::vector<uint> i){
    vertices = v;
    textures = t;
    normals = n;
    indices = i;

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), &vertices[0], GL_STATIC_DRAW);

    glGenBuffers(1, &VBO_tex);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * textures.size(), &textures[0], GL_STATIC_DRAW);

    glGenBuffers(1, &VBO_normal);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_normal);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * normals.size(), &normals[0], GL_STATIC_DRAW);

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint) * indices.size(), &indices[0], GL_STATIC_DRAW);

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_normal);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
};

void Mesh::draw(){
    glBindVertexArray(VAO);
    glBindTexture(GL_TEXTURE_2D, texture);
    //glDrawArrays(GL_TRIANGLES, 0, vertices.size());
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
};

#include <iostream>
Mesh loadModel(std::string path){

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

    std::string err;
    bool ret = tinyobj::LoadObj(shapes, materials, err, path.c_str());

    std::vector<glm::vec3> vertices;
    std::vector<glm::vec3> normals;
    std::vector<glm::vec2> textures;
    std::vector<uint> indices;

    for(auto shape : shapes){
        std::cout << shape.name << std::endl;
        for(uint i = 0; i < shape.mesh.positions.size(); i+=3){
            glm::vec3 vertex;
            vertex.x = shape.mesh.positions[i];
            vertex.y = shape.mesh.positions[i+1];
            vertex.z = shape.mesh.positions[i+2];
            vertices.push_back(vertex);
        }
        for(uint i = 0; i < shape.mesh.normals.size(); i+=3){
            glm::vec3 vertex;
            vertex.x = shape.mesh.normals[i];
            vertex.y = shape.mesh.normals[i+1];
            vertex.z = shape.mesh.normals[i+2];
            normals.push_back(vertex);
        }
        for(uint i = 0; i < shape.mesh.indices.size(); i++){
            indices.push_back(shape.mesh.indices[i]);
        }
        for(uint i = 0; i < shape.mesh.texcoords.size(); i+=2){
            glm::vec2 vertex;
            vertex.x = shape.mesh.texcoords[i];
            vertex.y = shape.mesh.texcoords[i+1];
            textures.push_back(vertex);
        }
    }

    return Mesh(vertices, normals, textures, indices);
};

main - cut down 主-减少

#include "graphics.h"
Graphics graphics("hai", 640, 480);
Shader shader(readFile("shader.vs"), readFile("shader.frag"));
shader.useShader();
graphics.loadTexture("tempTexture.jpg");
Mesh m = loadModel("treeStump.obj");
graphics.clearScreen();
shader.useShader();
m.draw();
graphics.render();

picture of failed render 失败渲染的图片

As you can see the texture is not drawn on the model properly but it works in blender, and other programs I have loaded it into. 如您所见,纹理没有在模型上正确绘制,但可以在Blender中工作,并且我已将其加载到其他程序中。 This next picture is of a different angle (and in blender) but it is what it should look like. 下一张图片的角度不同(在搅拌机中),但它看起来应该是这样。

picture of correct render 正确渲染的图片

If I need to provide more information please tell me! 如果我需要提供更多信息,请告诉我! Thanks! 谢谢!

You have 2 components for your texture coordinates, which is typical: 您的纹理坐标有2个组件,这是典型的:

glm::vec2 vertex;
vertex.x = shape.mesh.texcoords[i];
vertex.y = shape.mesh.texcoords[i+1];
textures.push_back(vertex);

But this does not match the way you specify the attribute: 但这与您指定属性的方式不匹配:

glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);

The second argument to glVertexAttribPointer() specifies the number of components in the attribute. glVertexAttribPointer()的第二个参数指定属性中组件的数量。 In this case, it should be 2 to match the data: 在这种情况下,匹配数据应为2:

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, NULL);

Also, if you care about performance or power usage at all, you should avoid copying data unnecessarily. 此外,如果您完全关心性能或功耗,则应避免不必要地复制数据。 I count about 4 copies of the vertex data in your code alone. 仅在您的代码中,我就算出了大约4个顶点数据副本。 Add the copies in the OBJ parser, and the ones made by the OpenGL driver, and you'll end up copying the entire vertex data about 7 times before it gets rendered. 将副本添加到OBJ解析器中,再添加OpenGL驱动程序生成的副本,您将最终在渲染整个顶点数据之前将其复制大约7次。 That's a lot of wasted electrons... 那是很多浪费的电子...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM