多个对象的 OpenGL 旋转在绘制循环中被覆盖

如何解决多个对象的 OpenGL 旋转在绘制循环中被覆盖

我想创建一个魔方立方体,其中每一面都包含多个立方体。到目前为止,我能够创建整个立方体。我现在想将立方体的一侧向左旋转,为此我创建了一个新矩阵,然后将统一体绑定到该矩阵。这工作正常,但如果我进行第二次操作,比如旋转另一边,我会再次创建一个带有旋转的新矩阵,并将制服绑定到该矩阵。在第二次旋转后绘制我的对象后,我的对象将重置为初始矩阵(旋转已恢复)。

左旋转代码:

glm::mat4 spinLeft(glm::mat4 anim,GLuint shaderProgram,int i) {
     if(i < 9) {
        // createAnim(shaderProgram,anim);
        if(nrRotations <= 900) {
            anim = spinObj(anim,1.0);
            // cout << nrRotations << endl; 
            nrRotations += 1;
            glUniformMatrix4fv(uniformAnim,1,GL_FALSE,glm::value_ptr(anim));

        }
    }
    return anim;
} 

glm::mat4 spinObj(glm::mat4 anim,float orientation) {
    float angle = 0.1f * orientation;

    anim = glm::rotate(anim,glm::radians(angle),glm::vec3(0.0f,0.0f,2.0f));
    
    return anim;
}

正确旋转的代码:

glm::mat4 spinRight(glm::mat4 anim,int i) {
        if(i == RIGHT || i == TOP_RIGHT || i == BOTTOM_RIGHT  
            || i == RIGHT+9 || i == TOP_RIGHT+9 || i == BOTTOM_RIGHT+9  
            || i == RIGHT+18 || i == TOP_RIGHT+18 || i == BOTTOM_RIGHT+18)
        {
            // createAnim(shaderProgram,anim);
            if(nrRotations <= 900) {
                anim = spinObj2(anim,1.0);
                // cout << nrRotations << endl; 
                nrRotations +=1; 
            glUniformMatrix4fv(uniformAnim,glm::value_ptr(anim));

            }
        } 

    return anim;
}

glm::mat4 spinObj2(glm::mat4 anim,float orientation) {
    float angle = 0.1f * orientation;

    anim = glm::translate(anim,-2.1f) );
    anim = glm::rotate(anim,glm::vec3(1.0f,0.0f));
    anim = glm::translate(anim,-(glm::vec3(0.0f,-2.1f)) );


    return anim;
}

负责绘图的代码,vtxArray 是包含我的立方体的数组,它们构成了整个立方体。使用 createAnim 函数,我绑定了一个新矩阵(它只是单位矩阵)。如果我不调用 createAnim,立方体不会重置为初始立方体,但我会遇到所有行都在旋转的问题,而不仅仅是我定义的 1 行。

for(int i = 0; i < arraySize; i+=1) {
            createAnim(shaderProgram,anim);

            if(move == 1) {
                if(i < 9) {
                    anim2 = spinLeft(anim2,shaderProgram,i);
                    if(nrRotations == 900) {
                        move ++;
                        nrRotations = 0;
                        // anim = anim2;
                    }
                }
            } else if (move == 2) {
                anim3 = spinRight(anim3,i);
                if (nrRotations == 900) {
                    move++;
                    nrRotations = 0;
                }
            }
          
            glBufferData(GL_ARRAY_BUFFER,6*36*4,&vtxArray[i],GL_STATIC_DRAW);  
            glDrawArrays(GL_TRIANGLES,36);
        }

为此我使用了 1 个 VBO 和 1 个 VAO。希望您理解我遇到的问题,如果需要更多代码或解释,请告诉我。

解决方法

您会想要利用矩阵乘法。网上有很多关于如何使用矩阵乘法按顺序“链接”旋转的好资源,并且是 MVP 矩阵如何从单独的模型、视图和投影矩阵链接在一起而不会丢失过程中的任何信息的直觉的一部分.

简而言之:

  • 遍历魔方中的所有块并过滤形成要旋转的面的块(检查其位置是否为特定值)
  • 使用矩阵乘法对其模型矩阵进行旋转
  • 更新块和绘制的制服

如果您遇到困难,这里有一个基于 LearnOpenGL 代码的示例,它演示了链式矩阵乘法:

#include <iostream>
#include <vector>
#include <algorithm>

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>

#include <learnopengl/camera.h>

#include <iostream>

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>


using std::vector;
using std::cout;
using std::endl;
using glm::mat4;
using glm::vec2;
using glm::vec3;
using glm::vec4;
using glm::perspective;
using glm::radians;
using glm::normalize;

void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow* window,double xpos,double ypos);
void mouse_button_callback(GLFWwindow* window,int button,int action,int mods);
void scroll_callback(GLFWwindow* window,double xoffset,double yoffset);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// grid dimensions
const unsigned int GRID_WIDTH = 600;
const unsigned int GRID_HEIGHT = 600;

float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;

// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;

mat4 view;
mat4 projection;
float fov = 90.0f;

Camera camera(glm::vec3(0.0f,0.0f,3.0f));

class Block {
public:
    unsigned int shaderProgram;
    unsigned int VBO,VAO;

    mat4 model;

    Block(vec3 pos=vec3(0,0)) {

        model = translate(mat4(1.0),pos);
        // scale it down a little bit to see the different blocks
        model = scale(model,vec3(0.99,0.99,0.99));

        float vertices[] = {
             0.5,-0.5,1,// 1
            -0.5,// 0
             0.5,0.5,// 2
            -0.5,// 0
            -0.5,// 3
             0.5,// 2

            -0.5,// 1
             0.5,// 2
             0.5,// 3
            -0.5,// 0

            -0.5,//0
             0.5,//1
             0.5,//2
             0.5,//2
            -0.5,//3
            -0.5,//0

             0.5,//1
            -0.5,//0
            -0.5,//3
             0.5,//2

        };


        glGenVertexArrays(1,&VAO);
        glGenBuffers(1,&VBO);

        glBindVertexArray(VAO);

        glBindBuffer(GL_ARRAY_BUFFER,VBO);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);

        // position attribute
        glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,6 * sizeof(float),(void*)0);
        glEnableVertexAttribArray(0);

        // color attribute
        glVertexAttribPointer(1,(void*)(3 * sizeof(float)));
        glEnableVertexAttribArray(1);

        const char *vertexShaderSource = "#version 330 core\n"
            "layout (location = 0) in vec3 aPos;\n"
            "layout (location = 1) in vec3 aCol;\n"
            "uniform mat4 model;\n"
            "uniform mat4 view;\n"
            "uniform mat4 projection;\n"
            "out vec4 outColor;\n"
            "void main()\n"
            "{\n"
            "   gl_Position = projection * view * model * vec4(aPos.x,aPos.y,aPos.z,1.0);\n"
            "   outColor = vec4(aCol,1.0f);\n"
            "}\0";
        const char *fragmentShaderSource = "#version 330 core\n"
            "out vec4 FragColor;\n"
            "in vec4 outColor;\n"
            "void main()\n"
            "{\n"
            "   FragColor = outColor;\n"
            "}\n\0";

        // vertex shader
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader,&vertexShaderSource,NULL);
        glCompileShader(vertexShader);
        // check for shader compile errors
        int success;
        char infoLog[512];
        glGetShaderiv(vertexShader,GL_COMPILE_STATUS,&success);
        if (!success)
        {
            glGetShaderInfoLog(vertexShader,512,NULL,infoLog);
            cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
        }
        // fragment shader
        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader,&fragmentShaderSource,NULL);
        glCompileShader(fragmentShader);
        // check for shader compile errors
        glGetShaderiv(fragmentShader,&success);
        if (!success)
        {
            glGetShaderInfoLog(fragmentShader,infoLog);
            cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
        }
        // link shaders
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram,vertexShader);
        glAttachShader(shaderProgram,fragmentShader);
        glLinkProgram(shaderProgram);
        // check for linking errors
        glGetProgramiv(shaderProgram,GL_LINK_STATUS,&success);
        if (!success) {
            glGetProgramInfoLog(shaderProgram,infoLog);
            cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl;
        }
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
    }

    void setMatrix(std::string name,glm::mat4 mat) {
        glUseProgram(shaderProgram);
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram,name.c_str()),&mat[0][0]);
    }

    void draw() {
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES,36);
    }


    vec3 getPosition() {
        return vec3(model[3]);
    }
};

class Cube {
public:
    vector<Block> blocks;
    Cube() {
        for (int x = -1; x <= 1; x++) {
            for (int y = -1; y <= 1; y++) {
                for (int z = -1; z <= 1; z++) {
                    blocks.push_back(Block(vec3(x,y,z)));
                }
            }
        }
    }

    void draw(mat4 view,mat4 projection) {
        for (int i = 0; i < blocks.size(); i++) {
            blocks[i].setMatrix("model",blocks[i].model);
            blocks[i].setMatrix("view",view);
            blocks[i].setMatrix("projection",projection);
            blocks[i].draw();           
        }

    }

    void rotate(std::string value,bool ccw) {
        int index;
        vec3 axis;
        if (value == "x") {
            index = 0;
            axis = vec3(1.0f,0.0f);
        }
        if (value == "y") {
            index = 1;
            axis = vec3(0.0f,1.0f,0.0f);
        }
        for (int i = 0; i < blocks.size(); i++) {
            if (fabs(blocks[i].getPosition()[index] - 1.0f) < 0.1f ) {
                // create rotation matrix
                mat4 rotationMatrix = glm::rotate(mat4(1.0f),radians(ccw ? -90.0f : 90.0f),axis);
                // multiply with current matrix
                blocks[i].model = rotationMatrix * blocks[i].model;
            }
        }
    }

};

Cube *rubiksCube;

int main()
{

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);
#endif

    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH,SCR_HEIGHT,"Rubik's Cube",NULL);
    if (window == NULL)
    {
        cout << "Failed to create GLFW window" << endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetCursorPosCallback(window,mouse_callback);
    glfwSetMouseButtonCallback(window,mouse_button_callback);
    glfwSetScrollCallback(window,scroll_callback);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        cout << "Failed to initialize GLAD" << endl;
        return -1;
    }

    projection = perspective(radians(fov),(float)SCR_WIDTH/(float)SCR_HEIGHT,0.1f,1000.0f);
    glClearColor(0.0,0.0,1.0);

    rubiksCube = new Cube();

    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glCullFace(GL_BACK);
    glFrontFace(GL_CCW);
    while (!glfwWindowShouldClose(window))
    {

        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;


        processInput(window);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        rubiksCube->draw(camera.GetViewMatrix(),projection);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();

    delete rubiksCube;

    return 0;
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window,GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window,true);     

    if (glfwGetKey(window,GLFW_KEY_W) == GLFW_PRESS)
        camera.ProcessKeyboard(FORWARD,deltaTime);
    if (glfwGetKey(window,GLFW_KEY_S) == GLFW_PRESS)
        camera.ProcessKeyboard(BACKWARD,GLFW_KEY_A) == GLFW_PRESS)
        camera.ProcessKeyboard(LEFT,GLFW_KEY_D) == GLFW_PRESS)
        camera.ProcessKeyboard(RIGHT,deltaTime);
}


// glfw: whenever the mouse moves,this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window,double ypos)
{
    if (firstMouse)
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top

    lastX = xpos;
    lastY = ypos;

    camera.ProcessMouseMovement(xoffset,yoffset);
}

// glfw: whenever the mouse scroll wheel scrolls,this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window,double yoffset)
{
    camera.ProcessMouseScroll(yoffset);
}


void mouse_button_callback(GLFWwindow* window,int mods)
{
    if (button == GLFW_MOUSE_BUTTON_1 && action == 1) {
        rubiksCube->rotate("x",true);
    }
    if (button == GLFW_MOUSE_BUTTON_3 && action == 1) {
        rubiksCube->rotate("y",true);
    }

    if (button == GLFW_MOUSE_BUTTON_2 && action == 1) {
        rubiksCube->rotate("x",false);
    }
}

输出:

rotating sides demo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res