波前OBJ模型不渲染- openglc++

Wavefront OBJ Model Not Rendering - OpenGL C++

本文关键字:openglc++ OBJ 模型 波前      更新时间:2023-10-16

我似乎无法在c++中使用glDrawElements渲染OBJ模型。

下面是我的代码:
#include <iostream>
#include <stdio.h>
#include <vector>
#include <fstream>
#include "Object.h"
#define BUFFER_OFFSET(i) ((char *)NULL + (i))

class Model : public object
{
private:
    struct  Vertex
    {
        CBfloat v1, v2, v3;
        CBfloat vn1, vn2, vn3;
        CBfloat vt1, vt2;
        Vertex(vec3 _position, vec3 _normal, vec2 _texCoord)
        {
            v1 = _position[0];
            v2 = _position[1];
            v3 = _position[2];
            vn1 = _normal[0];
            vn2 = _normal[1];
            vn3 = _normal[2];
            vt1 = _texCoord[0];
            vt2 = _texCoord[1];
        }
    };
    struct  Face
    {
        CBuint v[3];
        CBuint vt[3];
        CBuint vn[3];
        CBuint mat_id;
        Face(CBuint v1, CBuint vt1, CBuint vn1, CBuint v2, CBuint vt2, CBuint vn2, CBuint v3, CBuint vt3, CBuint vn3) : mat_id(-1)
        {
            v[0] = v1;
            vt[0] = vt1;
            vn[0] = vn1;
            v[1] = v2;
            vt[1] = vt2;
            vn[1] = vn2;
            v[2] = v3;
            vt[2] = vt3;
            vn[2] = vn3;
        }
    };
    struct  Mesh
    {
        CBuint vbo;
        CBuint ebo;
        Mesh() {}
        Mesh(std::vector <Vertex>& v, std::vector <CBuint>& i)
        {
            // Generate
            glGenBuffers(1, &vbo);
            glGenBuffers(1, &ebo);
            // Bind
            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
            // Buffer
            glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(Vertex), &v[0], GL_STATIC_DRAW);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(CBuint) * 3, &i[0], GL_STATIC_DRAW);
            // Set attribs
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
            glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(v) * 3));
            glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(v) * 5));
            // Enable attribs
            glEnableVertexAttribArray(0);
            glEnableVertexAttribArray(1);
            glEnableVertexAttribArray(2);
            // Clean up
            glBindVertexArray(0);
        }
        ~Mesh()
        {
            glDeleteBuffers(1, &vbo);
            glDeleteBuffers(1, &ebo);
        }
    };
    // Local variables
    CBuint                      _vao;
    bool                        _materialised;
    std::string                 _obj_url;
    std::string                 _mtl_url;
    std::vector <std::string>   _material_element;
    std::vector <Vertex>        _vertices;
    std::vector <CBuint>        _indices;
    std::vector <Mesh*>         _meshes;
    std::vector <Material*>     _materials;
public:
    Model(Shader* shader) : _materialised(false) {}
    Model(Shader* shader, const char* obj_file) : _materialised(false)
    {
        // Load OBJ file
        if (loadOBJ(obj_file) != 1)
            std::cout << "Error: Failed to load OBJ!" << std::endl;
        // Load MTL file
        if (_materialised)
        {
            if (loadMTL(shader, _mtl_url.c_str()) != 1)
                std::cout << "Error: Failed to load MTL file!" << std::endl;
        }
        // Apply material if none were applied
        if (!_materialised)
        {
            _materials.push_back(new Material(shader, "default_m",false, false, 1.0f, vec3(1.0f, 1.0f, 1.0f), vec3(0.25f, 0.25f, 0.25f), 1.0f, 8.0f, 1.0f));
            _materialised = true;
        }
        // Initialise matrix
        initialiseMatrix(shader);
    }
    ~Model()
    {
        if (!_indices.empty())
            clear();
        glDeleteVertexArrays(1, &_vao);
    }
    inline CBvoid clear()
    {
        _vertices.clear();
        _indices.clear();
        _materials.clear();
        _meshes.clear();
    }
    inline CBint loadOBJ(const char* file)
    {
        this->_obj_url = file;
        // Check for valid file
        std::ifstream _in(file);
        if (!_in)
        {
            std::cout << "Error: OBJ file is invalid!" << std::endl;
            return -1;
        }
        else if (!_in.is_open())
        {
            std::cout << "Error: Cannot open OBJ file!" << std::endl;
            return -1;
        }
        // Get data
        char data[256];
        std::vector <std::string> line;
        while (_in.getline(data, 256))
            line.push_back(data);
        // Assign vertex data
        std::vector <vec3>  _v;
        std::vector <vec3>  _vn;
        std::vector <vec2>  _vt;
        std::vector <Face>  _f;
        for (unsigned int i = 0; i < line.size(); i++)
        {
            switch ((line[i])[0])
            {
            case '#':
                continue;
            case '':
                continue;
            case 'm':
                char mtl_url[128];
                sscanf_s((&line[i])[0].c_str(), "mtllib %s", mtl_url, sizeof(mtl_url));
                _mtl_url = mtl_url;
                _materialised = true;
                break;
            case 'v':
                float x, y, z;
                if ((line[i])[1] == 'n')
                {
                    sscanf_s((&line[i])[0].c_str(), "vn %f %f %f", &x, &y, &z);
                    _vn.push_back(vec3(x, y, z));
                }
                if ((line[i])[1] == 't')
                {
                    sscanf_s((&line[i])[0].c_str(), "vt %f %f", &x, &y);
                    _vt.push_back(vec2(x, y));
                }
                else if ((line[i])[1] == ' ')
                {
                    sscanf_s((&line[i])[0].c_str(), "v %f %f %f", &x, &y, &z);
                    _v.push_back(vec3(x, y, z));
                }
                break;
            case 'u':
                char material_element[128];
                sscanf_s((&line[i])[0].c_str(), "usemtl %s", &material_element, sizeof(material_element));
                // Assign new material to element
                if (_material_element.size() > 1)
                    _f[_f.size() - 1].mat_id = _material_element.size();
                _material_element.push_back(material_element);
                break;
            case 'f':
                CBuint v_i[3];
                CBuint vn_i[3];
                CBuint vt_i[3];
                sscanf_s((&line[i])[0].c_str(), "f %d/%d/%d %d/%d/%d %d/%d/%d", &v_i[0], &vt_i[0], &vn_i[0], &v_i[1], &vt_i[1], &vn_i[1], &v_i[2], &vt_i[2], &vn_i[2]);
                // Faces
                _f.push_back(Face(v_i[0], vt_i[0], vn_i[0], v_i[1], vt_i[1], vn_i[1], v_i[2], vt_i[2], vn_i[2]));
                // Indices
                _indices.push_back(v_i[0] - 1);
                _indices.push_back(vt_i[0] - 1);
                _indices.push_back(vn_i[0] - 1);
                _indices.push_back(v_i[1] - 1);
                _indices.push_back(vt_i[1] - 1);
                _indices.push_back(vn_i[1] - 1);
                _indices.push_back(v_i[2] - 1);
                _indices.push_back(vt_i[2] - 1);
                _indices.push_back(vn_i[2] - 1);
                break;
            }
        }

        // Optimise vertices
        for (CBuint i = 0; i < _v.size(); i++)
            _vertices.push_back(Vertex(_v[i], vec3(0.0f, 0.0f, 0.0f), vec2(1.0f, 1.0f)));
        // Optimise buffers
        CBuint next_element = 0;
        glGenVertexArrays(1, &_vao);
        glBindVertexArray(_vao);
        if (_materials.size() > 1)
        {
            for (CBuint i = 0; i < _f.size(); i++)
            {
                if (_f[i].mat_id == next_element)
                {
                    _meshes.push_back(new Mesh(_vertices, _indices));
                    next_element++;
                }
            }
        }
        else
            _meshes.push_back(new Mesh(_vertices, _indices));
        glBindVertexArray(0);

        // Output
        std::cout << "v: " << _v.size() << std::endl;
        std::cout << "vn: " << _vn.size() << std::endl;
        std::cout << "vt: " << _vt.size() << std::endl;
        std::cout << "f: " << _f.size() << std::endl;
        std::cout << "vertices: " << _vertices.size() << std::endl;
        std::cout << "indices: " << _indices.size() << std::endl;
        std::cout << "meshes: " << _meshes.size() << std::endl;
        std::cout << "materials: " << _materials.size() << std::endl;
        // Close file and return
        _in.close();
        return 1;
    }
    inline CBint loadMTL(Shader* shader, const char* file)
    {
        // ----------------- MTL pipeline -----------------
        // ----------------------------------------------------
        // Ns - specular exponent multiplied by the texture value
        // d  - dissolve multiplied by the texture value
        // Ka - ambient colour multiplied by the texture value
        // Kd - diffuse colour multiplied by the texture value
        // Ks - specular colour multiplied by the texture value
        // Ke - emissive colour multiplied by the texture value
        // map_* - texture map multiplied by the texture value
        // bump - normal map multiplied by the texture value

        // Check file
        std::ifstream in_file(file);
        if (!in_file)
        {
            std::cout << "Error: MTL file is invalid!" << std::endl;
            return -1;
        }
        else if (!in_file.is_open())
        {
            std::cout << "Error: MTL file failed to open!" << std::endl;
            return -1;
        }
        // Push_back materials from elements in obj
        for (unsigned int i = 0; i < _material_element.size(); i++)
            _materials.push_back(new Material(shader, _material_element[i], false, false, 1.0f, vec3(1.0f, 1.0f, 1.0f), vec3(0.5f, 0.5f, 0.5f), 0.75f, 8.0f, 1.0f));
        // Get data
        char data[256];
        std::vector <std::string> line;
        while (in_file.getline(data, 256))
            line.push_back(data);
        // Assign data
        CBint  current_material_element = -1;
        for (unsigned int i = 0; i < line.size(); i++)
        {
            switch ((line[i])[0])
            {
            case '#':
                continue;
            case '':
                continue;
            case 'n':
                current_material_element++;
                break;
            case 't':
                if ((line[i])[1] == 'N' && (line[i])[2] == 's')
                {
                    float _Ns = 0.0f;
                    sscanf_s((&line[i])[0].c_str(), "tNs %f", &_Ns);
                    _materials[current_material_element]->_specular_damper = _Ns;
                }
                else if ((line[i])[1] == 'd')
                {
                    float _d = 0.0f;
                    sscanf_s((&line[i])[0].c_str(), "td %f", &_d);
                    _materials[current_material_element]->_opacity = _d;
                }
                else if ((line[i])[1] == 'K' && (line[i])[2] == 'd')
                {
                    vec3 _Kd = vec3(0.0f);
                    sscanf_s((&line[i])[0].c_str(), "tKd %f %f %f", &_Kd.data[0], &_Kd.data[1], &_Kd.data[2]);
                    _materials[current_material_element]->_diffuse = _Kd;
                }
                else if ((line[i])[1] == 'K' && (line[i])[2] == 's')
                {
                    vec3 _Ks = vec3(0.0f);
                    sscanf_s((&line[i])[0].c_str(), "tKs %f %f %f", &_Ks.data[0], &_Ks.data[1], &_Ks.data[2]);
                    _materials[current_material_element]->_specular = _Ks;
                }
                break;
            }
        }
        return 1;
    }
    virtual void update(double delta)
    {
        tickMatrix();
        // TEMP!
        _rotation = vec4(20.0f, 0.0f, 1.0f, 0.0f);
    }
    virtual void render()
    {
        glUniformMatrix4fv(_u_model, 1, GL_FALSE, _model);
        _materials[0]->bind();
        glBindVertexArray(_vao);
        glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    }
};

当硬编码顶点和索引时,我可以渲染一个简单的三角形,所以它不能是着色器问题。我已经彻底检查了索引顶点优化部分,看不到任何问题,即使与其他示例比较后。

有任何想法,更正,解决方案或诸如此类的东西吗?

编辑:立方体模型呈现,但现在我遇到了一个新的问题-在渲染三角形时,索引似乎被双重交叉打乱了:

点击我截图!

这是同一个立方体。对象模型,但处于点亮模式:

点击查看点亮模式!

顶点着色代码:

#version 330 core
// Vertex attributes
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoord;
// Node parses
out vec2 TexCoord;
out vec3 Normal;
out vec3 Fragpos;
// Uniforms
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
// Vertex loop
void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);   
    Normal =  mat3(transpose(inverse(model))) * normal;
    Fragpos = vec3(model * vec4(position, 1.0f));
    TexCoord = texCoord;
}

片段着色器代码:

#version 330 core

// Node parses
out vec4 color;
in vec2 TexCoord;
in vec3 Normal;
in vec3 Fragpos;
// Camera data
uniform vec3    view_loc;
vec3            view_dir;
// Model data
vec3    normal;
// Phong data
vec3    _ambient;
vec3    _diffuse;
vec3    _specular;
vec3    _emissive;
vec3    _result;
// Material uniforms
uniform struct MATERIAL
{
    bool    masked;
    bool    additive;
    float   opacity;
    float   specular_damper;
    float   specular_intensity;
    float   emissive_intensity;
    vec3    diffuse;
    vec3    specular;   
} _mat;
uniform sampler2D texture[3];
// Global uniforms
uniform struct GLOBAL
{
    float   ambient_coefficient;
    vec3    ambient_colour;
} _global;
// Directional uniforms
uniform struct DIRECTIONAL
{
    float   intensity;
    vec3    position;
    vec3    colour;
} _dir;
vec3 d_view_dir;
// Directional light
vec3 directional()
{
    vec3 r;
    d_view_dir = normalize(-_dir.position);
    float src = max(dot(normal, d_view_dir),0.0);
    r = (src * _dir.colour) * _dir.intensity;
    return r;
}
// Final gather
vec4 finalGather()
{
    normal = normalize(Normal);
    view_dir = normalize(view_loc - Fragpos);
    // Ambient
    _ambient = _global.ambient_coefficient * _mat.diffuse * _dir.intensity;
    // Diffuse
    _diffuse = _mat.diffuse * directional();
    // Specular 
    vec3 reflectDir = reflect(-d_view_dir, normal);
    float power = pow(max(dot(view_dir, reflectDir), 0.0), _mat.specular_damper);
    _specular = (_mat.specular) * power * _dir.colour * _dir.intensity;
    // Emissive

    // Final result
    _result = (_ambient + _diffuse + _specular);
    //_diffuse;
    return  vec4(_result, _mat.opacity);
}
// Main loop
void main(void)
{
    color = vec4(finalGather());
}

可能是缓冲区偏移量问题吗?谢谢大家的帮助!

您发布了大量代码,因此可能存在比下面指出的更多的错误。此外,即使你正确加载和渲染了你的对象,它仍然可以不显示各种原因,例如,因为坐标在视图体积之外。

从一个快速的看,我看到两个错误的代码,你加载几何到缓冲区,并设置顶点属性:

glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(Vertex), &v[0], GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(CBuint) * 3, &i[0], GL_STATIC_DRAW);

在第二个调用中,您只将3个索引加载到索引缓冲区。您必须根据相应向量的大小计算所有索引的大小,就像您对第一次调用所做的那样:

glBufferData(GL_ELEMENT_ARRAY_BUFFER, i.size() * sizeof(CBuint), &i[0], GL_STATIC_DRAW);

顶点设置中的偏移量也不正确:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(v) * 3));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(v) * 5));

v是一个矢量,所以sizeof(v)是矢量对象的大小,这在这里是无关的。您需要顶点对象内字段的偏移量:

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(CBfloat) * 3));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(CBfloat) * 6));