OpenGL — движущийся объект с использованием Modelmatrix

Я работаю над проектом OpenGL. В этом проекте я хотел бы смоделировать 3D-игру в шахматы на С++. Конечно, части должны быть подвижными по желанию. Шахматная доска и фигуры уже отображаются с включенными текстурами.

Я работал над преобразованием частей. В моем классе моделей все важные параметры, такие как вершины, индексы, числовые вершины, числовые индексы и т. д., считываются из соответствующей модели. Это происходит в конструкторе этого класса.

Я также создаю единичную матрицу (glm::mat4(1.0f)) для каждой модели в конструкторе класса модели.

После того, как все параметры прочитаны, я помещаю их в vector<Mesh*>.

В классе сетки вершины и индексы сначала загружаются в буфер вершин/индексов в конструкторе.

Расположение юниформ-переменной в вершинном шейдере для матрицы моей модели также вычисляется в конструкторе.

В функции рендеринга класса сетки буфер вершин/индексный буфер привязан, и установлены все юниформы. В конце функции я вызываю glDrawElements.

В вершинном шейдере я умножаю матрицу модели, viewProjectionMatrix и vec4(a_position, 1.0f) на gl_Position. Если единичная матрица в конструкторе класса модели — glm::mat4(1.0f), модель отображается нормально.

Но если я трансформирую, масштабирую или поворачиваю матрицу в конструкторе для целей тестирования, больше ничего не отображается. Я сделал ошибку в том, как я это делаю, или я на правильном пути?

#pragma once
#include <vector>
#include <fstream>

#include "libs/glm/glm.hpp"
#include "shader.h"
#include "vertexbuffer.h"
#include "indexbuffer.h"
#include "mesh.h"
#include <cassert>


class Model {

public:
    Model(const char* filename, Shader* shader) {

        this->shader = shader;
        modelmatrix = glm::mat4(1.0f); 
        //modelmatrix = glm::scale(modelmatrix, glm::vec3(10));
        std::ifstream input = std::ifstream(filename, std::ios::in | std::ios::binary); 
        uint64 numMeshes;
        uint64 numMaterials;

        
        input.read((char*)&numMaterials, sizeof(uint64));
        for (uint64 i = 0; i < numMaterials; i++) {
            Material material = {};
            input.read((char*)&material, sizeof(BMFMaterial)); 

            
            uint64 diffuseMapNameLenght = 0;
            input.read((char*)&diffuseMapNameLenght, sizeof(uint64)); 
            std::string diffuseMapName(diffuseMapNameLenght, '\0'); 
            input.read((char*)&diffuseMapName[0], diffuseMapNameLenght); 

            uint64 normalMapNameLenght = 0;
            input.read((char*)&normalMapNameLenght, sizeof(uint64)); 
            std::string normalMapName(normalMapNameLenght, '\0'); 
            input.read((char*)&normalMapName[0], normalMapNameLenght); 

            if (diffuseMapNameLenght > 0) {
                std::cout << filename << " successfully loaded" << std::endl;
            }
            else {
                std::cout << filename << " failed loading" << std::endl;
            }

            int32 textureWidth = 0;
            int32 textureHeight = 0;
            int32 bitsPerPixel = 0;
            glGenTextures(2, &material.diffuseMap); 
            stbi_set_flip_vertically_on_load(true);

            auto textureBuffer = stbi_load(diffuseMapName.c_str(), &textureWidth, &textureHeight, &bitsPerPixel, 4); //Map geladen und in Buffer drinnen      
            glBindTexture(GL_TEXTURE_2D, material.diffuseMap);
            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);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer); //Texture in Grafikkarte geladen

           
            if (textureBuffer) {
                stbi_image_free(textureBuffer);
            }

            auto textureBuffer2 = stbi_load(normalMapName.c_str(), &textureWidth, &textureHeight, &bitsPerPixel, 4); //Map geladen und in Buffer drinnen      
            glBindTexture(GL_TEXTURE_2D, material.normalMap);
            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);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer2); //Texture in Grafikkarte geladen

            
            if (textureBuffer2) {
                stbi_image_free(textureBuffer2);
            }

            glBindTexture(GL_TEXTURE_2D, 0); 
            materials.push_back(material); 
        }


        input.read((char*)&numMeshes, sizeof(uint64)); 
        for (uint64 i = 0; i < numMeshes; i++) {

            input.read((char*)&materialIndex, sizeof(uint64)); 
            input.read((char*)&numVertices, sizeof(uint64)); 
            input.read((char*)&numIndices, sizeof(uint64)); 


            for (uint64 i = 0; i < numVertices; i++) {
                Vertex vertex;
                input.read((char*)&vertex.position.x, sizeof(float));
                input.read((char*)&vertex.position.y, sizeof(float));
                input.read((char*)&vertex.position.z, sizeof(float));
                input.read((char*)&vertex.normal.x, sizeof(float));
                input.read((char*)&vertex.normal.y, sizeof(float));
                input.read((char*)&vertex.normal.z, sizeof(float));
                input.read((char*)&vertex.textureCoord.x, sizeof(float));
                input.read((char*)&vertex.textureCoord.y, sizeof(float));

                vertices.push_back(vertex);
            }
            for (uint64 i = 0; i < numIndices; i++) {
                uint32 index;
                input.read((char*)&index, sizeof(uint32));
                indices.push_back(index);
            }

            Mesh* mesh = new Mesh(vertices, numVertices, indices, numIndices, materials[materialIndex], shader, modelmatrix); //Mesh laden 
            meshes.push_back(mesh);
        }

    }

    
    void render() {

       
        for (Mesh* mesh : meshes) {
            mesh->render();
        }

    }

    ~Model() {
        for (Mesh* mesh : meshes) {
            delete mesh;
        }
    }

private:
    std::vector<Mesh*> meshes; 
    std::vector<Material> materials; 

    glm::mat4 modelmatrix;
    std::vector<Vertex> vertices;
    uint64 numVertices = 0;
    std::vector<uint32> indices;
    uint64 numIndices = 0;
    uint64 materialIndex = 0;
    Shader* shader;
};
#pragma once
#include <iostream>
#include <vector>
#include <fstream>
#include "libs/glm/mat4x4.hpp"
#include "libs/glm/glm.hpp"
#include "shader.h"
#include "vertexbuffer.h"
#include "indexbuffer.h"
#include "libs/stb_image.h"

struct BMFMaterial {
    glm::vec3 diffuse;
    glm::vec3 specular;
    glm::vec3 emissive;
    float shininess;
};

struct Material {       
    BMFMaterial material;
    GLuint diffuseMap; 
    GLuint normalMap;
};

class Mesh {
        
public:
    
    Mesh(std::vector<Vertex>& vertices, uint64 numVertices, std::vector<uint32>&indices, uint64 numIndices, Material material, Shader* shader, glm::mat4 modelmatrix) {
        this->material = material;
        this->shader = shader;
        this->numIndices = numIndices;
        this->modelmatrix = modelmatrix;

       
        vertexBuffer = new VertexBuffer(vertices.data(), numVertices);
        indexBuffer = new IndexBuffer(indices.data(), numIndices, sizeof(indices[0]));

        
        diffuseLocation = glGetUniformLocation(shader->getShaderID(), "u_material.diffuse");
        specularLocation = glGetUniformLocation(shader->getShaderID(), "u_material.specular");
        emissiveLocation = glGetUniformLocation(shader->getShaderID(), "u_material.emissive");
        shininessLocation = glGetUniformLocation(shader->getShaderID(), "u_material.shininess");
        diffuseMapLocation = glGetUniformLocation(shader->getShaderID(), "u_diffuse_map");
        modelmatrixlocation = glGetUniformLocation(shader->getShaderID(), "u_modelmatrix");
    }

    ~Mesh() { 
        delete vertexBuffer;
        delete indexBuffer;
    }

    inline void render() {
        std::cout << glm::to_string(modelmatrix) << std::endl;
        vertexBuffer->bind();
        indexBuffer->bind();
        
        glUniformMatrix4fv(modelmatrixlocation, 1, GL_FALSE, &modelmatrix[0][0]);
        glUniform3fv(diffuseLocation, 1, (float*)&material.material.diffuse[0]);
        glUniform3fv(specularLocation, 1, (float*)&material.material.specular[0]);
        glUniform3fv(emissiveLocation, 1, (float*)&material.material.emissive[0]);
        glUniform1f(shininessLocation, material.material.shininess);
        glBindTexture(GL_TEXTURE_2D, material.diffuseMap);
        glUniform1i(diffuseMapLocation, 0); 
       glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, 0); 

    }
private:
    VertexBuffer* vertexBuffer;
    IndexBuffer* indexBuffer;
    Shader* shader;
    Material material;
    uint64 numIndices = 0;
    glm::mat4 modelmatrix;
    
    int diffuseLocation; 
    int specularLocation;
    int emissiveLocation;
    int shininessLocation;
    int diffuseMapLocation;
    int modelmatrixlocation;
};
    while (!close) { //GAMELOOP
        camera.update();
            
            //model = glm::rotate(model, glm::radians(rotation = 1.0f), glm::vec3(1.0f, 0.0f, 0.0f));
            modelViewProj = camera.getViewProj();//*model //Pro Frame jedes mal neu berechnen
            glm::mat4 modelView = camera.getView(); //*model
            glm::mat4 invModelView = glm::transpose(glm::inverse(modelView));
    
            glm::vec4 sunDirectionCamera = glm::transpose(glm::inverse(camera.getView())) * glm::vec4(sunDirection, 1.0f); //sunDirection ist abhänging von Kamera, weil Licht wird im viewspace berechnet
            glUniform3fv(directionLocationDirection, 1, (float*)&sunDirectionCamera[0]); //aktivieren
            glm::mat4 pointLightMatrix = glm::mat4(1.0f); //Für Matrixmultiplikation weil der Punkt nicht immer am gleichen Punkt bleiben soll
            pointLightPosition = pointLightPosition * pointLightMatrix; //Position ändert sich, rotiert nun um y-Achse
            glm::vec3 transformedPointLightPosition = (glm::vec3)(camera.getView() * pointLightPosition); //Transformierte Position im Viewspace 
            glUniform3fv(positionLocationPoint, 1, (float*)&transformedPointLightPosition[0]);
    
            glUniformMatrix4fv(modelViewProjMatrixLocation, 1, GL_FALSE, &modelViewProj[0][0]); //Matrix setzen/aktivieren
            glUniformMatrix4fv(modelViewLocation, 1, GL_FALSE, &modelView[0][0]);
            glUniformMatrix4fv(invModelViewLocation, 1, GL_FALSE, &invModelView[0][0]);
            
            //Brett und Figuren rendern/zeichnen
            whitepawnA2.render();
            board.render();
            
            /*
            whitebishopright.render();
            whitebishopleft.render();
            whiteking.render();
            whiteknightleft.render();
            whiteknightright.render();
            whiterookleft.render();
            whiterookright.render();
            whitequeen.render();
            whitepawnH2.render();
            whitepawnG2.render();
            whitepawnF2.render();
            whitepawnE2.render();
            whitepawnD2.render();
            whitepawnC2.render();
            whitepawnB2.render();
    
            blackknightleft.render();
            blackknightright.render();
            blackking.render();
            blackbishopleft.render();
            blackbishopright.render();
            blackqueen.render();
            blackrookleft.render();
            blackrookright.render();
            blackpawnA.render();
            blackpawnB.render();
            blackpawnC.render();
            blackpawnD.render();
            blackpawnE.render();
            blackpawnF.render();
            blackpawnG.render();
            blackpawnH.render();
    */
            SDL_GL_SwapWindow(window); //double buffer aktivieren
    
            //FPS COUNTER
            uint64 endCounter = SDL_GetPerformanceCounter();
            uint64 counterElapsed = endCounter - lastCounter;
            delta = ((float32)counterElapsed) / (float32)perfCounterFrequency; //Zeit die seit letztem Frame vergangen ist
            uint32 FPS = (uint32)((float32)perfCounterFrequency / (float32)counterElapsed);
            //std::cout << FPS << std::endl;
            lastCounter = endCounter;
        }
    return 0;
    }
    #include "shader.h"
    #include <fstream>
    #include <iostream>
    
    
    Shader::Shader(const char* vertexShaderFilename, const char* fragmentShaderFilename) {
        shaderID = createShader(vertexShaderFilename, fragmentShaderFilename);
    }
    
        Shader::~Shader() {
            glDeleteProgram(shaderID);
        }
    
        void Shader::bind() {
            glUseProgram(shaderID);
        }
    
        void Shader::unbind() {
            glUseProgram(0);
        }
    
        GLuint Shader::getShaderID() {
            return shaderID;
        }
    
        GLuint Shader::compile(std::string shaderSource, GLenum type) { //Shadersourcecode so kompiliert werden
            GLuint id = glCreateShader(type);
            const char* src = shaderSource.c_str();
            glShaderSource(id, 1, &src, 0);
            glCompileShader(id);
    
            int result;
            glGetShaderiv(id, GL_COMPILE_STATUS, &result);
            if (result != GL_TRUE) {
                int length = 0;
                glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
                char* message = new char[length];
                glGetShaderInfoLog(id, length, &length, message);
                std::cout << "Shader compilation error: " << message << std::endl;
                delete[] message;
                return 0;
            }
            return id;
            
        }
    
        std::string Shader::parse(const char* filename) {
            FILE* file;
    #ifdef _WIN32
            if (fopen_s(&file, filename, "rb") != 0) {
                std::cout << "File " << filename << " not found" << std::endl;
                return "";
            }
    #else
            file = fopen(filename, "rb");
            if (file == nullptr) {
                std::cout << "File " << filename << " not found" << std::endl;
                return "";
            }
    #endif
            std::string content; //Dateininhalt
            fseek(file, 0, SEEK_END); //ans ende der datei gehen
            size_t filesize = ftell(file); //wie weit ist man im file
            rewind(file); //wieder zurückgehen
            content.resize(filesize); //file resizen damit man nicht zu wenig oder zu viel speicher reserviert
            fread(&content[0], 1, filesize, file); //&content[0] gibt adresse auf speicherbereich - 1 ganze filesize soll gelesen werden - 
            fclose(file); //file wieder schließen
            return content; //code returnen
        }
        GLuint Shader::createShader(const char* vertexShaderFilename, const char* fragmentShaderFilename) {
            std::string vertexShaderSource = parse(vertexShaderFilename); //Sourcecode speichern
            std::string fragmentShaderSource = parse(fragmentShaderFilename);
    
            GLuint program = glCreateProgram(); //program erstellen
            GLuint vs = compile(vertexShaderSource, GL_VERTEX_SHADER); //shader erstellen
            GLuint fs = compile(fragmentShaderSource, GL_FRAGMENT_SHADER);
    
            glAttachShader(program, vs); //shader wird program hinzugefügt
            glAttachShader(program, fs);
    
            glLinkProgram(program); //executable erstellt und läuft auf vertex
            
            //Solange program gelinked ist, kann alles wieder deattached und gelöscht werden - spart speicherplatz
    #ifdef _RELEASE
            glDetachShader(progam, vs);
            glDetachShader(program, fs);
    
            glDeleteShader(vs);
            glDeleteShader(fs);
    #endif
            return program;
    }
    //Vertexshader soll Position von Vertex berechnen
    #version 330 core
    //INPUTS IN DEN SHADER
    layout(location = 0) in vec3 a_position; //layout location 0 -> 1 Attribut
    layout(location = 1) in vec3 a_normal;
    layout(location = 2) in vec2 a_tex_coord;
    
    //OUTPUTS
    out vec3 v_normal;
    out vec3 v_position;
    out vec2 v_tex_coord;
    
    uniform mat4 u_modelmatrix;
    uniform mat4 u_modelView;
    uniform mat4 u_modelViewProj;
    
    uniform mat4 u_invModelView;
    
    
    void main()
    {
        gl_Position = u_modelmatrix * u_modelViewProj * vec4(a_position, 1.0f); //vec4 für Matrixmultiplikationen - Position in positionsvariable - 1.0f -> 4 Koordinate
        v_normal = mat3(u_invModelView) * a_normal; //Normalevktor berechnen
        v_position = vec3(u_modelView * vec4(a_position, 1.0f)); //Position des Fragments berechnen
        v_tex_coord = a_tex_coord;
    } 

Почему этот вопрос выглядит так, как будто он был создан ИИ?

Irelia 13.02.2023 23:20

Я написал текст на немецком и только что перевел на английский :)

Julian 13.02.2023 23:37
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
0
2
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для любого будущего читателя:

Правильнее будет вопрос.

Почему мои объекты исчезли после применения трансформации?

После моего первоначального предположения, которое вы можете увидеть ниже, OP опубликовал более подробный код, и в конце концов я обнаружил ошибку в программе шейдера.

Умножение матрицы было в неправильном порядке:

// OP's original code
gl_Position = u_modelmatrix * u_modelViewProj * vec4(a_position, 1.0f);
// Good order
gl_Position = projection * view * model * vec4(aPos, 1.0);

Обратный порядок также может быть хорошим в зависимости от порядка матрицы

Хороший туториал про трансформации и системы координат


Оригинальный ответ

Вы не предоставили каждую часть своего кода, поэтому я могу только догадываться. Я предполагаю, что в вашем классе шейдеров вы создаете шейдерную программу, а затем правильно выполняете компоновку.

Но чтобы обновить униформы в шейдере, вы должны сообщить OpenGL, какую программу шейдера использовать, вызвав:

glUseProgram(shader->getShaderID());
//and then
glUniformMatrix4fv(...);
...

Обычно это делается в функции render() (особенно важно, если вы используете несколько шейдеров), и я не вижу этого в вашем коде.

Может потребоваться дополнительный код, чтобы найти проблему, если она связана с чем-то другим (где вы вызываете функцию render() и что там происходит? как выглядит ваша шейдерная программа?).

Спасибо за помощь! Я вызываю функцию render() в своем основном игровом цикле. В игровом цикле сначала вычисляются ViewProjectionMatrix и View matrix. Затем происходит расчет освещения. Затем я загружаю матрицы в шейдер, и модели рендерятся. Я включил туда gameloop и свою шейдерную программу. Спасибо.

Julian 14.02.2023 11:38

Проверяя ваш шейдер, умножение матриц может быть в неправильном порядке. Лучше всего, насколько я знаю, порядок должен быть gl_Position = projection * view * model * vec4(aPos, 1.0);, и это может вызвать проблемы, если вы поменяете его местами.

Szala 14.02.2023 21:28

Если это вызывает проблему, вы можете найти гораздо более подробное дополнительное объяснение здесь: stackoverflow.com/questions/17717600/…

Szala 14.02.2023 21:39

А также здесь: stackoverflow.com/questions/23521089/…

Szala 14.02.2023 21:50

Ты прав. Умножение матриц было в неправильном порядке. Я даже не знал, что есть определенный порядок, которому ты должен следовать. Спасибо большое!!

Julian 14.02.2023 23:33

Другие вопросы по теме