$30 off During Our Annual Pro Sale. View Details »

Object Space Raymarching in Unreal Engine 5.2

がむ
September 01, 2023

Object Space Raymarching in Unreal Engine 5.2

がむ

September 01, 2023
Tweet

More Decks by がむ

Other Decks in Programming

Transcript

  1. Object Space Raymarching
    in Unreal Engine 5.2

    2023-09-01 レイトレ合宿9セミナー
    @gam0022 / Sho HOSODA

    View Slide

  2. 自己紹介

    @gam0022(がむ)/ Sho HOSODA

    グラフィックスエンジニア/Unityでモバイルゲームを開発

    『Unityバイブル R5夏号』 を執筆

    ● ボーンデジタルの

    Unityバイブルシリーズの最新号 

    ● 年2回の定期刊行の第1号 

    ● ShaderGraphの章を担当

    ● 2023-08-29発売

    2

    View Slide

  3. 自己紹介

    @gam0022(がむ)/ Sho HOSODA

    グラフィックスエンジニア/Unityでモバイルゲームを開発

    ● CGWORLDにデモシーンの記事を寄稿

    ○ 「メガデモ」とも呼ばれる

    ○ これが64KB?! デモシーンを支える
    プロシージャル技術 

    ○ https://cgworld.jp/feature/202101-de
    moscene.html

    3

    View Slide

  4. 自己紹介

    @gam0022(がむ)/ Sho HOSODA

    グラフィックスエンジニア/Unityでモバイルゲームを開発

    ● Aphex TwinのARアプリの開発に協力 

    ● アルバムのジャケットがARマーカー 

    ● レイマーチングでメンガースポンジを描画 

    4

    View Slide

  5. 自己紹介

    @gam0022(がむ)/ Sho HOSODA

    グラフィックスエンジニア/Unityでモバイルゲームを開発

    WORMHOLE by @gam0022 & @sadakkey

    1st place in Combined Demo Compo at Tokyo Demo Fest 2018

    Made with Unity

    RE: SIMULATED by @gam0022 & @sadakkey

    1st place in PC 64K Intro at Revision 2020

    Original WebGL Framework

    Unityゲーム プログラミング・バイブル 2nd Generation

    2021年 ボーンデジタル出版

    著者のひとりとして参加

    商業誌でレイマーチングを解説する実績を解禁
    🏆

    5

    View Slide

  6. 概要

    • Unreal Engine(UE)5.2上でオブジェクトスペースのレイマーチングを実装した

    • MaterialのCustomノードを用いて複雑な処理はHLSLのコードで実装した

    6

    View Slide

  7. 結果:パラメーターによる滑らかな変形

    MengerSpongeと呼ばれる有名なフラクタルを距離関数によってモデリング

    距離関数のパラメーターを変化させることで滑らかに形状を変形できる

    7

    View Slide

  8. 結果:UEのレンダリング結果との統合

    ● 他のオブジェクトと相互にライティングの影響を受けている(GI)

    ● 床に反射し、ライティング結果が周囲に馴染んでいる

    8

    View Slide

  9. 結果:リアルタイム動作

    RTX A4000 LaptopやRTX3080でリアルタイムに動作

    カメラや画面解像度に依存するが、30FPS~60FPSの範囲内で安定して動作

    9

    View Slide

  10. 作った理由

    Unreal Engineを勉強するため📝

    10

    View Slide

  11. レイマーチングとは?

    • レイマーチングとは

    ‣ 距離関数で表現された形状に対する交差判定の手法


    • 距離関数とは

    ‣ 任意の座標pから物体表面への最短距離を返す関数

    float sdSphere(vec3 p, float r)
    {
    return length(p) - r;
    }
    11

    View Slide

  12. レイマーチングとは?

    float sdBox(vec3 p, vec3 b)
    {
    vec3 q = abs(p) - b;
    return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
    }
    https://iquilezles.org/articles/distfunctions/
    12

    View Slide

  13. レイマーチングとは?

    • レイマーチングを可視化したアニメーション by @kanetaaaaa 

    ‣ Raymarching in Raymarching

    ‣ https://twitter.com/kanetaaaaa/status/1141307706139004934

    ‣ https://qiita.com/kaneta1992/items/21149c78159bd27e0860

    13

    View Slide

  14. レイマーチングとは?

    • レイマーチングのアルゴリズム

    ‣ 距離関数だけレイを進めるのを繰り返す(マーチング・ループ)

    • 距離関数dが0に近似できたら衝突したと判定

    ‣ abs(d) < eps

    ‣ epsは0.001 など適切に設定

    • ループ回数がNを超えたら衝突していないと判定

    ‣ Nは100〜300くらいが一般的

    極めてシンプル

    14

    View Slide

  15. レイマーチングの別名:SphereTracing

    • レイを少しずつ進めるような手法全般がレイマーチングなので意味が広い

    ‣ 例:ボリュームレンダリングのアルゴリズムもレイマーチング


    • 今説明した、最短距離ずつレイを進める手法は区別のために

    SphereTracingと呼ぶこともある

    ‣ 特にアカデミックではこの呼び方

    15

    View Slide

  16. 「オブジェクトスペース」のレイマーチングとは?

    ● CubeのStaticMeshにレイマーチングのシェーダーを適用することで、Cubeを彫刻のように削り出してフラクタルの形状にできる

    ● Cubeはレイマーチングのオブジェクトのバウンディングボックスのように扱う(オブジェクトスペースのレイマーチング)

    ● レイマーチングはGPU負荷が高いアルゴリズムだが、バウンディングボックスによって負荷軽減できる

    通常シェーダーを適用した Cube レイマーチング対応シェーダーを適用した Cube
    16

    View Slide

  17. 結果:オブジェクトスペースのレイマーチング

    Actorのトランスフォームに追従
    オブジェクトスペースでレイマーチングを計算することで実現

    translation rotation
    17

    View Slide

  18. 結果:オブジェクトスペースのレイマーチング

    Actorのトランスフォームに追従
    オブジェクトスペースでレイマーチングを計算することで実現

    scale
    18

    View Slide

  19. 実装の流れ

    1. UE上のHLSL(.ush)シェーダー開発環境の構築 

    a. C++の開発環境のセットアップ 

    b. AddShaderSourceDirectoryMappingでシェーダーを配置するディレクトリを登録 


    2. UE上のレイマーチングの実装 

    a. HLSL(.ush)でレイマーチングを実装 

    b. MaterialのCustomノードの Include File Paths に .ush を追加、 

    レイマーチングの関数を呼び出す 

    c. Customノードの計算結果をResultノードに出力、ライティング計算はエンジン側に任せる 

    19

    View Slide

  20. HLSL(.ush)によるシェーダー開発環境の構築

    ● まずはC++の開発環境を整える必要がある 

    ● Visual Studio 2022のセットアップ|Unreal Engine 5から始める C++ & Blueprint 

    ● 上記の記事を参考にVisual Studio 2022と必要なコンポーネントをインストール 



    20

    View Slide

  21. HLSL(.ush)によるシェーダー開発環境の構築

    ● C++の開発環境をセットアップしたら、AddShaderSourceDirectoryMappingを呼び出してシェーダーを配置するディレクトリをエ
    ンジン側に登録する


    ● 下記の記事の「普通の方法」を参考にC++のコード実装

    ● UE4,5 プロジェクトファイル内の外部シェーダーファイル(usf, ush, hlsl)をインクルードする為の設定。 - Qiita 

    ● C++プロジェクト化

    ● プロジェクト名.Build.csにRenderCoreへの依存関係を追加

    ● プロジェクトにモジュール開始,終了ファンクションを追加

    ● モジュール開始のStartupModule()に下記のコードを追加


    void FMyProjectModule::StartupModule()
    {
    UE_LOG(LogTemp, Warning, TEXT("Module Started"));
    FString ShaderDir = FPaths::Combine(FPaths::ProjectDir(), "Shaders");
    AddShaderSourceDirectoryMapping("/Project", ShaderDir);
    }
    21

    View Slide

  22. HLSL(.ush)によるシェーダー開発環境の構築

    ● ディレクトリ構成

    ● プロジェクト直下にShadersディレクトリを作成

    ● .ushのファイル名例

    ● D:\UnrealProjects\プロジェクト名\Shaders\Raymarching.ush


    ● Customノードからの参照方法

    ● Include File Pathsでは以下のように指定

    ● /Project/Raymarching.ush


    22

    View Slide

  23. 余談:Include File Pathsが無かった時代の関数定義の手法

    2015年の記事によると、当時はCustomノードのInclude File Pathsが無かった

    SQLインジェクションのような感じで、HLSLのコードが展開される仕様をハックして関数定義


    ● https://twitter.com/TakuroKX/status/670292440369094656

    ● Customノード3分ハッキング

    ● UE4のCustomノード(カスタムHLSLシェーダ)を使ってみた - ぼっちプログラマのメモ




    23

    View Slide

  24. レイマーチングの
    Customノード
    Emissiveのパターン計算
    前後関係の解消のための
    Pixel Depth Offsetの計算
    カメラのレイの生成
    定数パラメーター
    World Position
    定数パラ
    メーター
    Material全体

    View Slide

  25. Material Editor全体

    • レイマーチングの処理はHLSLで実装

    ‣ ノードで実装するには複雑すぎる


    • ノード部分の実装内容は限定的

    ‣ カメラのレイの生成

    ‣ Emissiveのパターン計算

    ‣ 前後関係の解消のためのPixel Depth Offsetの計算

    25

    View Slide

  26. 実装解説:レイマーチング基本

    Raymarching.ush では以下のインターフェースで関数定義 

    ノードの Additional Outpus に対応する値は inout を指定


    void raymarching(
    float3 origin, float3 ray, int raymarchingLoop,
    float uniformScale, float3 mengerOffst, float mengerScale,
    inout float hit, inout float depth, inout float3 hitPosition,
    inout float3 albedo, inout float3 normal, inout float ao, inout float emissive
    )
    コード全体は長いので省略
    26

    View Slide

  27. 実装解説:レイマーチング基本

    CustomノードのCodeでは、raymarhcingの関数を呼び出すだけ 


    albedo = objectAlbedo;
    raymarching(
    origin, ray, raymarchingLoop,
    uniformScale, mengerOffst, mengerScale,
    hit, depth, hitPosition,
    albedo, normal, ao, emissive
    );
    return albedo;
    27

    View Slide

  28. 実装解説:レイマーチング基本

    Include File Pathsに “/Project/Raymarching.ush” を指定

    28

    View Slide

  29. 実装解説:レイマーチング基本

    Raymarching.ush では以下のインターフェースで関数定義 

    ノードの Additional Outpus に対応する値は inout を指定


    void raymarching(
    float3 origin, float3 ray, int raymarchingLoop,
    float uniformScale, float3 mengerOffst, float mengerScale,
    inout float hit, inout float depth, inout float3 hitPosition,
    inout float3 albedo, inout float3 normal, inout float ao, inout float emissive
    )
    コード全体は長いので省略
    29

    View Slide

  30. 実装解説:レイマーチング基本

    raymarching関数のインターフェースと一致させて、Inputs/Additional Outpusを定義 


    Inputs Additional Outpus
    30

    View Slide

  31. 実装解説:レイマーチング基本

    ● Material Domain: Surface

    ○ レイマーチングはボリュームレダリングの印象があるかもしれないが、SurfaceでOK

    ● Blend Mode: Masked

    ○ レイマーチングの衝突判定によって形状をマスクする必要がある

    ○ このオプションを有効にすることで、Opacity Maskを出力できる

    ■ 交差している場合は1、交差していない場合は0を出力

    ■ 要するにdiscard

    ● Shading Model: Default Lit

    ○ ライティング計算はエンジン側に任せる

    ● Two Sideded: ON

    ○ カメラがレイマーチングの内部に

    入った場合に両面描画が必要

    31

    View Slide

  32. レイの原点(origin)
    レイの方向(ray)
    Materialノード解説:カメラのレイの生成

    32

    View Slide

  33. Materialノード解説:カメラのレイの生成

    • ray(レイの方向)は簡単 

    ‣ ray = normalize(Surfaceの座標 - カメラの位置)

    ‣ ※Surfaceの座標 = 描画しようとしているピクセルのワールド座標 

    33
    カメラの位置
    Surfaceの座標
    差分 正規化
    レイの方向(ray)の生成

    View Slide

  34. Materialノード解説:カメラのレイの生成

    • origin(レイの原点)はDynamicBranch(動的分岐) がある

    34
    カメラの位置
    Surfaceの座標
    レイの原点(origin)の生成
    動的分岐

    View Slide

  35. カメラがレイマーチング空間に潜った場合の考慮

    カメラがレイマーチング内部に潜った場合を考慮して分岐している 

    35

    View Slide

  36. カメラがレイマーチング空間に潜った場合の考慮

    カメラがレイマーチング空間の内部にあるかどうかの判定する必要がある 

    ● 専用のCustomノードを作成 

    ● isInsideCube(localPos) を呼び出し 

    36

    View Slide

  37. カメラがレイマーチング空間に潜った場合の考慮

    ● Two SidedをONにする 

    ‣ カメラがレイマーチング空間の内部にある場合、 

    Cubeの裏側のポリゴンのシェーダーでレイマーチングを描画する必要があるため 

    37

    View Slide

  38. カメラがレイマーチング空間に潜った場合の考慮

    ● レイの原点はカメラの位置によって分岐 

    ● カメラがCube外部 → Cubeの表面

    ● カメラがCube内部 → カメラ座標


    内外判定のCustomノード
    Cubeの表面 カメラ座標
    動的分岐
    38

    View Slide

  39. 他のオブジェクトの前後関係の解消

    他のオブジェクト(白い球体)と重なっても前後関係を正しく解消

    39

    View Slide

  40. 他のオブジェクトの前後関係の解消

    • Pixel Depth Offset

    ‣ 本来のCubeの座標とレイマーチングの交差点の差分から計算 

    ‣ レイマーチングの交差点はワールド空間に戻してから計算 

    40

    View Slide

  41. 他のオブジェクトの前後関係の解消

    • Pixel Depth Offset

    ‣ プラス方向(画面奥方向)にしかDepthをオフセットできない 

    ‣ DepthBufferを直接書き換えることはできない仕様だと思う 

    41

    View Slide

  42. まとめ

    • UE5上でもレイマーチングを実装できた

    ‣ ノードでは大変なので、HLSLを定義してCustomノードで呼び出し


    • UE5のレンダリングシステムに統合できた

    ‣ 影やGIも問題ない

    ‣ 他のオブジェクトとの前後関係の解決

    42

    View Slide

  43. もっと詳しい情報

    • GitHub

    ‣ UnrealEngineのプロジェクト

    ‣ https://github.com/gam0022/RaymarchingInUE5


    • 解説記事

    ‣ Object Space Raymarching in Unreal Engine 5.2 | gam0022.net

    ‣ https://gam0022.net/blog/2023/07/31/raymarching-in-ue5/

    43

    View Slide

  44. Object Space Raymarching
    in Unreal Engine 5.2

    2023-08-31 リアルタイムCG道場オフライン交流会
    @gam0022 / Sho HOSODA

    View Slide