保存当前观察点的OpenGL网格



我有一个OpenGL可视化器(使用OpenTK)。它应该以PLY格式打开一个网格文件,并显示它。用户可以围绕对象移动、旋转或缩放它。最后,用户应该能够将网格保存到PLY文件中,从他/她在保存之前看到的完全相同的视图。

我已经将网格对象抽象成一个类。下面是类(sort of)的样子:

public class Mesh {
    Vector3d vertices[];
    int[] triangleIndices;
    Matrix4d translation = Matrix4d.Identity();
    Matrix4d rotation = Matrix4d.Identity();
    Matrix4d scale = Matrix4d.Identity();
    int vboHandle;
    int faceHandle;
    public void Draw() {
        GL.PushMatrix();
        /**
         * Apply transformations
         */
         // Do VBO drawing stuff
         // ...
         GL.PopMatrix();
    }
}

我正在做的是将PLY文件加载为VBO。当要绘制网格时,我首先应用平移,应用旋转(通过找到对象的质心,平移坐标系统,旋转并向后平移),然后(以与旋转相同的方式)应用缩放。

这工作得很好,可视化器正确绘制网格。但是,当我想保存时,我不知道如何对所有顶点应用相同的转换集并编写PLY文件。
我试着这样做:(非常模仿我上面的Draw方法):

for(int i = 0 ; i <this.vertices.Length; i++) 
{
    // Apply the transformations
    Vector3d transformed = Vector3d.Transform(this.vertices[i], this.translation);
    // Handle rotation
    Matrix4d centerTrans = Matrix4d.CreateTranslation(Center);
    transformed = Vector3d.Transform(transformed, centerTrans);
    transformed = Vector3d.Transform(transformed, this.rotation);
    centerTrans = Matrix4d.CreateTranslation(-Center);
    transformed = Vector3d.Transform(transformed, centerTrans);
    // Handle scale
    centerTrans = Matrix4d.CreateTranslation(Center);
    transformed = Vector3d.Transform(transformed, centerTrans);
    transformed = Vector3d.Transform(transformed, this.scale);
    centerTrans = Matrix4d.CreateTranslation(-Center);
    transformed = Vector3d.Transform(transformed, centerTrans);
    result[i] = transformed;
}

但问题是输出有点偏离(特别是当对象被旋转时)。

我的主要问题是如何解决这个问题,以及解决这个问题的正确方法是什么。

p。我知道我的方法可能是过时的,幼稚的,错误的(考虑到OpenGL的最佳实践),但我正在创建这个可视化工具来解决一个完全不相关的更大的问题。所以在某种程度上,我是在为自己的目的而黑东西。对于解决这个问题的好方法,任何建议都是非常感谢的。

PS2。多次Matrix4d变换的原因是我总是希望旋转应用到对象的中心,我不知道有任何其他方法可以达到相同的效果。

需要注意的一点是转换的顺序。当你使用旧的OpenGL矩阵堆栈指定转换时,它们以反向顺序应用于顶点。

例如,如果你有这样的序列:

glTranslatef(...);
glRotatef(...);

这意味着首先旋转顶点,然后平移。

虽然这种行为乍一看似乎违反直觉,但实际上比相反的方式要有用得多。例如,如果使用视图矩阵,则在帧的开始处指定它。然后在绘制对象时指定模型转换。但是视图转换需要在模型转换之后应用,即使它是首先指定的。

类似地,如果你有一个对象的层次结构,你经常想要指定适用于所有对象的"全局"转换,然后当你在层次结构中绘制对象时指定"局部"转换。但是,局部转换需要在全局转换之前应用。

基于此,如果你在自己的代码中一个接一个地应用转换,你将不得不以与你为OpenGL渲染指定它们时使用的顺序相反的顺序应用它们。

选择

有几种可能的替代方法:

  • 你可以得到当前的变换矩阵,然后把它应用到你的顶点:

    GLfloat mat[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, mat);
    

    只有在渲染帧时使用才有效。如果您希望在呈现之外应用转换,那么您的方法更可行。此外,它让你更深入地使用遗留矩阵堆栈,这意味着你有更多的工作,如果你曾经想携带你的代码到OpenGL核心配置文件,或将其移植到OpenGL ES。

  • 正如@Ike在上面的评论中建议的那样,您可以更改代码以首先组合矩阵,然后将组合矩阵应用于您的顶点。如果你有很多使用相同转换序列的顶点,这将更有效。

  • OpenGL有一个叫做"转换反馈"的功能,它允许你从图形管道中得到转换后的坐标。我不认为它最适合你的用例,但无论如何你可能想要阅读它。

相关内容

  • 没有找到相关文章

最新更新