【发布时间】:2018-12-23 05:59:57
【问题描述】:
我正在使用 OpenGL 编写一个 3D 游戏。渲染半透明三角形时遇到排序问题。我知道它们需要分类,但是如何分类呢?我不想使用 BSP 树(如果我想改变对象的位置,那么我需要重建树。)和 OIT 算法(性能昂贵)。我想按“覆盖率”对它们进行排序。
我有两个半透明的三角形,我使用透视相机将它们投影到屏幕上。
视口:0、0、1280、720
例如
[正确排序]黑色三角形覆盖绿色三角形。
[INCORRECT SORTING] 一个绿色三角形覆盖了黑色三角形。
图像中的三角形是不透明的,以便清楚地看到排序伪影。
我对这个问题的解决方案
将这些三角形的顶点转换为屏幕空间坐标并通过插值 z 坐标来比较它们,但是在我的图像上你可以看到黑色三角形的一个坐标在视口之外,因此这个坐标很奇怪(像这样:- 2896; 1423; 1.169),我无法在黑色三角形上插入 z 坐标。
我如何转换到屏幕空间坐标
- 通过 MVP 矩阵变换三角形顶点
- 执行透视分割
- 转换到屏幕空间
通过 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);
}
转换到屏幕空间
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);
我做错了什么?为什么在视口外部进行协调很奇怪?如何获得视口外的正确坐标?
--- 编辑 ---
我发现如果三角形的一个坐标在视口之外,那么三角形必须一分为二。
但是如何使用裁剪空间坐标和裁剪平面将三角形一分为二呢?
【问题讨论】:
-
奇怪的坐标可能是由位于相机后面的顶点引起的。但是,您的主要问题是三角形并不总是可以排序(想象三个交错三角形;在这种情况下,您需要拆分其中一个)。 kd 树或 BSP 树等数据结构允许您在必要时进行这些拆分。为什么不想使用它们?
-
有几种标准的裁剪算法。但我真的不明白你的方法,尤其是“将这些三角形的顶点转换为屏幕空间坐标并通过插值 z 坐标进行比较”。意思是?你为什么点插入 z 值?
-
@derhass 为了获得 z 插值的点(x,y),我正在寻找两条线之间的交点,一条来自第一个三角形,第二条来自绿色。然后我从第一个三角形和第二个三角形中插入 z。
-
@NicoSchertler 我不想使用 BSP treen,因为如果我想改变对象的位置,那么我需要重建这棵树。
-
“我正在寻找两条线之间的交点,一条来自第一个三角形,第二条来自绿色。然后我从第一个三角形和第二个三角形插入 z。”这个算法没有丝毫意义。您似乎想对这些线使用 2D 投影,只需在两个三角形都覆盖的一点上进行深度测试。但这仅适用于三角形不相交的情况 - 但如果可以假设,您将不需要复杂的算法来首先投影和裁剪它们。
标签: java opengl 3d translucency