GLM 如何处理翻译

2023-11-25

OpenGL 数学库 (GLM) 使用以下算法来计算平移矩阵:

//taken from source code
template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)
{
    mat<4, 4, T, Q> Result(m);
    Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];
    return Result;
}

(这里的向量v是一个 3 维向量,矩阵 m 是一个 4X4 矩阵,因为我们使用齐次坐标向量v也是 4 维的)。

以下来自线性代数理论:

Let m有条目:

enter image description here

现在,假设矩阵m给出一些线性变换,也是一个变换矩阵,我们想分别在 X、Y 和 Z 维度上添加 X、Y 和 Z 的平移,如果我没记错的话,我们的方式这是通过形成一个复合矩阵来实现的:

enter image description here

这给出了类似的东西:

enter image description here

现在,我不明白 Translate 的 GLM 函数的作用,因为它的作用如下:

enter image description here

添加平移变换的矩阵,即 m 变为:

enter image description here

现在,这两个矩阵不相等,因此它们会导致不同的变换,所以我很困惑哪个矩阵进行实际翻译,哪个矩阵是正确的,或者算法背后是否隐藏着任何其他想法?

注意:在阅读答案之前,请注意在矩阵的列主表示中,您可以使用以下方式访问矩阵的条目:matrix[column-index][row-index].

Edit

我用来执行转换的源代码:

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
#include <string.h>

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"


// Window Dimensions
const GLint WIDTH=800, HEIGHT=600;
GLuint VAO, VBO, shader;
GLint uniformModel {};
GLint uniformModelRot {};
GLfloat triOffset {};
float triMaxOffset = 0.7f;
bool direction = true;
const float toRadians =  3.14159265f/180.0f;


// vertex shader
static const char* vShader = 
"#version 330\n"
"layout (location = 0) in vec3 pos;\n"
"uniform mat4 model;\n"
"void main(){\n"
"   gl_Position = model * vec4(0.5*pos, 1.0);\n"
"}\n";

// fragment shader
static const char* fShader = ""
"#version 330\n"
"out vec4 color;\n"
"uniform mat4 model;\n"
"void main(){\n"
"   color = model *vec4(1.0, 1.0, 0.0, 1.0);\n"
"}\n";

void AddShader(GLuint theProgram, const char* ShaderCode, GLenum shaderType, std::string info){
    std::cerr <<"INFO: Adding "<<info<<" Shader"<<std::endl;
    GLuint theShader = glCreateShader(shaderType);

    const GLchar* theCode[1];
    theCode[0] = ShaderCode;

    GLint codeLength[1];
    codeLength[0] = strlen(ShaderCode);

    glShaderSource(theShader, 1, theCode, codeLength);
    glCompileShader(theShader);

    GLint result =0;
    GLchar eLog[1024] ={0};

    glGetShaderiv(theShader, GL_COMPILE_STATUS, &result);
    if(!result){
        glGetShaderInfoLog(shader, sizeof(eLog), NULL, eLog);
        std::cerr<<"Error compiling program"<<std::endl;
        return;
    }
    glAttachShader(theProgram, theShader);

}

void CompileShader(){
    shader = glCreateProgram();
    if(!shader){
        std::cerr<<"Error creating shader"<<std::endl;
        return;
    }

    AddShader(shader, vShader, GL_VERTEX_SHADER, "vertex");
    AddShader(shader, fShader, GL_FRAGMENT_SHADER, "fragment");

    GLint result =0;
    GLchar eLog[1024] ={0};

    glLinkProgram(shader);
    glGetProgramiv(shader, GL_LINK_STATUS, &result);
    if(!result){
        glGetProgramInfoLog(shader, sizeof(eLog), NULL, eLog);
        std::cerr<<"Error linking program"<<std::endl;
        return;
    }

    glValidateProgram(shader);
    glGetProgramiv(shader, GL_VALIDATE_STATUS, &result);
    if(!result){
        glGetProgramInfoLog(shader, sizeof(eLog), NULL, eLog);
        std::cerr<<"Error Validating program"<<std::endl;
        return;
    }

    uniformModel = glGetUniformLocation(shader,"model");

}

void CreateTriangles(){
    GLfloat vertices[]={
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    };

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

        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*9,vertices, GL_STATIC_DRAW);
        glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
        glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}


int main(){
    //initialize GLFW
    if(!glfwInit()){
        std::cerr << "GLFW initialization failed!" << std::endl;
        glfwTerminate();
        return 1;
    }

    //Setup GLFW window properties
    //openGL version
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    // core profile = no backward compatibility
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //allow forward compatibility
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    GLFWwindow *mainWindow = glfwCreateWindow(WIDTH, HEIGHT, "TEST WINDOW", NULL, NULL);

    if(!mainWindow){
        std::cerr << "GLFW Window creation failed" << std::endl;
        glfwTerminate();
        return 1;
    }

    // get Buffer size information
    int bufferWidth, bufferHeight;
    glfwGetFramebufferSize(mainWindow, &bufferWidth, &bufferHeight);
    // set context for GLEW to use
    glfwMakeContextCurrent(mainWindow);

    // allow modern extension features

    if(glewInit()!=GLEW_OK){
        std::cerr << "GLEW initialization failed" << std::endl;
        glfwDestroyWindow(mainWindow);
        glfwTerminate();
        return 1;
    }

    // setup viewport size
    glViewport(0, 0, bufferWidth, bufferHeight);
    CreateTriangles();
    CompileShader();




    while(!glfwWindowShouldClose(mainWindow)){
        // get and handle user input events
        glfwPollEvents();

        glClearColor(1.0f, 0.0f, 0.0f, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);

        if(direction){
            triOffset += 0.05f;
        }else{
            triOffset -= 0.05f;
        }

        if(abs(triOffset) >= triMaxOffset){
            direction = !direction;
        }

        glUseProgram(shader);

        glm::mat4 modelMatrix(1.0f); 
        modelMatrix = glm::translate(modelMatrix, glm::vec3(triOffset, 0.0f, 0.0f));

        glUniformMatrix4fv(uniformModel, 1, GL_FALSE,glm::value_ptr(modelMatrix));
            glBindVertexArray(VAO);
                glDrawArrays(GL_TRIANGLES,0,3);
            glBindVertexArray(0);
        glUseProgram(0);
        // swap buffers
        glfwSwapBuffers(mainWindow);
    }

    return 0;
}

OpenGL 数学 (GLM)是基于OpenGL 着色语言 (GLSL). What glm::translate实际上就是建立一个平移矩阵并将输入矩阵乘以平移。它计算m*t的意思是GLSL 向量和矩阵运算:

mat<4, 4, T, Q> Result(m);
Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];

(在下面的Result被替换为R)

Note, m[0] * v[0]将该列的每个分量相乘m[0]由标量v[0]。结果是向量(m[0][0]*v[0], m[0][1]*v[0], m[0][2]*v[0], m[0][3]*v[0]).

So R[3] = m[0]*v[0] + m[1]*v[1] + m[2]*v[2] + m[3]是相同的

R[3][0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0]
R[3][1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1]
R[3][2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2]
R[3][3] = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3]

glm::translate实际上计算:

vh = (v[0], v[1], v[2], 1)
R = m
R[3][0] = dot( (m[0][0], m[1][0], m[2][0], m[3][0]), vh )
R[3][1] = dot( (m[0][1], m[1][1], m[2][1], m[3][1]), vh )
R[3][2] = dot( (m[0][2], m[1][2], m[2][2], m[3][2]), vh )
R[3][3] = dot( (m[0][3], m[1][3], m[2][3], m[3][3]), vh )

上面的代码计算点积的行数来自m, by vh. vh是翻译的第四列t。注意平移矩阵t定义为:

     c0  c1  c2  c3 
---------------------  
r0:   1   0   0  v[0]  
r1:   0   1   0  v[1]
r2:   0   0   0  v[2]
r3:   0   0   0  1  

4x4 矩阵的串联 (R = m*t) 是个点积的行数m和列t并可表示为: (看OpenGL 着色语言 4.60 规范 - 5.10。向量和矩阵运算)

for i from 0 to 3
    for j fro 0 to 3
        R[i][j] = dot( (m[0][j], m[1][j], m[2][j], m[3][j]), t[i] )

Where dot(a, b) == a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3],
(m[0][j], m[1][j], m[2][j], m[3][j]) is the j第-行m and
t[i] is i第 列t.

For glm::translate复制就足够了R[0], R[1] and R[2] from m[0], m[1] and m[2].

例如为了 (i=0, j=0):

R[0][0] = dot( (m[0][0], m[1][0], m[2][0], m[3][0]), t[0] )
R[0][0] = dot( (m[0][0], m[1][0], m[2][0], m[3][0]), (1, 0, 0, 0) )
R[0][0] = m[0][0] * 1 + m[1][0] * 0 + m[2][0] * 0 + m[3][0]) * 0
R[0][0] = m[0][0]

GLM矩阵(如 OpenGL 矩阵)按列主序存储。如果您在调试器中研究矩阵,可能会导致混乱。

如果你有矩阵

     c0  c1  c2  c3 
-------------------  
r0:  Xx  Yx  Zx  Tx  
r1:  Xy  Yy  Zy  Ty 
r2:  Xz  Yz  Zz  Tz  
r3:   0   0   0   1  

那么 4*4 OpenGL 矩阵的内存图像如下所示:

Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1

如果您在调试器中调查它,它可能看起来像:

[ [ Xx, Xy, Xz, 0 ],
  [ Yx, Yy, Yz, 0 ],
  [ Zx, Zy, Zz, 0 ],
  [ Tx, Ty, Tz, 1 ] ]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GLM 如何处理翻译 的相关文章

随机推荐

  • 从独立存储中延迟加载列表框图像

    我有很多图像存储在独立存储中 并希望将它们显示在列表框中 但是 我不希望立即加载所有图像 而是延迟加载 因此 只有当用户滚动查看新项目时 才应加载图像 我还想使用数据绑定来提供列表项的数据和图像 在测试中 我所做的所有图像总是立即立即加载
  • 具有多种内容类型的 ContentChildren

    您好 我目前正在构建一个允许其中包含多种列类型的表 我希望能够像这样使用它
  • 架构arm64的重复符号(Xcode错误)

    我从项目中删除了对 GoogleMobileAdsSDKiOS 7 1 的所有引用 并添加了 7 4 1 当我在模拟器上运行应用程序时 一切正常 但在设备上运行时 我收到 App Mach O 链接器错误 duplicate symbol
  • 从 mysql 字段内的 json 中提取数据

    我有一个包含行的表 其中一行有一个包含如下数据的字段 name Richard lastname null city Olavarria cityId null 我想选择我拥有的所有不同的 城市 值 仅使用mysql服务器 是否可以 我正在
  • 当被属性遮蔽时修改类 __dict__

    我正在尝试修改类中的值 dict 直接使用类似的东西X dict x 1 不可能进行这样的修改 因为一个类 dict 实际上是一个mappingproxy不允许直接修改值的对象 尝试直接修改或等效的原因是我试图将类属性隐藏在元类上定义的同名
  • Facebook 页面自动“赞”URL(用于 QR 码)

    我想知道是否可以构建一个 URL 来自动喜欢 Facebook 页面 然后 这个 URL 可以转换为 QR 码 这样人们就可以通过使用智能手机阅读您的页面来自动 喜欢 您的页面 我已经搜索了很多 但到目前为止我所能找到的只是商业服务 例如S
  • AppCompatActivity.onCreate 只能从同一库组内调用

    升级到appcompat后25 1 0我开始遇到奇怪的错误 在我的代码中 Override protected void onCreate Bundle savedInstanceState super onCreate savedInst
  • SSIS 存储过程调用

    我正在尝试调用一个简单的存储过程 它将返回正常测试格式的名称列表 全部在一行中 我向它传递了两个参数 但无论我如何设置调用 无论是在 OLE DB 源编辑器中 还是在执行 SQL 任务中 我的 SQL 语句中一定缺少一些东西 因为我不断收到
  • HTML5 Canvas 在绘图时闪烁

    我从一个等距游戏开始 当绘制地面的所有部分时 我的画布正在闪烁 不在 IE 中 当我将 fps 设置为 20 或更低时 闪烁停止 我该如何解决这个问题 有任何想法吗 var camerax 300 cameray 100 var fps 6
  • 如何解决 Xcode 上 Storyboard 的警告? [复制]

    这个问题在这里已经有答案了 Trailing Leading constraint is missing which may cause overlapping with other views 我的故事板 只需放置 2 个标签及其约束 避
  • ui:repeat 不适用于 f:selectItem

    我正在使用 Icefaces 选择菜单从用户列表中选择用户 我想为每个用户重复 selectItem 这是我尝试过的
  • 您的实用工具包中有什么? [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我认识的一些最高效的工程师 开发人员和 IT 专业人员通常都会携带一个由有用程序 插件或实用程序组成的通用 工具包 以帮助他们进行日常调试 开发或设计 问题是 您的实用工具包中有什么
  • 如何在 Visual Studio 2008 中添加 ASP.NET 的页面事件

    这是一个 Visual Studio 问题 我觉得所有有用的智能感知应该有一些帮助 但我似乎找不到它 我在 VS2008 中用 ASP NET C 制作了一个带有代码隐藏的页面 当然它会自动生成 PageLoad 事件方法 那么 如果我想为
  • rjava .jcall 问题

    我目前正在开发一个 R 包以将 java 代码集成到 R 中 但是 我在尝试正确调用 java 类方法时遇到问题 到目前为止我已经独立开发了一个java程序并编译成class文件 然后打包为jar文件 我的代码示例如下 library rJ
  • 在Android中设置每天在特定时间重复闹钟

    我正在使用闹钟管理器在每天的特定时间运行闹钟 下面是代码 Calendar calendar Calendar getInstance calendar setTimeInMillis System currentTimeMillis ca
  • 使用 epoll 进行非阻塞 tcp 连接

    我的 Linux 应用程序正在执行非阻塞 TCP 连接系统调用 然后使用epoll wait检测三向握手完成 有时epoll wait两者都返回POLLOUT POLLERR为同一套接字描述符设置的事件 我想了解 TCP 级别发生了什么 我
  • uisearchDisplayController:更改标签“无结果”

    使用 uisearchDisplayController 时如何更改标签 无结果 Regards 我已经成功删除了标签 因为从来没有空结果集 如果因为从服务器获取而没有结果 请将数据源重置为单行 并让它显示空白的表视图单元格 此外 使用逻辑
  • 为什么我在尝试检查偶数/奇数时会收到“类型错误:字符串格式化期间未转换所有参数”?

    这段代码给出了一个错误 print type a whole number n input if n 2 1 print Odd else print Even 我假设我必须对 if 语句中的变量 n 做一些特殊的事情 我是 Python
  • simple_form的collection_radio_button和自定义标签类

    我正在尝试使用 FontAwesome 制作带有无线电集合的星级评级表格 为此我实际上需要更改 simple form 生成的 collection radio button 输入的标签类 但找不到任何明显的解决方案 到目前为止我使用 fo
  • GLM 如何处理翻译

    OpenGL 数学库 GLM 使用以下算法来计算平移矩阵 taken from source code template