如何安排GPU上的光栅化器?

时间:2018-03-15 09:31:02

标签: shader gpu gpgpu raytracing rasterizing

在基于k-d树加速结构的光线跟踪器的开发过程中,我遇到了一个问题。有时在光线/三角形交叉测试期间(使用Möller-Trumbore算法),两个相邻的三角形射线都会错过它们。在跨视轴的慢动作期间,它导致暗三角形之间的亮点闪烁(或反之亦然,对于任何对比度对)。特别是对于高多边形模型。

假设,光线/三角交叉算法是整个光线跟踪器的最热点(这个断言是硬全面全面基准测试的结果)。 Möller-Trumbore是最快的GPU算法(BTW我使用GPU,而不是CPU)。由于SAH(表面区域启发式),整个帧时间的大约一半被光线/三角交叉测试消耗。

为了避免闪烁,我只是在对于中心坐标计算和比较步骤的光线/三角形交叉测试期间使用略微加宽的三角形。这些是在运行时执行的。

要正确加宽三角形,请执行以下操作:每个计算uvw乘以三角形对应高度的长度,并与-EPSILON进行比较或1.0 + EPSILON以物理单位测量(如果高度以米为单位,则为0.0001米)。

要计算三角形的所有三个高度,我需要计算它的平方,即交叉积的长度:对于ABC三角形,AB = B - AAC = C - Alength(cross(AB, AC))和每个的长度它的一面:length(AB)length(AC)BC = AC - ABlength(BC)。其中length(vec)sqrt(dot(vec, vec))的地方(提到估算计算的复杂程度)。当然可以很容易地避免sqrt的计算。但是这个扩展步骤仍占用整个帧时间的大约10%。所以在纠正和运行速度之间需要权衡。

现在我记得,光栅化器根本没有EPSILON这样的参数。它的正确性不依赖于舍入误差问题。

如何安排硬件光栅化器?为什么它总是给出正确的结果?

我可以猜想,在相邻三角形的遍历过程中,光栅化器以统一的方式进行计算,误差变得片面,从而在两侧相互补偿。

代码示例(HLSL),其中牺牲了相关性以支持运行时速度:

bool KdTriIntersectCheck(TKdTree kdTree,
                         in TRay ray, in float tMin, in float tMax,
                         inout THit hit, in uint face)
{ // Möller–Trumbore
  float3 A = KdGetVertex(kdTree, hit.triangleIndex, 0);
  float3 AB = KdGetVertex(kdTree, hit.triangleIndex, 1) - A;
  float3 AC = KdGetVertex(kdTree, hit.triangleIndex, 2) - A;
  float3 P = cross(ray.direction, AC);
  float denominator = dot(AB, P);
  if (denominator <= 0.0) {
    return false;
  }
  float3 Q = ray.source - A;
  hit.uv.x = dot(Q, P);
  if ((hit.uv.x < 0.0) || (hit.uv.x > denominator)) {
    return false;
  }
  float3 R = cross(Q, AB);
  hit.uv.y = dot(ray.direction, R);
  if ((hit.uv.y < 0.0) || (hit.uv.x + hit.uv.y > denominator)) {
    return false;
  }
  hit.uv /= denominator;
  hit.distance = dot(AC, R) / denominator;
  hit.isFront = true;
  return (hit.distance >= tMin - EPSILON) && (hit.distance <= tMax + EPSILON);
}

0 个答案:

没有答案