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
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
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

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