OpenGL旋转和翻译正确完成

时间:2012-12-29 17:19:19

标签: opengl vertex-shader

在OpenGL中进行旋转和翻译时,我有点卡住了。

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

My VertexShader:

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();
}

这很有效,但感觉不对。最好的方法是什么?

1 个答案:

答案 0 :(得分:16)

这个

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包含完整的compount模型方向以及翻译和视图矩阵。我们现在需要做的就是绑定用于对象的着色器程序

         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);
    }

/* ... */

}