如何在 OpenGL 中对半透明三角形进行排序?
How to sort translucent triangles in OpenGL?
我正在使用 OpenGL 编写 3D 游戏。渲染半透明三角形时出现排序问题。我知道它们需要分类,但如何分类?我不想使用 BSP 树(如果我想更改对象的位置,那么我需要重建树。)和 OIT 算法(性能昂贵)。我想按 "coverage".
对它们进行排序
我有两个半透明三角形,我使用透视相机将它们投射到屏幕上。
视口:0、0、1280、720
例如
[正确排序]黑色三角形覆盖绿色三角形。
[排序不正确]绿色三角形覆盖了黑色三角形。
图像中的三角形是不透明的,以便清楚地看到排序伪影。
我对这个问题的解决方法
将这些三角形的顶点转换为屏幕 space 坐标并通过插值 z 坐标进行比较,但是在我的图像上你可以看到黑色三角形的一个坐标在视口之外,因此这个坐标很奇怪(像这样:-2896;1423;1.169)我无法在黑色三角形上插入 z 坐标。
如何变换到屏幕space坐标
- 通过 MVP 矩阵变换三角形顶点
- 执行透视分割
- 转换为屏幕space
通过 MVP 矩阵转换
public Vector4f transform(Vector4f vector) {
float x = m00 * vector.x + m10 * vector.y + m20 * vector.z + m30 * vector.w;
float y = m01 * vector.x + m11 * vector.y + m21 * vector.z + m31 * vector.w;
float z = m02 * vector.x + m12 * vector.y + m22 * vector.z + m32 * vector.w;
float w = m03 * vector.x + m13 * vector.y + m23 * vector.z + m33 * vector.w;
return new Vector4f(x, y, z, w);
}
透视鸿沟
public Vector3f perspectiveDivide() {
float wInverse = 1.0f / w;
return new Vector3f(x * wInverse, y * wInverse, z * wInverse);
}
转换为屏幕space
public void toScreenCoords(int width, int height) {
x = (x * 0.5f + 0.5f) * width;
y = (y * 0.5f + 0.5f) * height;
z = (z + 1.0f) * 0.5f;
}
我是如何做到的
Vector4f clipspace = mvp.transform(triangle_vertex);
Vector3f ndc = clipspace.perspectiveDivide();
Vector3f screenspace = ndc.toScreenCoords(1280, 720);
我做错了什么?为什么坐标在视口外很奇怪?如何获取视口外的正确坐标?
--- 编辑 ---
我发现,如果三角形的一个坐标在视口之外,那么三角形必须一分为二。
但是如何使用裁剪space坐标和裁剪平面将三角形一分为二呢?
正确排序(半透明)三角形的快速简便的解决方案
"Fake projection sorting" 正如我所说。
如果你可以假设三角形不会相交,那么你可以检查三角形(黑色或绿色)是否与四面体相交(绿色三角形的黑色坐标和相机位置)。
一个例子
第一个三角坐标:
0.0, 0.0, 5.0
0.0, 5.0, 5.0
5.0, 5.0, 5.0
第二个三角坐标:
0.0, 0.0, 5.0
5.0, 0.0, 5.0
5.0, 0.0, 5.0
相机位置
1.15, 5.8, 5.5
然后,四面体坐标将是三角形(例如,第一个)和相机位置的坐标。
0.0, 0.0, 5.0 // First coordinate from the first triangle
0.0, 5.0, 5.0 // Second coordinate from the first triangle
5.0, 5.0, 5.0 // Third coordinate from the first triangle
1.15, 5.8, 5.5 // Camera position
您需要做的最后一件事是检查第二个三角形是否与四面体相交。如果 second 三角形相交,则它覆盖第一个三角形。如果您使用第二个三角形的坐标来创建四面体,那么您需要检查第一个三角形的交点而不是第二个。
备注
不要使用 Java 中的 TreeSet 或 TreeMap 来比较使用 "Fake projection sorting" 的三角形,它会产生不正确的排序。
我正在使用 OpenGL 编写 3D 游戏。渲染半透明三角形时出现排序问题。我知道它们需要分类,但如何分类?我不想使用 BSP 树(如果我想更改对象的位置,那么我需要重建树。)和 OIT 算法(性能昂贵)。我想按 "coverage".
对它们进行排序我有两个半透明三角形,我使用透视相机将它们投射到屏幕上。
视口:0、0、1280、720
例如
[正确排序]黑色三角形覆盖绿色三角形。
[排序不正确]绿色三角形覆盖了黑色三角形。
图像中的三角形是不透明的,以便清楚地看到排序伪影。
我对这个问题的解决方法
将这些三角形的顶点转换为屏幕 space 坐标并通过插值 z 坐标进行比较,但是在我的图像上你可以看到黑色三角形的一个坐标在视口之外,因此这个坐标很奇怪(像这样:-2896;1423;1.169)我无法在黑色三角形上插入 z 坐标。
如何变换到屏幕space坐标
- 通过 MVP 矩阵变换三角形顶点
- 执行透视分割
- 转换为屏幕space
通过 MVP 矩阵转换
public Vector4f transform(Vector4f vector) {
float x = m00 * vector.x + m10 * vector.y + m20 * vector.z + m30 * vector.w;
float y = m01 * vector.x + m11 * vector.y + m21 * vector.z + m31 * vector.w;
float z = m02 * vector.x + m12 * vector.y + m22 * vector.z + m32 * vector.w;
float w = m03 * vector.x + m13 * vector.y + m23 * vector.z + m33 * vector.w;
return new Vector4f(x, y, z, w);
}
透视鸿沟
public Vector3f perspectiveDivide() {
float wInverse = 1.0f / w;
return new Vector3f(x * wInverse, y * wInverse, z * wInverse);
}
转换为屏幕space
public void toScreenCoords(int width, int height) {
x = (x * 0.5f + 0.5f) * width;
y = (y * 0.5f + 0.5f) * height;
z = (z + 1.0f) * 0.5f;
}
我是如何做到的
Vector4f clipspace = mvp.transform(triangle_vertex);
Vector3f ndc = clipspace.perspectiveDivide();
Vector3f screenspace = ndc.toScreenCoords(1280, 720);
我做错了什么?为什么坐标在视口外很奇怪?如何获取视口外的正确坐标?
--- 编辑 ---
我发现,如果三角形的一个坐标在视口之外,那么三角形必须一分为二。
但是如何使用裁剪space坐标和裁剪平面将三角形一分为二呢?
正确排序(半透明)三角形的快速简便的解决方案
"Fake projection sorting" 正如我所说。 如果你可以假设三角形不会相交,那么你可以检查三角形(黑色或绿色)是否与四面体相交(绿色三角形的黑色坐标和相机位置)。
一个例子
第一个三角坐标:
0.0, 0.0, 5.0
0.0, 5.0, 5.0
5.0, 5.0, 5.0
第二个三角坐标:
0.0, 0.0, 5.0
5.0, 0.0, 5.0
5.0, 0.0, 5.0
相机位置
1.15, 5.8, 5.5
然后,四面体坐标将是三角形(例如,第一个)和相机位置的坐标。
0.0, 0.0, 5.0 // First coordinate from the first triangle
0.0, 5.0, 5.0 // Second coordinate from the first triangle
5.0, 5.0, 5.0 // Third coordinate from the first triangle
1.15, 5.8, 5.5 // Camera position
您需要做的最后一件事是检查第二个三角形是否与四面体相交。如果 second 三角形相交,则它覆盖第一个三角形。如果您使用第二个三角形的坐标来创建四面体,那么您需要检查第一个三角形的交点而不是第二个。
备注
不要使用 Java 中的 TreeSet 或 TreeMap 来比较使用 "Fake projection sorting" 的三角形,它会产生不正确的排序。