16.2K Views
January 17, 24
スライド概要
CEDEC2016 (Computer Entertainment Developers Conference 2016)で行われた講演
『「バイオハザード7」を実現するレンダリング技術』
で使用されたスライドです。
※本スライドには動画が含まれております。pptxファイルをダウンロードすることで動画込みでご覧いただけます
講演概要は以下のサイトをご覧ください。
https://cedec.cesa.or.jp/2016/session/ENG/918.html
※CEDECの資料公開サイトCEDiLでも本資料が公開されています。
https://cedil.cesa.or.jp/
株式会社カプコンが誇るゲームエンジン「RE ENGINE」を開発している技術研究統括によるカプコン公式アカウントです。 これまでの技術カンファレンスなどで行った講演資料を公開しています。 【CAPCOM オープンカンファレンス プロフェッショナル RE:2023】 https://www.capcom-games.com/coc/2023/ 【CAPCOM オープンカンファレンス RE:2022】 https://www.capcom.co.jp/RE2022/ 【CAPCOM オープンカンファレンス RE:2019】 http://www.capcom.co.jp/RE2019/
「バイオハザード7」を実現する レンダリング技術 株式会社カプコン 三嶋 仁/清水昭尋
RE ENGINE • バイオハザード7 のために開発 • 高速なゲーム作成 • 高パフォーマンス • 目標 – 1080p 60FPS
はじめに • 多くの設計概念は、GCC資料をご確認下さい GPU駆動レンダリングへの取り組み http://sssslide.com/www.slideshare.net/capcom_rd/gpu-59175056 • Lighting – 三嶋 • Mesh/Fluid – 清水
フレームとコスト Frame Cost Common(Wrinkle,Stamp,Water,NRC) + AsyncShadowCacheCopy ~0.85ms Gbuffer ( + PreZ)+Decal+WaterSurface ~2.7ms~ Shadow + AsyncLighting ( IndirectLighting,SSAO,HiZ) ~3.0ms~ Lighting +( DirectLighting, SSR, SSSSS, PreFilter) ~3.5ms~ Transparent ~3.5ms PostEffect Bloom + DOF + Tonemap + ColorCorrect + LendsDistortion 1.8~2.5ms UI + (sRGB or BT2020) 0.3ms
照明
照明計算 • 遅延レンダリング – ライティングモデルは唯一ひとつ • Lambert + CookTorrance(GGX) • 一体感のあるライティング – 静的な背景と動的物体は同じ照明を使用 • 直接照明、間接照明の共有 • 放射照度ボリュームとローカルキューブマップを使用 空間的に間接照明を配置 – 多少の環境変化にも対応
直接照明 • 光源の種類 – 平行光源,点光源+IES,投影光源+IES – それぞれの光源の影計算 • 2段階のカリング – GPUオクルージョンカリング • 影の描画のON/OFF – 深度を利用したクラスタードシェーディング • タイルに深度を持たせた構造
拡散反射 • 全てのシェーダで同一の物を使用 – 葉やカーテン、ランプシェードの表現も必要 – 完全拡散反射と完全散乱を線形補間 Diffuse = 𝑙𝑒𝑟𝑝( 𝑛・𝑙 1 , , 𝑡𝑟𝑎𝑛𝑠𝑙𝑢𝑐𝑒𝑛𝑐𝑦) 𝜋 4𝜋
光沢反射 • GGXの近似計算 – 光源と視線がすれすれの角度の時に異なる
ライトカリング • 32x32ピクセルを1タイル、深度方向を16分割して使用 – タイルの最小値と最大値の深度を視推台に沿わせた AABBと、光源との交差判定 – スポットなどは、複数の平面との交差判定で対応 • 可能なら非同期コンピュートでカリングを実行
ライトカリング クラスター構造 • Cluster Grid – 60x34x16 (1080p), 32bit – ライトリストの使用マスクを8bit保持 • ライトリストの読み込みを抑える目的 Cluster Grid(32bit) 24bit 8bit Light cluster offset address Light List mask • Light List • – 最大連続した8個の32bitデータ – ビット単位でライトインデックスの表示状態を保持 – Light List Maskとビットからライトのインデックスを復元[Humus 2015] 最大512光源まで対応 Light List Mask X LightList(32bit) X LitID:7 X LitID:0
ライトデータの参照 • ビット演算でライトインデックスを求める uint mask = LightClusterGrid.Load(uint4(ss,lod,0)); uint cluster_mask = mask & 0xff; uint offset_address = (mask & 0xffffff00) >> 6; while (cluster_mask){ uint cluster_idx = firstbitlow(cluster_mask); cluster_mask = bitfieldinsert((1 << cluster_idx),0,cluster_mask); uint light_mask = LightList.Load( mad( cluster_idx, 4, offset_address)); while (light_mask){ uint idx = firstbitlow(light_mask); light_mask = bitfieldinsert((1 << idx),0,light_mask); uint litght_idx = mad( cluster_idx, 32, idx); LightParameter light = LightParameterSRV[ light_idx];
深度方向の分割 • 深度の線形分割だと分解能が悪い 深度間を対数で分割 深度間を線形に分割 𝑠𝑙𝑖𝑐𝑒𝐼𝑛𝑑𝑒𝑥 ∗ 𝑠𝑙𝑖𝑐𝑒𝐶𝑜𝑢𝑛𝑡 partition(Z)= 𝑙𝑒𝑟𝑝(𝑍𝑚𝑖𝑛 , 𝑍𝑚𝑎𝑥 , 𝑙𝑜𝑔𝛼 ( 𝛼 = 16 を使用 (𝛼 − 1) + 1))
ライトカリング結果
メモリアクセスの高速化 • Wave単位でメモリアクセスが同一になる可能性 – 赤色はwave内で同じ光源情報を取得した箇所 – 緑色はwave内で異なる個所 • Waveはハードウェアによりサイズが異なる – コンソール向けの最適化 – PCはSM6.0のWave Voteで実現? LightParameter light; uint lane0 = WaveReadFirstLane( light_idx); if( WaveAllTrue(light_idx == lane0)){ light = LightParameterSRV[ lane0]; }else{ light = LightParameterSRV[ light_idx]; }
影 • 影の管理領域 – Texture2DArray – Default 1024x1024x32 D32Float( or D16Unorm) • 影のキャッシュ – 動かない光源が、静的な物体の影の投影計算を高速化するために使用 – 内部のフォーマットは、通常の影と同一のものを使用
影キャッシュの更新戦略 • • 光源が動く →キャッシュしない 光源が動かない →キャッシュ対象 – 影キャッシュが存在しない • 影バッファに背景の深度を描画後、影キャッシュにコピー • 動的物体を影バッファに描画 – 影キャッシュが存在する • 動的な物体が映らない – 初めて映らなかった 影キャッシュを影バッファにコピー – 動的な物体が映らない状態が2フレーム以上続く 影キャッシュを影バッファにコピーせず現在の影を表示 • 動的な物体が映る – 影キャッシュを影バッファにコピー – 動的物体を影バッファに描画
影キャッシュのコピー • AsyncCompute/DMAが使える環境 – 描画処理の先頭から実行 – もしくは、前のフレームの安全なところから実行 – 可能な限りコピー時間を無くす • 使えない環境 – 描画直前にコピーを実行
影キャッシュのコピー • コピーコスト – 一枚のシェードマップのコピーが0.1msと仮定 – 32個コピーすると3.2ms • コピーをしない影が最速 影の視推台内で動的な物体が存在する場合のみ コピーを実行
間接照明 • 放射照度ボリュームとローカルキューブマップを使用 – コンピュートシェーダで同時に計算 • 放射照度ボリューム – データ構造の分離 • プローブ間の接続関係を持ったメッシュのネットワーク • プローブ自身の明るさ情報 – 照明条件の変化につよくなる • ローカルキューブマップ – 放射照度ボリュームの結果を利用した補正
プローブネットワーク • プローブ間の接続関係は四面体構造で管理 [Cupisz 2012],[Valient2014] • プローブの位置の作成 – エンジンでボクセル化,プローブの位置を作成 ミップマップ的な疎なプローブを2段階作成 – プローブの位置から四面体群を作成 – 四面体の空間構造をBSPツリーに変換 スタックレスツリーで保持
プローブネットワーク
ライトプローブ
• ライトプローブはエンジンで作成
– [Stefanov 2012]の基底を利用
• 各4方向の色情報はR11G11B10Floatで保持
• 復元は飽和しなければ低精度を利用
//ベース
float3 decodeR11G11B10(uint X){
float3
C;
uint R = bitfieldextract(X,0u,11u);
C.x = f16tof32(R << F11_OFFSET);
uint G = bitfieldextract(X,11u,11u);
C.y = f16tof32(G << F11_OFFSET);
uint B = bitfieldextract(X,22u,10u);
C.z = f16tof32(B << F10_OFFSET);
return C;
}
//低精度
float3 decodeR11G11B10_EST(uint X){
float3
C;
C.x = abs(f16tof32(X << 4));
C.y = f16tof32(bitfieldextract(X,7u,15u));
C.z = abs(f16tof32(X >> 17));
return C;
}
ライトプローブの調整 • 区画ごとにライトプローブの調整が可能 – ネットワークと光源が分離されているため – 照明条件の変更で利用
プローブ結果
プローブ結果
プローブ結果
パフォーマンス改善 • ピクセル単位で探査は計算コストが高い – 均一格子の追加 – 1フレーム前の結果を再利用 – 非同期コンピュートでの動作
均一格子の追加 • 位置から明示的に格子位置がわかる – 空間を32x32x32の均一格子で分離 – 格子内の四面体を利用したBSPへ • メモリの削減と、実行速度の改善
1フレーム前の結果を再利用 • 前フレームで照明計算後に四面体IDを保存 • 現在のワールド座標から、過去のスクリーン 座標の四面体IDを再利用可能か評価
非同期で計算 • 非同期が可能なプラットフォームなら – コンピュートシェーダで間接照明 • 影の計算の裏で動作
放射照度ボリュームの情報 cost プローブの数 9628個 プローブネットワークのサイズ 14MB プローブネットワークの構築時間 80秒(Core i7-4790) ライトプローブのサイズ 154KB
ローカルキューブマップ • 間接照明の光沢反射 – HDDデータ 256x256(BC6h) cubemap – 内部データ 512x512xmip8 R11G11B10FloatのOctahedronMap エッジ付近はEdgeFixedUpと似たバイリニアフィルタを使い連続性を確保 • 光沢反射をそのまま使うと問題が発生 – 暗がりで有機物が金属質に見える – 場所によって拡散光の光沢感の明るさに差が発生
ローカルキューブマップ • キューブマップの明るさを再正規化[Lazarov 2014] IndirectS𝑝𝑒𝑐𝑢𝑙𝑎𝑟 = 𝑙𝑢𝑚𝑎(𝑃𝑟𝑜𝑏𝑒𝐷𝑖𝑓𝑓𝑢𝑠𝑒 𝑛 ) ∗ 𝑙𝑢𝑚𝑎(𝐿𝑜𝑐𝑎𝑙𝐶𝑢𝑏𝑒𝑚𝑎𝑝(𝑛,𝑙𝑜𝑤𝑒𝑠𝑡𝑀𝑖𝑝) 𝐿𝑜𝑐𝑎𝑙𝐶𝑢𝑏𝑒𝑚𝑎𝑝(𝑟, 𝑚𝑖𝑝)
スペキュラープローブの修正前
スペキュラープローブの修正後
間接照明の課題と展望 • • • • 間接照明の計算 – 1080pで1.5ms ネットワーク構築は超遅い – 綺麗なBSPツリーを作るのは困難 品質 – プローブ間の補間が美しくない(まるで頂点カラー) – ライトリーク • 現状プローブの位置を移動することで回避 – キューブマップの補正 – プローブ自体の品質 リライティング – エンジンで焼く時間 • VPLでプローブをリライティング?
メッシュ
メッシュレンダラの設計 • IndirectDraw API の使用 • 統合的バッファ管理 • GPUカリング 概要は「GPU駆動レンダリングへの取り組み」をご覧ください [Mishima2016]
IndirectDraw API • すべてのメッシュが IndirectDraw (Multi) – IndirectDraw 引数バッファは全メッシュで一つ – アロケータによりバッファを切り出して利用 • IndirectDraw による効果 – ☻ GPUからの描画バッファ操作 – バッファ管理のオーバーヘッド
メッシュ描画のための情報 • レンダラが全メッシュバッファを管理 Indirect Args 情報 インスタンス情報 Index Count World Matrix Instance Count Previous World Matrix Start Index Location Joint Offset Base Vertex Location Previous Joint Offset Start Instance Location User Parameters 20 Byte 112 Byte
描画コール DrawIndirect CPU変数 IndirectArgsオフセット Root32bit Constant Indirect Args バッファ インスタンスインデックスバッファ 1 3 2 5 9 ・ ・ 8 ・ 7 ・・・・・・ インスタンスバッファ • 描画コール固有データは DirectX12 RootSignature風 • IndirectArgs、インスタンス インデックス、インスタンス 情報それぞれのバッファ データはCPU更新
描画コール DrawIndirect CPU変数 • オフセットと描画数を指定 • 同一マテリアルで描画する ものは連続で並べておく IndirectArgsオフセット Root32bit Constant Indirect Args バッファ インスタンスインデックスバッファ 1 3 2 5 9 ・ ・ 8 ・ 7 インスタンスバッファ
描画コール DrawIndirect CPU変数 IndirectArgsオフセット Root32bit Constant Indirect Args バッファ インスタンスインデックスバッファ 1 3 2 5 9 ・ ・ 8 ・ 7 インスタンスバッファ • インスタンスインデックス バッファを介して インスタンス情報を引く • SV_InstanceIDによる Instance Count パラメータ への対応 • インスタンシング描画はイ ンスタンスインデックスを 連続で並べておく
GPUカリング • コンピュートシェーダーによる実装 – Indirect Args の Instance Count を操作 – 非同期実行 • バイオハザード7では鋭意検証中 – 視錐台カリング – オクルージョンカリング [Hill2011] – クラスターカリング[Haar2015]
メッシュクラスター • 巨大なバウンダリを持つメッシュを分割 – IndirectDraw により一括描画 – カリングによる頂点負荷の軽減 – 背面クラスターのカリング[Chajds2016]
クラスター分割
クラスター分割 三角形 24109 クラスター 98 背面カリングが効くクラスター 16
メッシュの課題と展望 • 新旧設計の混在からの脱却 – IndirectDraw の利点を最大限に引き出せない • 頂点・インデックスバッファの統合 etc… – マテリアル、テクスチャ管理の最適化 • 積極的なカリング – 効果的な負荷削減には至っていない – 事前処理による頂点・インデックス最適化
流体
流体シミュレーションの導入 • 新しいエフェクト表現としての利用 – 動きや外観、インタラクション • GPUによる2Dシミュレーション – 2種類のシミュレーションを実装 • 煙、炎 • 水面 概要は「妄想から実装へ ~次世代VFX表現の、リアルタイムへの落とし込みの挑戦とプロセス~」をご覧ください[Watamura2015]
流体 (煙・炎) • シミュレーション – 2D速度場を利用した密度移流 – FP16精度 • 描画 – 密度テクスチャのカラーグレーディング – ディテールテクスチャの投影 – 2Dビルボードスプライト
流体のシミュレーション • Euler 方程式を解く 𝜕𝐯 1 + 𝐯 ∙ 𝛁 𝐯 = − 𝛁𝑝 + 𝐟 𝜕𝑡 𝜌 𝛁∙𝐯 = 𝟎 • アルゴリズム – 移流 (2次精度 MacCormack) [Selle2007] – 圧力 (2次精度中心差分) – 外力 • 数値発散の原因、クランプ・運用で回避
流体処理フロー エフェクト生成 密度移流 密度バッファ • シミュレーションはコンピュート シェーダーによる実装 • 密度バッファ、速度バッファを シミュレーションにより更新 • 描画はエフェクトパス 流体シミュレータ 速度バッファ 消滅 描画
流体シミュレータの処理 速度移流 • GPU流体シミュレーション[Harris2004] – テクスチャ使用の格子 外力・障害物処理 圧力・プロジェクション • 移流計算は3パスMacCormack (密度移流にも使用) [Crane2008] • 圧力計算はJacobi 8-16パス • その他リソース依存が発生する箇所 で数パス – rot, div の計算等
シミュレータへの外力 • 速度エミッタ、障害物との接触 – 3Dカプセル形状 • 移動による慣性 – 速度バッファへの外力ベクトル付与 • Curlノイズ – 2Dノイズから生成
シミュレータへの外力(動画)
流体のシミュレーションコスト • すべてのシェーダーが軽量 – 10~20パスの計算 – レジスタプレッシャーがないため非同期で混合 シミュレーション解像度 密度解像度 GPU(ms) x 𝟐2 x 𝟒2 x 𝟖2 32 x 32 0.074 0.078 0.086 64 x 64 0.079 0.099 0.168 128 x 128 0.120 0.203 0.526
流体のシミュレーションコスト • すべてのシェーダーが軽量 – 10~20パスの計算 – レジスタプレッシャーがないため非同期で混合 シミュレーション解像度 密度解像度 GPU(ms) x 𝟐2 x 𝟒2 x 𝟖2 32 x 32 0.074 0.078 0.086 64 x 64 0.079 0.099 0.168 128 x 128 0.120 0.203 0.526
流体の適用例 • 流体エフェクトは複数発生することが多い – 5~10枚程度のビルボード – ビルボードを重ねることによる立体感
流体 (水面) • シミュレーション – 2D速度場と高さを移流 – FP16精度 • 描画 – 高さバッファ、テセレータを利用した頂点生成 – ユーザーマテリアルの利用
水面のシミュレーション • Shallow Water 方程式を解く • アルゴリズム 𝜕𝜂 + 𝛁𝜂 𝐯 = −𝜂𝛁 ⋅ 𝐯 𝜕𝑡 𝜕𝐯 + 𝛁𝐯 𝐯 = 𝑔𝛁(𝜂 + 𝑔𝑟𝑜𝑢𝑛𝑑) 𝜕𝑡 – 移流 (1次精度 Semi-Lagrangian) – 高さ・速度 (2次精度中心差分)
水面処理フロー 生成 水面シミュレータ 速度バッファ 高さバッファ • シミュレーションはコンピュート シェーダーによる実装 • 速度バッファ、高さバッファを シミュレーションにより更新 • 描画はGBuffer or 半透明 頂点カリング インデックスバッファ 消滅 描画
水面シミュレータの処理 移流 • 格子分割による処理[Thuerey2008] – 2パスシェーダー 高さを更新 障害物処理 速度を更新 • スレッドグループ内スレッド数は 8x8 or 16x16 – LDSを活用 – 境界スレッドは 隣接をフェッチ
水面シミュレータの処理 • 格子分割による処理[Thuerey2008] 移流 == 0) { if (threadGroupID.x valueCache[id - int2(1, 0)] = value[dispatchThreadID - int2(1, 0)]; – 2パスシェーダー } if (threadGroupID.y == 0) { 高さを更新 valueCache[id - int2(0, 1)] = value[dispatchThreadID - int2(0, 1)]; } … • スレッドグループ内スレッド数は 8x8 or 16x16 障害物処理 速度を更新 – LDSを活用 – 境界スレッドは 隣接をフェッチ
頂点カリング • タイルパターンは一様グリッド float x = frac(vertexID * gTileCountInv.x); float y = floor(vertexID * gTileCountInv.x) * gTileCountInv.y; • 可視判定 – 各タイルAABBと視錐台 – 有効であればオクルージョン – 可視タイルでインデックスバッファを構築 • DrawIndexedIndirect
水面のアーティスト制御 • 高さバッファとコントロールマップのブレンド – シミュレーションへの介入 float blendHeight = gControlMap.SampleLevel(BilinearWrap, uv * gTilingCoeff, 0); float newHeight = height + gBlendCoeff * blendHeight; • 3Dカプセル形状とのインタラクション – 接触箇所の高さを変化
水面のアーティスト制御(動画)
水面の描画 • GBufferを利用 – ☻ フォワード描画によるライティング負荷を抑制 – 屈折表現が出来ない • 2パス描画 (Zを別に描く) – Zを読みながら描けるプラットフォームでは1パス
GBufferへの水面ブレンド • 色と法線、その他パラメータをブレンド GBufferDecalOutput output = getGBufferOutputForDecal(materialOutput); output.BaseColorMetallicTranslucency.a = min(blend * gWaterColorBlend, 1); output.NormalXNormalYRoughnessMisc.a = min(blend * gWaterNormalBlend, 1); ブレンドステート [BaseColorMetallicTranslucency] ColorOp: “Add”, SrcColor: “SrcAlpha”, DestColor: "InvSrcAlpha" AlphaOp: “Add”, SrcAlpha: “One”, DestAlpha: "Zero" ColorMask: "R|G|B" [NormalXNormalYRoughnessMisc] ColorOp: “Add”, SrcColor: “SrcAlpha”, DestColor: "InvSrcAlpha" AlphaOp: “Add”, SrcAlpha: “BlendFactor”, DestAlpha: “Zero" ColorMask: "R|G|B|A"
ブレンド係数による変化 カラー 1 法線 0
ブレンド係数による変化 カラー 1 法線 1
ブレンド係数による変化 カラー 法線 0.8 0
ブレンド係数による変化 カラー 0.8 法線 0.8
ブレンド係数による変化 カラー 0.2 法線 0.8
水面のコスト • シミュレーションは解像度の影響が大きい – メモリbusyになりがち 解像度 128x128 256x256 512x512 1024x1024 GPU(ms) 0.043 0.079 0.291 0.607 • 描画は頂点負荷になりやすい – テセレーションは距離ベース
水面の適用例 • 30㎡の水面 – シミュレーション解像度 512x512 – 描画解像度 128x128 + テセレーション
流体の課題と展望 • 負荷は(それなりに)高め – リソースバッファ数、アロケーション – 高解像度でのシミュレーションコスト • シミュレーションの安定化 – アーティファクト改善
本日のセッション紹介 13:30~14:30 ラピッドイテレーションを実現するゲームエンジンの設計 石田 智史 「バイオハザード7 レジデント イービル」におけるVR完全対応までのみちのり、歩みの中の気づき 高原 和啓(メインホール) 14:50~15:50 REエンジンで採用されているアセット変換の仕組みとキャッシュ共有について 是松 匡亮 16:30~17:30 「バイオハザード7 レジデント イービル」におけるアニメーション技術について 橋本 直樹
Q&A 何かご質問はございませんか?
参考文献 • • • • • • • • • • • • • • [Cupisz 2012]Light Probe Interpolation Using Tetrahedral Tessellations [Valient2014] Taking Killzone: Shadow Fall Image Quality Into the Next Generation Practical Clustered Shading http://www.humus.name/Articles/PracticalClusteredShading.pdf Clustered Shading http://www.humus.name/index.php?page=3D&ID=90 [Lazarov 2014]Getting More Physical in Call of Duty: Black Ops II [Stefanov 2012]Deferred Radiance Transfer Volumes: Global Illumination in Far Cry 3 [Mishima2016]GPU駆動レンダリングへの取り組み [Watamura2015]妄想から実装へ ~次世代VFX表現の、リアルタイムへの落とし込みの挑戦とプロセス~ [Hill2011]Practical, Dynamic Visibility for Games http://blog.selfshadow.com/publications/practical-visibility/ [Haar2015]GPU-Driven Rendering Pipelines [Chajds2016]GeometryFX 1.2 – Cluster Culling http://gpuopen.com/geometryfx-1-2-cluster-culling/ [Selle2007]An Unconditionally Stable MacCormack Method [Harris2004]Fast Fluid Dynamics Simulation on the GPU [Crane2008]Real-Time Simulation and Rendering of 3D Fluids • [Thuerey2008]Real Time Physics Class Notes, 11. Shallow Water Equations
GBufferFormat RenderTarget Format RT0 Emissive(必要なら使用) R11G11B10Float RT1 BaseColor(sRGB) + MetallicTranslucency(A) R8G8B8A8Unorm(sRGB) RT2 Normal(X,Y)+Roughness(Z)+MISC R10G10B10A2Unorm RT3 OcclusionSSSSS(X,Occlusion 7bit, SSSSSS 3bit)+Velocity(Y,Z)+VelocitySign(W) R10G10B10A2Unrom Metallic = saturate(MetallicTranslucency *2.0-1.0) Translucency = Metallic > 0 ? 0 : saturate(1.0-2.0* MetallicTranslucency ) Velocity: sqrt(abs(v))で保存
BSP-Treeの探査コード
• データ構造と探査コード例
– ノードは20Byteで表現
– 原始的だが動作
struct BSPNode{
union{
uint
data;
struct{
uint type : 1;
uint index: 31;
};
};
union{
struct{
float3 normal;
float dist;
};
struct{
uint vertexId[4];
};
};
};
uint head= BSPTree.Load(id+0);
uint4 body= BSPTree.Load4(id+4);
w hile ((ihead&1) == 0){
float4 plane = asfloat(body);
if (dot(plane.xyz,worldpos) + plane.w >= 0.001f) {
id+=20;
//次のノードへ移動
}else {
id = head>>1; // 別のノードへ移動
}
index= BSPTree.Load(id+0);
body = BSPTree.Load4(id+4);
}
head>>=1;
//実際のデータへ
uint4 probeID = body;