从当前视点保存 OpenGL 网格
Save an OpenGL mesh from the current viewing point
我有一个 OpenGL 可视化工具(使用 OpenTK)。它应该打开一个 PLY 格式的网格文件,并显示它。用户能够围绕对象移动、旋转或缩放它。最后,用户应该能够从 he/she 保存前看到的完全相同的视图将网格保存到 PLY 文件中。
我已经将网格对象抽象为 class。这是 class(有点)的样子:
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;
}
但问题是输出有点偏差(尤其是在对对象应用旋转时)。
我的主要问题是如何解决这个问题以及解决这个问题的正确方法是什么。
PS。我知道我的方法可能是过时的、幼稚的,并且对于整个网格渲染的事情是错误的(并考虑 OpenGL 最佳实践),但我创建这个可视化工具是为了解决一个完全不相关且更大的问题。所以在某种程度上,我是为了我的目的而进行黑客攻击。非常感谢任何有关解决此问题的好方法的建议。
PS2。多次 Matrix4d
变换的原因是我总是希望将旋转应用于对象的中心,而我不知道有任何其他方法可以达到相同的效果。
需要注意的一个方面是转换的顺序。当您使用旧版 OpenGL 矩阵堆栈指定变换时,它们将以 与指定它们的顺序相反的顺序 应用于顶点。
例如,如果你有这个序列:
glTranslatef(...);
glRotatef(...);
这意味着首先旋转顶点,然后平移。
虽然这种行为乍一看似乎违反直觉,但它实际上比相反的方式更有用。例如,如果您使用视图矩阵,您可以在帧的开头指定它。然后在绘制对象时指定模型转换。但是视图转换需要在模型转换之后应用,即使它是首先指定的。
同样,如果您有对象的层次结构,您通常希望指定适用于所有对象的 "global" 转换,然后在层次结构中更深层次绘制对象时指定 "local" 转换.但同样,局部变换需要在全局变换之前应用。
基于此,如果您在自己的代码中逐一应用变换,则必须按照与为 OpenGL 渲染指定它们时使用的顺序相反的顺序应用它们。
备选方案
有几个可能的替代方案可以替代您当前使用的方案:
你可以获得当前的变换矩阵,然后将它应用到你的顶点:
GLfloat mat[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mat);
只有在渲染帧时使用它才会很好地工作。如果您想在渲染之外应用转换,您的方法更可行。此外,它还可以让您更深入地使用遗留矩阵堆栈,这意味着如果您想将代码导入 OpenGL Core Profile 或将其移植到 OpenGL ES,您需要做更多的工作。
正如@Ike 在上面评论中所建议的那样,您可以更改代码以首先组合矩阵,然后将组合矩阵应用于顶点。如果您有很多顶点使用相同的变换序列,这会更有效。
OpenGL 有一项名为 "transform feedback" 的功能,可让您从图形管道中获取转换后的坐标。我不认为它非常适合您的用例,但您可能还是想阅读它。
我有一个 OpenGL 可视化工具(使用 OpenTK)。它应该打开一个 PLY 格式的网格文件,并显示它。用户能够围绕对象移动、旋转或缩放它。最后,用户应该能够从 he/she 保存前看到的完全相同的视图将网格保存到 PLY 文件中。
我已经将网格对象抽象为 class。这是 class(有点)的样子:
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;
}
但问题是输出有点偏差(尤其是在对对象应用旋转时)。
我的主要问题是如何解决这个问题以及解决这个问题的正确方法是什么。
PS。我知道我的方法可能是过时的、幼稚的,并且对于整个网格渲染的事情是错误的(并考虑 OpenGL 最佳实践),但我创建这个可视化工具是为了解决一个完全不相关且更大的问题。所以在某种程度上,我是为了我的目的而进行黑客攻击。非常感谢任何有关解决此问题的好方法的建议。
PS2。多次 Matrix4d
变换的原因是我总是希望将旋转应用于对象的中心,而我不知道有任何其他方法可以达到相同的效果。
需要注意的一个方面是转换的顺序。当您使用旧版 OpenGL 矩阵堆栈指定变换时,它们将以 与指定它们的顺序相反的顺序 应用于顶点。
例如,如果你有这个序列:
glTranslatef(...);
glRotatef(...);
这意味着首先旋转顶点,然后平移。
虽然这种行为乍一看似乎违反直觉,但它实际上比相反的方式更有用。例如,如果您使用视图矩阵,您可以在帧的开头指定它。然后在绘制对象时指定模型转换。但是视图转换需要在模型转换之后应用,即使它是首先指定的。
同样,如果您有对象的层次结构,您通常希望指定适用于所有对象的 "global" 转换,然后在层次结构中更深层次绘制对象时指定 "local" 转换.但同样,局部变换需要在全局变换之前应用。
基于此,如果您在自己的代码中逐一应用变换,则必须按照与为 OpenGL 渲染指定它们时使用的顺序相反的顺序应用它们。
备选方案
有几个可能的替代方案可以替代您当前使用的方案:
你可以获得当前的变换矩阵,然后将它应用到你的顶点:
GLfloat mat[16]; glGetFloatv(GL_MODELVIEW_MATRIX, mat);
只有在渲染帧时使用它才会很好地工作。如果您想在渲染之外应用转换,您的方法更可行。此外,它还可以让您更深入地使用遗留矩阵堆栈,这意味着如果您想将代码导入 OpenGL Core Profile 或将其移植到 OpenGL ES,您需要做更多的工作。
正如@Ike 在上面评论中所建议的那样,您可以更改代码以首先组合矩阵,然后将组合矩阵应用于顶点。如果您有很多顶点使用相同的变换序列,这会更有效。
OpenGL 有一项名为 "transform feedback" 的功能,可让您从图形管道中获取转换后的坐标。我不认为它非常适合您的用例,但您可能还是想阅读它。