SlideShare a Scribd company logo
実践! QBVH
2013/8/24 レイトレ合宿
林 秀一
(http://d.hatena.ne.jp/shuichi_h)
※スライドの一部の図について
•以下の画像はwikipediaから借用しており、
ライセンスはwikipediaの表記に従います。
http://en.wikipedia.org/wiki/Bounding_volume_hierarchy
http://en.wikipedia.org/wiki/K-d_tree http://en.wikipedia.org/wiki/Octree
アジェンダ
1. 空間構造とは
2. なぜ必要?
3. さまざまな空間構造
4. 人気の空間構造
5. 空間構造の対価
6. よい空間構造とは
7. AABB
8. BVH
1. 構造
2. 構築
3. AABBとRayの交差判定
4. トラバースの流れ
9. QBVH
1. 特長
2. 構造
3. データ構造
4. 構築
5. 交差判定
6. トラバース早期打ち切り
10. 参考文献
空間構造とは
•空間を何らかのルールで区切った構造
•空間中のデータを高速に探索するために使
用される事が多い
なぜ必要?
•単純にレイトレを作ると プリミティブの数
レイの数 の交差判定が必要
•プリミティブやレイの数が増えるとすぐに非現
実的な処理時間になる
➡空間構造を使えば...
•交差判定処理の大部分を省ける
•計算量の増加がlogオーダーに抑えられる
なぜ必要?
•レイが当たった領域の中にある三角形だけ判定
すればよい
空間構造あり空間構造なし
空間構造の対価
•空間構造を格納するメモリ
•構築時間
•動的なシーンでは、更新も必要、
部分的に再構築する等の最適化も必要
よい空間構造とは
•交差判定が高速
•構築が高速
•メモリ使用量が少ない
•インコヒーレントなレイに対しても有効
(バラバラの方向からのレイにも有効)
さまざまな空間構造
Uniform Grid Octree
kd-tree BVH 等々...
Uniform Grid Octree
人気の空間構造
kd-tree BVH
レイトレでは、kd-tree と BVH が人気
AABB
•Axis-Aligned Bounding Box
•XYZ軸に平行なバウンディングボックス
•BVHで使用
BVH
Bounding Volume Hierarchy
BVH:構造
• 外側のAABBの中に、2つのAABBを含む
BVH:構造
•2分木になる
•葉はプリミティブ
•各ノードが自身のAABBを持つ
BVH:構造
•AABBは重なっていることもある
•あるノードの配下にあるオブジェクトはすべて、
そのノードのAABBに収まる
•空間的に収まっていても、そのノード配下とは限らない
BVH: 構築
よりよい方法はototoiさんのセミナーで!
方法1
中央の位置で分割
方法2
同数になるように分割
AABBとRayの交差判定
➡レイとBBoxが交わる範囲があるか否か判定する
Ray
AABB
•交差する位置座標を求める必要はない
•交差しているか、していないかだけ分かればOK
e
d
xmin
AABBとRayの交差判定
e …レイの始点
d …レイの方向
Ray
レイとAABBの交点を求める
AABBとRayの交差判定
txmin = (xmin - xe) / xd
レイdをtxmin倍すると xminと交わる
txmin倍
txmin
e
d
xmin
Ray
xd
xmin - xd
AABBとRayの交差判定
tymin
tymax
txmin
txmax
t [tymin, tymax]
t [txmin, txmax]
t [txmin, txmax] [tymin, tymax]
縦横で交わるtの範囲を求めて
tymax>txminか判定する
※縦横両方tというパラメータ空間の値なので比較できる
tymaxtxmin
AABBとRayの交差判定
レイの方向や、ゼロ除算によって出てくる+ , - ,を
考慮しても、最終的にシンプルなロジックになる。
詳細はRealistic Ray Tracing等を参照。
AABBとRayの交差判定
bool BBox::RayIntersect(const Ray &r, float tmin, float tmax)
{
// X軸
int sign = r.sign[0];
float t0 = (bb[sign].x - r.o.x) / r.dir.x;
float t1 = (bb[1-sign].x - r.o.x) / r.dir.x;
if (t0 > tmin) tmin = t0;
if (t1 < tmax) tmax = t1;
if (tmin > tmax) return false;
// Y軸
...
// Z軸
...
return true;
}
※もちろん割り算は予め1.f / r.dirを計算してRayに保存しておき、それとの掛け算にした方がいい
AABBとRayの交差判定
bool BBox::RayIntersect(const Ray &r, float tmin, float tmax)
{
// X軸
int sign = r.sign[0];
float t0 = (bb[sign].x - r.o.x) / r.dir.x;
float t1 = (bb[1-sign].x - r.o.x) / r.dir.x;
if (t0 > tmin) tmin = t0;
if (t1 < tmax) tmax = t1;
if (tmin > tmax) return false;
// Y軸
sign = r.sign[1];
t0 = (bb[sign].y - r.o.y) / r.dir.x;
t1 = (bb[1-sign].y - r.o.y) / r.dir.y;
if (t0 > tmin) tmin = t0;
if (t1 < tmax) tmax = t1;
if (tmin > tmax) return false;
// Z軸
sign = r.sign[2];
t0 = (bb[sign].z - r.o.z) / r.dir.z;
t1 = (bb[1-sign].z - r.o.z) / r.dir.z;
if (t0 > tmin) tmin = t0;
if (t1 < tmax) tmax = t1;
if (tmin > tmax) return false;
return true;
} ※もちろん割り算は予め1.f / r.dirを計算してRayに保存しておき、それとの掛け算にした方がいい
トラバースの流れ
1.RayとノードのBBoxを交差判定
(1)ヒットした場合
1)ノードが枝:
2つの子ノードをそれぞれ交差判定(再帰処理)
2)ノードが葉:
 交点の位置、色、法線等、必要な情報を格納
(2)ヒットしなかった場合
 何もせずreturn
QBVH: 特長
•SIMD命令を効果的に使用
•Binary BVH比 1.6∼2.0倍 高速
•kd-tree比 1.3∼1.6倍 高速
•メモリは10%∼50%削減
•インコヒーレントなレイに対しても有効
(※以上は、下記論文での主張です。)
H. Dammertz and J. Hanika1 and A. Keller: Shallow Bounding Volume Hierarchies for Fast
SIMD Ray Tracing of Incoherent Rays.
http://www.uni-ulm.de/fileadmin/website_uni_ulm/iui.inst.100/institut/Papers/QBVH.pdf
インコヒーレントなレイにも有効
•SIMDを使う別の手法:「レイパケット」の場合...
‣複数のレイをまとめてSIMDで交差判定
‣インコヒーレントなレイだとSIMDが有効に活用されず
➡一方でQBVHは、常にSIMDを有効活用する
QBVH:構造
•4つ(Quad)の子ノードを持つ
•子ノードのAABBは親のノードが持つ
•4つの子ノードのAABBをSIMDでまとめて
交差判定
Binary BVH Quad BVH
QBVH:構造
•ツリーが浅くなる
➡トラバース速そう
0
1
2
3
4
0
1
QBVH: データ構造
child0 child1 child2 child3
__m128
__m128
__m128
__m128
__m128
__m128
min x min x min x min x
min y min y min y min y
min z min z min z min z
max x max x max x max x
max y max y max y max y
max z max z max z max z
child0 idx child1 idx child2 idx child3 idx
axis top axis left axis right fill
1ノードあたり sizeof(float) * 8 * 4 = 128
QBVH: データ構造
child0 child1 child2 child3
__m128
__m128
__m128
__m128
__m128
__m128
min x min x min x min x
min y min y min y min y
min z min z min z min z
max x max x max x max x
max y max y max y max y
max z max z max z max z
child0 idx child1 idx child2 idx child3 idx
axis top axis left axis right fill
min/max xyz …子ノードのAABB
child idx …子ノードのインデックス
axis …分割軸 0:x 1:y 2:z
QBVH: データ構造
child0 child1 child2 child3
__m128
__m128
__m128
__m128
__m128
__m128
min x min x min x min x
min y min y min y min y
min z min z min z min z
max x max x max x max x
max y max y max y max y
max z max z max z max z
child0 idx child1 idx child2 idx child3 idx
axis top axis left axis right fill
SIMD処理できるように
SoA(Structure of Array)レイアウト
QBVH: データ構造
axis left
axis right
axis top
QBVH: 子ノードのindex
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
child idx:
32bit
空ならINT_MIN
QBVH: 子ノードのindex
枝or葉(1bit)
枝or葉のindex(31bit)
△ △ △ △ △ △ NULL △ △ △ △ △ NULL
先頭のインデックスを指す
葉のデータの配列:
child idx:
やり方 その1
QBVH: 子ノードのindex
枝or葉(1bit)
枝or葉のindex(31bit)
△ △ △ △ △ △ △ △ △ △ △ △ △
先頭のインデックスを指す
葉のデータの配列:
child idx:
やり方 その2
子の数(4bit)
QBVH: 子ノードのindex
枝or葉(1bit)
枝or葉のindex(31bit)
△ △ △ △ △ △ △ △ △ △ △ △ △
葉のデータの配列:
child idx:
やり方 その3
葉の数
葉のindex
その他情報
葉の数
葉のindex
その他情報
葉の数
葉のindex
その他情報
QBVH: 構築
•区切った領域をもう一段階、区切るだけ
•Binary BVHと同じ要領でOK
0
QBVH: 交差判定
•4つの子ノードのAABBをSIMDでまとめて
交差判定
•次項ソースコード参照
inline int SIMD_QBVH::IntersectSIMD(
const __m128 bboxes[2][3], // min-max[2] of xyz[3] of boxes[4]
const __m128 orig[3], // ray origin, xyz[3]
const __m128 idir[3], // ray inverse direction, xyz[3]
const int sign[3], // ray xyz direction -> +:0,-:1
__m128 tmin, __m128 tmax // ray range tmin-tmax
) const
{
// x coordinate
tmin = _mm_max_ps(
tmin, _mm_mul_ps(_mm_sub_ps(bboxes[sign[0]][0], orig[0]), idir[0])
);
tmax = _mm_min_ps(
tmax, _mm_mul_ps(_mm_sub_ps(bboxes[1 - sign[0]][0], orig[0]), idir[0])
);
// y coordinate
tmin = _mm_max_ps(
tmin, _mm_mul_ps(_mm_sub_ps(bboxes[sign[1]][1], orig[1]), idir[1])
);
tmax = _mm_min_ps(
tmax, _mm_mul_ps(_mm_sub_ps(bboxes[1 - sign[1]][1], orig[1]), idir[1])
);
// z coordinate
tmin = _mm_max_ps(
tmin, _mm_mul_ps(_mm_sub_ps(bboxes[sign[2]][2], orig[2]), idir[2])
);
tmax = _mm_min_ps(
tmax, _mm_mul_ps(_mm_sub_ps(bboxes[1 - sign[2]][2], orig[2]), idir[2])
);
return _mm_movemask_ps(_mm_cmpge_ps(tmax, tmin));//tmin<tmaxとなれば交差
}
QBVH: トラバース早期打ち切り
(1)
(2)
(3)
(4)
•レイのxyzの符号と分割軸の方向から、
交差判定する順番にノードをソート
•もし葉(三角形)に当たったら、次のノード
以降の交差判定を省略
参考文献
H. Dammertz and J. Hanika1 and A. Keller: Shallow Bounding Volume
Hierarchies for Fast SIMD Ray Tracing of Incoherent Rays.
http://www.uni-ulm.de/fileadmin/website_uni_ulm/iui.inst.100/institut/Papers/QBVH.pdf
QBVHの論文です。
ototoi: QBVHを実装した - 明日ではないから
http://d.hatena.ne.jp/ototoi/20090925/p1
QBVHについての解説、他の空間構造とのパフォーマンス比較結果、ソースコードがあります。
Shirley P.: Realistic Ray Tracing, Second Edition. AK Peters, Ltd., 2000.
http://www.amazon.com/dp/1568814615
BVHのソースコード、AABB-Ray交差判定の詳しい説明が載っています。
Kayvon F.: CMU 15-869, Graphics and Imaging Architectures.
http://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15869-f11/www/
Carnegie Mellon Universityのグラフィックスコースの資料。
Real-time ray tracingというリンクのPDFにレイパケットの説明があります。
ありがとうございました

More Related Content

実践QBVH