Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CEDEC2019 Directx Raytracing Shader Lesson

orangesuzuki
September 05, 2019

CEDEC2019 Directx Raytracing Shader Lesson

CEDEC2019「シェーダーでかんたんにわかる!」DirectXリアルタイムレイトレーシング入門

「シェーダーでかんたんにわかる!」をテーマに、シェーダーとその描画結果を照らし合わせながら、Microsoft DirectX Raytracing(以下DXR)によるレイトレーシング表現の基礎を解説します。

DirectXやレイトレーシングになじみがない方でも、レイトレーシングの原理を理解し、ゲーム開発に取り入れる際の素養や考え方を身に着けていただくことを目的としています。
https://cedec.cesa.or.jp/2019/session/detail/s5ca1602cd1ab5

▼学習リソースの紹介

■読む
- Ray Tracing Gems : http://www.realtimerendering.com/raytracinggems/
- DirectX-Specs | Engineering specs for DirectX features. : https://microsoft.github.io/DirectX-Specs/
- SIGGRAPH 2018 - Full Rays Ahead! From Raster to Real-Time Raytracing : https://www.slideshare.net/DICEStudio/siggraph-2018-full-rays-ahead-from-raster-to-realtime-raytracing-110056010

■教わる
- Introduction to DirectX RayTracing : http://intro-to-dxr.cwyman.org/
- Introduction to DirectX Raytracing - YouTube : https://www.youtube.com/watch?v=Q1cuuepVNoY

■手を動かす
- GitHub - microsoft/DirectX-Graphics-Samples:https://github.com/microsoft/DirectX-Graphics-Samples
- GitHub - TheRealMJP/DXRPathTracer:https://github.com/TheRealMJP/DXRPathTracer
- GitHub - acmarrs/IntroToDXR:https://github.com/acmarrs/IntroToDXR

orangesuzuki

September 05, 2019
Tweet

More Decks by orangesuzuki

Other Decks in Technology

Transcript

  1. Copyright 2019 DELiGHTWORKS. ディライトワークス株式会社 研究開発部 Real Time Computingユニット リードリサーチャー 鈴木

    克史 「シェーダーでかんたんにわかる!」 リアルタイムレイトレーシング入門 DirectX
  2. Copyright 2019 DELiGHTWORKS. 10 Menu レイトレーシングパイプライン 1 フォンシェーディング 2 レイトレースシャドウ

    3 レイトレースリフレクション 4 レイトレース アンビエントオクリュージョン 5
  3. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 11 レイトレーシングの原理 Scratchapixel

    2.0 Rasterization: a Practical Implementation https://www.scratchapixel.com/lessons/3d-basic-rendering/ rasterization-practical-implementation
  4. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 12 レイトレーシングのパイプライン RayGenerationシェーダー

    ClosestHitシェーダー Missシェーダー 交点あり 交点なし シーンの走査 レイの生成 レイを飛ばす(TraceRay関数) 三角形に交差した? RayGeneration、ClosestHit、Missの 3つのシェーダーをまずおさえよう はい いいえ
  5. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 13 レイトレーシングのパイプライン RayGenerationシェーダー

    Intersectionシェーダー Any-hitシェーダー ClosestHitシェーダー Missシェーダー 交点あり 交点なし シーンの走査 半透明に交差 レイの交差判定 レイの生成 レイを飛ばす(TraceRay関数) はい いいえ 三角形に交差した? 独自に交差判定したい → Intersection 半透明を描画したい → Any-hitシェーダー ※Closest-hitシェーダーでも可能
  6. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 15 アルベドカラーの描画 [shader("raygeneration")]

    void MyRaygenShader() { // 1. レイの生成 Ray ray = レイを生成する(); UINT 繰り返し回数 = 0; // 2. レイを飛ばしてピクセル色を取得する float4 color = TraceRadianceRay(ray, 繰り返し回数); // 3. 取得したカラーをテクスチャーに格納する g_renderTarget[DispatchRaysIndex().xy] = color; } RayGenerationの役目 1. レイの生成 2. レイを飛ばして色を決定 3. テクスチャーに色を出力
  7. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 16 アルベドカラーの描画 //

    closesthitシェーダーのタグ [shader("closesthit")] // RayPayload:出力されるオブジェクト void MyClosestHitShader (inout RayPayload rayPayload, in MyAttributes attr) { // 出力 rayPayload.color = マテリアルカラー; } Closest-hitシェーダーの引数は、 レイについてまわるオブジェクト「RayPayload」と、 交差情報の属性「MyAttributes」が入る ↓ 事前に定義が必要
  8. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 17 アルベドカラーの描画 //

    交差した属性情報 struct MyAttributes { float3 normal; }; // レイについてまわるオブジェクト struct RayPayload { // カラー float4 color; // 再帰回数 uint recursionDepth; };
  9. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 18 フォグの描画 //

    カラー float4 color = マテリアルカラー; // レイの長さ float t = RayTCurrent(); // フォグの適用 color = lerp(color,背景色, 1.0 - exp(-0.000002 * t * t * t)); // 出力 rayPayload.color = color; RayTCurrent関数によって 深度値がとれる!
  10. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 19 フォンシェーディング //

    カラー float4 color = マテリアルカラー; // フォンシェーディング color = フォンシェーディングの計算( color, attr.normal, false); // レイの長さ float t = RayTCurrent(); // フォグの適用 color = lerp(color,背景色, 1.0 - exp(-0.000002 * t * t * t)); // 出力 rayPayload.color = color; レイトレーシングのシェーダーでも ラスタライザーで使っていた 従来のテクニックが使える!
  11. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 22 レイトレースシャドウの原理 視点

    スクリーン スクリーンレイ シャドウレイ シャドウレイ スクリーンレイ スクリーンレイを飛ばした後、 さらに光源に向かってレイを飛ばす。 遮蔽されているかどうかを判定する
  12. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. シャドウレイ関数(TraceShadowRay) 23 レイトレースシャドウのアルゴリズム

    スクリーンレイを飛ばす オブジェクトと交差あり シーンの走査 RayGenerationシェーダー ClosestHitシェーダー 遮蔽情報を使ってシェー ディング シャドウのアルゴリズムは2ステップ
  13. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. シャドウレイ関数(TraceShadowRay) 24 レイトレースシャドウのアルゴリズム

    スクリーンレイを飛ばす オブジェクトと交差あり シーンの走査 RayGenerationシェーダー ClosestHitシェーダー 他のオブジェクト に交差した? shadowPayload を返す いいえ 遮蔽なし shadowPayload.hit = false Missシェーダー シャドウレイを飛ばす RayGenerationシェーダー はい 遮蔽あり shadowPayload.hit = true ClosestHit シェーダー 遮蔽情報を使ってシェー ディング シャドウのアルゴリズムは2ステップ
  14. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 25 レイトレースシャドウ︰メイン部分 //

    カラー float4 color = マテリアルカラー; // レイの交差位置 float3 hitPosition = HitWorldPosition(); // シャドウレイの作成 Ray shadowRay = { hitPosition, normalize(光源の位置 - hitPosition) }; // シャドウかどうかの算出 bool shadowRayHit = TraceShadowRay (shadowRay, rayPayload.recursionDepth); // フォンシェーディング color = フォンシェーディングの計算( color, attr.normal, shadowRayHit); // レイの長さ float t = RayTCurrent(); // フォグの適用 color = lerp(color,背景色, 1.0 - exp(-0.000002 * t * t * t)); // 出力 rayPayload.color = color; TraceShadowRay関数の結果を シェーディング計算に適用する
  15. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 26 レイトレースシャドウ︰シャドウかどうかの判定① //

    シャドウかどうかの判定 bool TraceShadowRay (in Ray ray, in UINT currentRayRecursionDepth) { // 再帰回数の上限を超えていたら、falseを返す if (currentRayRecursionDepth >= MAX_RAY_RECURSION_DEPTH) { return false; } // レイオブジェクトを作成 RayDesc rayDesc; rayDesc.Origin = ray.origin; // レイの原点 rayDesc.Direction = ray.direction; // レイの方向 rayDesc.TMin = 0; // レイの最小範囲 rayDesc.TMax = 10000; // レイの最大範囲 // ShadowRayPayloadの初期化 ShadowRayPayload shadowPayload = { true };
  16. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 27 レイトレースシャドウ︰シャドウかどうかの判定② //

    レイを飛ばす TraceRay( // シーン構造(AccelerationStructure) g_scene, // 各種フラグ設定 RAY_FLAG_CULL_BACK_FACING_TRIANGLES | RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_OPAQUE // Any hit shaderをスキップ | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, // Closest hit shaderをスキップ TraceRayParameters::InstanceMask, TraceRayParameters::HitGroup::Offset[RayType::Shadow], TraceRayParameters::HitGroup::GeometryStride, TraceRayParameters::MissShader::Offset[RayType::Shadow], // レイとshadowPayloadを渡す rayDesc, shadowPayload); // 交差済みかどうかを返す return shadowPayload.hit; }
  17. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 30 レイトレースリフレクションの原理 法線

    リフレクションマテリアル スクリーンレイ 視点 スクリーン リフレクションレイ スクリーンレイを飛ばした後、 さらに反射角方向にレイを飛ばす
  18. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. リフレクション関数 (TraceRadianceRay) 31

    レイトレースリフレクションのアルゴリズム スクリーンレイを飛ばす オブジェクトと交差あり シーンの走査 RayGenerationシェーダー ClosestHitシェーダー payload情報を使って シェーディング リフレクションのアルゴリズムも 2ステップ
  19. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. リフレクション関数 (TraceRadianceRay) 32

    レイトレースリフレクションのアルゴリズム スクリーンレイを飛ばす オブジェクトと交差あり シーンの走査 RayGenerationシェーダー ClosestHitシェーダー オブジェクトに交 差した? payload を返す いいえ 遮蔽されている payload.color = 背景色 Missシェーダー レイを飛ばす RayGenerationシェーダー はい payload.color = 描画色 ClosestHit シェーダー payload情報を使って シェーディング リフレクションのアルゴリズムも 2ステップ
  20. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 33 レイトレースリフレクション① //

    リフレクション float4 reflectedColor = float4(0, 0, 0, 0); // リフレクションレイの作成 Ray reflectionRay = { HitWorldPosition(), reflect(WorldRayDirection(), attr.normal) }; // リフレクションカラーの算出 float4 reflectionColor = TraceRadianceRay(reflectionRay, rayPayload.recursionDepth); // フレネル効果の適用 float3 fresnelR = FresnelReflectanceSchlick(WorldRayDirection(), attr.normal, color.xyz); // リフレクションカラーの計算 reflectedColor = 反射係数 * float4(fresnelR, 1) * reflectionColor;
  21. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 34 レイトレースリフレクション② //

    フォンシェーディング float4 phongColor = フォンシェーディングの計算( color, attr.normal, shadowRayHit); //フォンシェーディングの結果とリフレクションを合算 color = phongColor + reflectedColor; // レイの長さ float t = RayTCurrent(); // フォグの適用 color = lerp(color,背景色, 1.0 - exp(-0.000002 * t * t * t)); // 出力 rayPayload.color = color;
  22. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 41 アンビエントオクルージョンの原理 レイの衝突点から法線方向を起点にした

    半球面上に無数のシャドウレイを作る それらの結果の平均を遮蔽度合いとする
  23. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 50 アンビエントオクルージョンのシェーダー float

    evaluateAO(float3 position, float3 normal) { uint2 pixIdx = DispatchRaysIndex().xy; // レイインデックス x=0~1920, y=0~1080 uint2 numPix = DispatchRaysDimensions().xy; // ステージサイズ x=1920, y=1080 // ランダムなシードを計算 uint randSeed = initRand(pixIdx.x + pixIdx.y * numPix.x, 100); // 遮蔽度合い float visibility = 0.0f; // 飛ばすレイの回数 const int aoRayCount = 4; for (int i = 0; i < aoRayCount; ++i) { // 法線を中心とした半球上のランダムなベクトルのサンプリング(コサイン重み付き分布) float3 sampleDir = getCosHemisphereSample(randSeed, normal); // シャドウレイを飛ばす float sampleVisibility = shootShadowRay(position, sampleDir, RAY_EPSILON, 10.0, 1); //遮蔽度合い += サンプリングした値 × コサイン項 / 確率密度関数 float NoL = saturate(dot(normal, sampleDir)); float pdf = NoL / PI; visibility += sampleVisibility * NoL / pdf; } // 平均を取る return (1 / PI) * (1 / float(aoRayCount)) * visibility; } 複数レイを飛ばして 平均を取る 数式の詳しい解説はP. 59参照
  24. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 51 アンビエントオクルージョンのシェーダー float

    evaluateAO(float3 position, float3 normal) { uint2 pixIdx = DispatchRaysIndex().xy; // レイインデックス x=0~1920, y=0~1080 uint2 numPix = DispatchRaysDimensions().xy; // ステージサイズ x=1920, y=1080 // ランダムなシードを計算 uint randSeed = initRand(pixIdx.x + pixIdx.y * numPix.x, 100); // 遮蔽度合い float visibility = 0.0f; // 飛ばすレイの回数 const int aoRayCount = 4; for (int i = 0; i < aoRayCount; ++i) { // 法線を中心とした半球上のランダムなベクトルのサンプリング(一様分布) float3 sampleDir = getUniformHemisphereSample(randSeed, normal); // シャドウレイを飛ばす float sampleVisibility = shootShadowRay(position, sampleDir, RAY_EPSILON, 10.0, 1); //遮蔽度合い += サンプリングした値 × コサイン項 / 確率密度関数 float NoL = saturate(dot(normal, sampleDir)); float pdf = 1.0 / (2.0 * PI); visibility += sampleVisibility * NoL / pdf; } // 平均を取る return (1 / PI) * (1 / float(aoRayCount)) * visibility; } 複数レイを飛ばして 平均を取る 数式の詳しい解説はP. 59参照
  25. Copyright 2019 DELiGHTWORKS. 52 AAなし デノイズなし AAあり デノイズなし AAあり デノイズ1回

    AAあり デノイズ2回 AAあり デノイズ3回 AAあり デノイズ3回 サンプル2回 AAあり デノイズ3回 サンプル3回
  26. Copyright 2019 DELiGHTWORKS. 53 AAなし デノイズなし AAあり デノイズなし AAあり デノイズ1回

    AAあり デノイズ2回 AAあり デノイズ3回 AAあり デノイズ3回 サンプル2回 AAあり デノイズ3回 サンプル3回
  27. Copyright 2019 DELiGHTWORKS. 55 レイトレーシングパイプライン 1 フォンシェーディング 2 レイトレースシャドウ 3

    レイトレースリフレクション 4 レイトレース アンビエントオクリュージョン 5 まとめ
  28. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 読む 初のDXR本:Ray Tracing

    Gems Microsoft DirectX仕様:DirectX-Specs SIGGRAPH 2018 - Full Rays Ahead! From Raster to Real-Time Raytracing 教わる SIGGRAPHコース Introduction to DirectX RayTracing 手を動かす microsoft/DirectX-Graphics-Samples TheRealMJP/DXRPathTracer acmarrs/IntroToDXR 学習リソースの紹介 Ray Tracing Gems http://www.realtimerendering.com/raytracinggems/ Introduction to DirectX RayTracing http://intro-to-dxr.cwyman.org/
  29. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 60 点PにおけるAmbient Occlusionの関数を下記と定義すると、

    AO(P) = 1 ∫ cos d (1.1) AO(P) = 1 � 1 ∑=1 (ω ) cos / (1.2) 下記のように近似できる(※モテカルロサンプリングによる積分の近似) ∫ d :微小領域dωの半球面Ω上での積分 ︓Visibility項(可視項・遮蔽されているかどうか。0 or 1を返す) cos ︓コサイン項(法線とシャドウレイの内積) ︓確率密度関数(Probability Density Function) k:サンプリング数(ここではシャドウレイの数) 補足:アンビエントオクルージョンの計算式 http://www.realtimerendering.com/raytracinggems/ 𝐶𝐶𝐶𝐶𝐶𝐶𝐶𝐶 15 "𝑂𝑂 𝑡𝑡𝑡𝑡𝑡 𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼 𝑜𝑜𝑜𝑜 𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆“ . 209
  30. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 61 コサイン重み付き分布(※p.59)によりサンプリングした場合、pdfは =

    cosθ/ (1.3) AO(P) = 1 ∑=1 (ω ) (1.4) よって、(1.3)より(1.2)は(1.4)のようにも書ける 補足:アンビエントオクルージョンの計算式 AO(P) = 1 � 1 ∑=1 (ω ) cos / (1.2) http://www.realtimerendering.com/raytracinggems/ 𝐶𝐶𝐶𝐶𝐶𝐶𝐶𝐶 15 "𝑂𝑂 𝑡𝑡𝑡𝑡𝑡 𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼𝐼 𝑜𝑜𝑜𝑜 𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆𝑆“ . 209
  31. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 62 サンプリング方式: Cosine-weighted

    sampling float3 getCosHemisphereSample(uint randSeed, float3 hitNorm) { // 2つのランダムな数値を取得 float2 randVal = float2(nextRand(randSeed), nextRand(randSeed)); // 法線に垂直なベクトルを取る(最後に利用する) float3 bitangent = getPerpendicularVector(hitNorm); float3 tangent = cross(bitangent, hitNorm); // ディスク上に一様にサンプリング float r = sqrt(randVal.x); float phi = 2.0f * PI * randVal.y; // 半球に射影する float x = r * cos(phi); float z = r * sin(phi); float y = sqrt(1.0 - randVal.x); // 1- r2 // 法線ベクトルの座標系に射影 return x * tangent + y * hitNorm.xyz + z * bitangent; } r Φ x z 半径r、角度Φのディスク上に一様に分布 y 1 r 半球に射影
  32. Copyright 2019 DELiGHTWORKS Inc. All Rights Reserved. 63 サンプリング方式: Uniform

    sampling float3 getUniformHemisphereSample(uint randSeed, float3 hitNorm) { // 2つのランダムな数値を取得 float2 randVal = float2(nextRand(randSeed), nextRand(randSeed)); // 法線に垂直なベクトルを取る(最後に利用する) float3 bitangent = getPerpendicularVector(hitNorm); float3 tangent = cross(bitangent, hitNorm); // θ、Φを決める float cosTheta = randVal.x; float sinTheta = sqrt(1.0f - cosTheta * cosTheta); float phi = 2.0f * PI * randVal.y; // 半球に射影する float x = sinTheta * cos(phi); float z = sinTheta * sin(phi); float y = cosTheta; // 法線ベクトルの座標系に射影 return x * tangent + y * hitNorm.xyz + z * bitangent; } r, θ, Φを元に半球面上にランダムな関するを取得する Φ θ x z y x = r sinθ ・ cosΦ z = r sinθ ・ sinΦ y = cosθ r rsinθ