【问题标题】:OpenGL rotation and translation done correctly正确完成 OpenGL 旋转和平移
【发布时间】:2012-12-14 13:52:50
【问题描述】:

在 OpenGL 中旋转和平移我有点卡住了。

我有 3 个矩阵、投影、视图和模型。

我的顶点着色器:

gl_Position =  projection * model * view * vec4(vertexData, 1);

平移和旋转对象的最佳方式是什么?

将我的模型矩阵乘以平移或旋转矩阵, 还是将数据(旋转和平移)传递给着色器和那里的数学?

我还需要知道我的鼠标选择实现的“最终对象位置”。

到目前为止我所做的是这样的:

object.Transformation = Matrix.CreateTransLation(x,y,z) * Matrix.CreateRotation(x,y,z);

...

ForEach object to Draw
{
    modelMatrix.Push();

    modelMatrix.Mult(object.Transformation); // this also updates the matrix for the shader

    object.Draw();

    modelMatrix.Pop();
}

这行得通,但感觉不对。最好的方法是什么?

【问题讨论】:

    标签: opengl vertex-shader


    【解决方案1】:

    这个

    gl_Position =  projection * model * view * vec4(vertexData, 1);
    

    错了。矩阵乘法不可交换,即运算顺序很重要。顶点位置的变换,按顺序是:

    • 型号
    • 查看
    • 投影

    OpenGL 使用的列向量的矩阵乘法是左关联的,即从右到左。因此,语句 R 侧的表达式应该是

    gl_Position =  projection * view * model * vec4(vertexPosition, 1);
    

    但是,您可以将视图和模型转换收缩为复合模型视图(第一个模型,然后是视图)转换。这节省了一个完整的矩阵乘法

    gl_Position =  projection * modelview * vec4(vertexPosition, 1);
    

    投影应保持独立,因为其他着色步骤可能需要顶点的眼睛空间位置,这是modelview * position 未应用投影的结果。

    顺便说一句:您正在转换顶点位置,而不是数据。顶点包含大量属性(不仅仅是位置),因此称其为“数据”在语义上是错误的。

    平移和旋转对象的最佳方式是什么?

    这些是模型视图转换的一部分。您应该在 CPU 上精确一次 创建一个转换矩阵,并将其传递给 GPU。在着色器中执行此操作将强制 GPU 为每个顶点重做整个计算。你不想这样做。

    因评论而更新

    假设您正在使用我的→linmath.h。然后在你的绘图函数中,你会为你的场景设置脚手架,即设置视口、构建的投影和视图矩阵

    #include <linmath.h>
    
    /* ... */
    
    void display(void)
    {
         mat4x4 projection;
         mat4x4 view;
    
         glClear(…),
         glViewport(…);
    
         mat4x4_frustum(projection, …);
    
         // linmath.h doesn't have a look_at function... yet
         // I'll add it soon
         mat4x4_look_at(view, …);
    

    然后,对于每个对象,您都有一个位置和方向(平移和旋转)。方向最方便地存储在四元数中,但对于处理向量,矩阵表示效果更好。所以我们遍历场景中的对象

         for(int i_object = 0; i_object < scene->n_objects; i++) {
             Object * const obj = scene->objects + i;
    
             mat4x4 translation, orientation, model_view;
    
             mat4x4_translate(translation, obj->pos.x, obj->pos.y, obj->pos.z);
             mat4x4_from_quat(orientation, obj->orientation);
             mat4x4_mul(model_view, translation, orientation);
    

    model_view 现在包含模型矩阵。接下来我们将view 矩阵相乘。请记住,矩阵乘法是从右到左的(mat4x4_mul 可以输出到其输入操作数之一)。

             mat4x4_mul(model_view, view, model_view);
    

    现在model_view 包含完整的复合模型方向和平移和视图矩阵。我们现在需要做的就是绑定用于对象的着色器程序

             glUseProgram(obj->shader->program);
    

    设置制服

             glUniformMatrix4f(obj->shader->location.projection, 1, GL_FALSE, projection);
             glUniformMatrix4f(obj->shader->location.modelview,  1, GL_FALSE, model_view);
             // and a few others...
    

    并绘制对象

            object_draw(obj);
        }
    
    /* ... */
    
    }
    

    【讨论】:

    • 感谢您的意见。我现在将相应地更改内容,看看结果如何。虽然我不明白你写的最后一部分,但我应该如何为对象创建平移和旋转?你能提供伪代码吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    相关资源
    最近更新 更多