光先追踪的加速方法就是引入层次结构数据结构,计算光线与层次结构的相交,从而加速光线与场景的求交。
OBB与Ray求交
- 我们在更之前的地方定义了一个
OBB
,往前翻一番也许就能找到
- \(center\) - 盒子的中心点
- \(\vec{u}\) - 盒子的某个法线 \(u\)
- \(\vec{v}\) - 盒子的某个法线 \(v\)
- \(\vec{w}\) - 盒子的某个法线 \(w\)
- 盒子的尺寸 - \(size\left(h_u,h_v,h_w
\right )\)
- 同样的 我们曾经定义过一条射线
- \(Ray \left( P\right ) = O + t \cdot
\vec{u}\)
Ray(P)
射线上某一点
O
射线的起点
t
沿着方向\(\vec{u}\)前进的长度
- \(\vec{u}\) 射线的方向向量
slab method
- 在OBB与光线的求交计算中,我们常用的方法是
slab method
- 将我们测量的这个盒子分成三组平行的板
- 分别将光线与对应的板做相交计算,在射线的方向上,有一个进入这一组板的时间\(t^{min}\),以及一个出板的时间\(t^{max}\)
- 分别计算对于三个面板的\(t^{min}_{i},t^{max}_{i},i \in
\left(u,v,w\right)\)
- 如果射线与盒子相交,那么简单的说这条射线一定有一段时间是处于这三个\(t^{min},t^{max}\)之中的。
计算原理
\(P_{min} = P + t_{min} \cdot
\vec{u}\) - \(1.0\)
\(P_{max} = P + t_{max} \cdot
\vec{u}\) - \(1.1\)
\(P_{i} = P + t \cdot \vec{u}\)
- \(1.2\)
$(P_{min} - C ) = min $ - \(1.3\)
$(P_{max} - C ) = max $ - \(1.4\)
\(1.0\)式 & \(1.1\)式 带入 \(1.3\)式 & \(1.4\)式得到: \[
\left [ \left (P + t_i \cdot \vec{u} \right ) - C \right ] \cdot
\vec{O_n} = O_{Size.j} / 2.0, i \in (min,max),j \in (x,y,z), n \in
(u,v,w)
\] => 化简得: \[
t_i = (O_{Size.i} / 2.0 - (C - P) \cdot \vec{O_n}) / (\vec{u} \cdot
\vec{O_n}), i \in (min,max),j \in (x,y,z), n \in (u,v,w)
\]
求交实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| bool Intersect::IntersectObbWithRay(const OBB& obb, Ray & ray) { auto delta = obb.m_center - ray.m_begin; float t1, t2; double minT = DBL_MIN, maxT = DBL_MAX;
{ float e = glm::dot(delta, obb.m_u); float f = glm::dot(ray.m_dir, obb.m_u); if (std::abs(f) > 1e-20) { t1 = (e + obb.m_size.x / 2.0) / f; t2 = (e - obb.m_size.x / 2.0) / f; if (t1 > t2) { auto temp = t1; t1 = t2; t2 = temp; }
if (t1 > minT) { minT = t1; } if (t2 < maxT) { maxT = t2; } if (minT > maxT) { return false; } if (maxT < 0) { return false; } } else if (-e - obb.m_size.x / 2.0 > 0 || -e + obb.m_size.x / 2.0 < 0) { return false; } }
{ float e = glm::dot(delta, obb.m_v); float f = glm::dot(ray.m_dir, obb.m_v); if (std::abs(f) > 1e-20) { t1 = (e + obb.m_size.y / 2.0) / f; t2 = (e - obb.m_size.y / 2.0) / f; if (t1 > t2) { auto temp = t1; t1 = t2; t2 = temp; }
if (t1 > minT) { minT = t1; } if (t2 < maxT) { maxT = t2; } if (minT > maxT) { return false; } if (maxT < 0) { return false; } } else if (-e - obb.m_size.y / 2.0 > 0 || -e + obb.m_size.y / 2.0 < 0) { return false; } }
{ float e = glm::dot(delta, obb.m_w); float f = glm::dot(ray.m_dir, obb.m_w); if (std::abs(f) > 1e-20) { t1 = (e + obb.m_size.z / 2.0) / f; t2 = (e - obb.m_size.z / 2.0) / f; if (t1 > t2) { auto temp = t1; t1 = t2; t2 = temp; }
if (t1 > minT) { minT = t1; } if (t2 < maxT) { maxT = t2; } if (minT > maxT) { return false; } if (maxT < 0) { return false; } } else if (-e - obb.m_size.z / 2.0 > 0 || -e + obb.m_size.z / 2.0 < 0) { return false; } }
return true; }
|