Unityによって予約されているTextureについて
概要
Unityにはいくつかの特別なテクスチャがあり、これらのテクスチャは特定の目的のために予約されている。
つまり、シェーダー内で同じ名前のテクスチャを独自に宣言して使用することは推奨されない。
とくにURPやHDRPのようなSRPでsahderを作成する際に気になるポイントかと思われる。
これらのテクスチャについて調べたので、おそらく他にもあるだろうがまとめておく。
URPのLit Shader
具体例として、URPのLit Shaderで用いられているpropertiesを抜粋する。
Properties { // Specular vs Metallic workflow _WorkflowMode("WorkflowMode", Float) = 1.0 _WaterHeight("WaterHeight", Float) = 0.55 _HeightScale("HeightScale", Float) = 1.0 [MainTexture] _BaseMap("Albedo", 2D) = "white" {} [MainColor] _BaseColor("Color", Color) = (1,1,1,1) _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0 _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 _MetallicGlossMap("Metallic", 2D) = "white" {} _SpecColor("Specular", Color) = (0.2, 0.2, 0.2) _SpecGlossMap("Specular", 2D) = "white" {} [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0 _BumpScale("Scale", Float) = 1.0 _BumpMap("Normal Map", 2D) = "bump" {} _Parallax("Scale", Range(0.005, 0.08)) = 0.005 _ParallaxMap("Height Map", 2D) = "black" {} _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0 _OcclusionMap("Occlusion", 2D) = "white" {} [HDR] _EmissionColor("Color", Color) = (0,0,0) _EmissionMap("Emission", 2D) = "white" {} _DetailMask("Detail Mask", 2D) = "white" {} _DetailAlbedoMapScale("Scale", Range(0.0, 2.0)) = 1.0 _DetailAlbedoMap("Detail Albedo x2", 2D) = "linearGrey" {} _DetailNormalMapScale("Scale", Range(0.0, 2.0)) = 1.0 [Normal] _DetailNormalMap("Normal Map", 2D) = "bump" {} // SRP batching compatibility for Clear Coat (Not used in Lit) [HideInInspector] _ClearCoatMask("_ClearCoatMask", Float) = 0.0 [HideInInspector] _ClearCoatSmoothness("_ClearCoatSmoothness", Float) = 0.0 // Blending state _Surface("__surface", Float) = 0.0 _Blend("__blend", Float) = 0.0 _Cull("__cull", Float) = 2.0 [ToggleUI] _AlphaClip("__clip", Float) = 0.0 [HideInInspector] _SrcBlend("__src", Float) = 1.0 [HideInInspector] _DstBlend("__dst", Float) = 0.0 [HideInInspector] _ZWrite("__zw", Float) = 1.0 [ToggleUI] _ReceiveShadows("Receive Shadows", Float) = 1.0 // Editmode props _QueueOffset("Queue offset", Float) = 0.0 // ObsoleteProperties [HideInInspector] _MainTex("BaseMap", 2D) = "white" {} [HideInInspector] _Color("Base Color", Color) = (1, 1, 1, 1) [HideInInspector] _GlossMapScale("Smoothness", Float) = 0.0 [HideInInspector] _Glossiness("Smoothness", Float) = 0.0 [HideInInspector] _GlossyReflections("EnvironmentReflections", Float) = 0.0 [HideInInspector][NoScaleOffset]unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {} [HideInInspector][NoScaleOffset]unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {} [HideInInspector][NoScaleOffset]unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {} }
プロパティのオプションについて
プロパティの前に[]を指定して、オプションをつけることができる。
オプションについての公式マニュアルは以下。
ShaderLab: Properties - Unity マニュアル
例えば[MainTexture]があるが、これを指定すると、通常Unityは_MainTexがメインテクスチャであるとして内部で処理しているが、[MainTexture]が指定されたテクスチャをMainTextureであるとしてshaderの処理を実行する。
LitShaderでは_BaseMapがメインテクスチャとして扱われている。
予約されているTexture変数
_MainTex
上にも少し書いたとおりであるが、マテリアルにつけられるメインのテクスチャのことを指している。
[MainTexture]がオプションで付けられていない限り、デフォルトでUnityは_MainTexがメインテクスチャであるとして処理する。
_CameraOpaqueTexture
不透明なオブジェクトのレンダリング結果を格納するために使用される。
FrameDebugを見ると描画している処理順が見れるが、DrawOpaqueObjectsの処理が終わった後に、RendererのOpaqueで指定されているObjectsの描画結果がこのテクスチャに格納される。
Transparentsの処理でblendなどしたい場合、利用できる。
_CameraDepthTexture
カメラの深度情報を表すテクスチャで、デプステストやシャドウマップの生成など、深度に関連する処理を行う際に利用できる。
予約されているわけではないが、一般的に使用されているTexture変数
_BumpMap
Normal Mapとして一般的に使用されている名前。
カスタムする傾向にないビルトインパイプラインでは、この名前をそのまま使用した方がよいかも。
_SpecularMap
Specular Mapとして一般的に使用されている名前。
物体の反射ハイライトの制御に使用される。
ChatGPT先生に聞いてみると
要約すると、Unityのビルトインシェーダーでは_SpecularMapという変数名が一般的に使用されますが、カスタムシェーダーを作成する場合は自由に変数名を選択できます。ただし、シェーダーマテリアルのテクスチャスロットに関連付ける際には、スロットの名前を _SpecularMap として指定する必要があります。
とのことだが、スロットの名前というのが不明。
Unity内部で予約されているわけでなないので、Specular Mapという名前でなくてもよいはず。
開発者以外が使用することを想定して、inspectorに出てくる名前の部分を"Specular Map"にしなさい、ということかもしれない。
_EmissionMap
物体の発光や自己発光を制御するために使用されるが、上記同様_EmissonMapという名前が推奨されるが、この名前でなくともよい。
Shaderの基本についての調査
概要
Unity初心者の私がShaderの構造や関数のエントリーポイントについて調査したのでまとめる。
Shader
ShaderLabやHLSLの用語説明などは、ページによくまとまっているので、以降は個人的に気になったC# ScriptからShaderへのデータの渡し方や関数のエントリーポイント、Passについて知っておくべき知識などをまとめる。
Unity のシェーダの基礎を勉強してみたのでやる気出してまとめてみた - 凹みTips
Unity ShaderLab ノート - Qiita
構造
Shader クラス - Unity マニュアルには以下のように記述がある。
シェーダーオブジェクト
シェーダーオブジェクトには以下が含まれています。名前など、それ自体の情報
フォールバックシェーダーオブジェクト。Unity がこのシェーダーオブジェクトを使用できない場合に、フォールバックシェーダーオブジェクトが使用されます。
1 つまたは複数のサブシェーダー
また、共有シェーダーコードや、カスタムエディター を使用するかどうかなどの追加情報を定義することもできます。シェーダーオブジェクトの定義については、ShaderLab: シェーダーオブジェクトの定義 を参照してください。SubShader
SubShader (サブシェーダー) は、シェーダーオブジェクトを、異なるハードウェア、レンダーパイプライン、ランタイム設定に対応する部分に分離することができます。SubShader には以下が含まれています。
このサブシェーダーが対応できるハードウェア、レンダーパイプライン、ランタイム設定についての情報。
サブシェーダー タグ (サブシェーダーに関する情報を提供するキーと値のペア)。
1 つまたは複数のパス
また、すべてのパスに共通するレンダー状態などの追加情報を定義することもできます。サブシェーダーで定義できるすべての内容については、ShaderLab: サブシェーダーの定義 を参照してください。Pass
Pass (パス) には以下が含まれています。Pass タグ (パスに関する情報を提供するキーと値のペア)。
シェーダープログラムを実行する前にレンダー状態を更新するための指示
1 つまたは複数のシェーダバリアントにまとめられたシェーダープログラム
また、名前などの追加情報を定義することもできます。パスで定義できるすべての内容については、ShaderLab: パスの定義 を参照してください。
SubShader
公式ドキュメント
ShaderLab: SubShader の定義 - Unity マニュアル
Shaderを、ハードウェアごとやパイプラインごとに分けて記述するときに、SubShaderにわけて記述できる。
つまりTagやPass, そのほかBlendなどの情報をSubShaderごとに分けて書く。
実際のUniversal Render Pipeline/Litを見ると、Tag情報の中でShaderModelを4.5と2.0でわけてSubShaderで記述しているようだった。
Tagについて
分けて記載するSubShaderの目的や特性をつける。
記述例
SubShader{ Tag {"RenderPipeline" = "UniversalRenderPipeline" "RenderType" = "Opaque" } }
調べてみたところ、以下のような設定値があるらしい。
ShaderLab: タグを SubShader に割り当てる - Unity マニュアル
Tag | 値 |
---|---|
RenderPipeline | UniversalRenderPipeline |
HighDefinitionRenderPipeline | |
Queue | Background |
Geometry | |
AlphaTest | |
Transparent | |
Overlay | |
RenderType | Opaque |
Transparent | |
TransparentCutout | |
Background | |
Overlay | |
TreeOpaque | |
TreeTransparentCutout | |
TreeBillboard | |
Grass | |
GrassBillboard | |
ForceNoShadowCasting | True |
False | DisableBatching | True |
False | |
LODFading | IgnoreProjector | True |
False | PreviewType | Sphere |
Plane | |
Skybox | CanUseSpriteAtlas | True |
False |
Pass
Passとはグラフィックスのシェーダープログラム内で特定の描画処理を定義するためのセクションまたはブロックのこと。
Universal Render Pipeline/Litを見てみると、物体の描画や影の描画ごとにPassが作成されていた。
各Passにvertex関数とfragment関数があるので、どのPassも条件があえば実行される。
SubShader{ Tags{"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "Lit" "IgnoreProjector" = "True" "ShaderModel"="4.5"} Pass{ Name "ForwardLit" Tags{"LightMode" = "UniversalForward"} HLSLPROGRAM #pragma vertex LitPassVertex #pragma fragment LitPassFragment *** ENDHLSL } Pass{ Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} HLSLPROGRAM #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment *** ENDHLSL } Pass{ Name "GBuffer" Tags{"LightMode" = "UniversalGBuffer"} *** } Pass{ Name "DepthOnly" Tags{"LightMode" = "DepthOnly"} *** } Pass{ Name "DepthNormals" Tags{"LightMode" = "DepthNormals"} *** } Pass{ Name "Meta" //for lightmap baking Tags{"LightMode" = "Meta"} *** } Pass{ Name "Universal2D" Tags{ "LightMode" = "Universal2D" } *** } }
またHLSLでは、vertex shaderとfragment shaderのメイン関数のエントリーポイントはそれぞれ
#pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment
のようにして指定する。
メイン関数のエントリーポイントを間違えると、たとえばFowardLit Passだと
did not find shader kernel LitPassVertex to comile
が表示されてコンパイルに失敗する。
#pragmaディレクティブは下記に一覧が表示されている。
HLSL のプラグマディレクティブ - Unity マニュアル
その他のshaderの文法については以下に詳細が記載されている。
例えば、fragment shaderで色を出力する関数にはSV_Targetの指定が必要。
シェーダーセマンティクス - Unity マニュアル
URPの概要についての調査
概要
Unity初心者の私がグラフィクスパイプラインの処理について調査したので、まとめたい。
モバイル端末での表示が関心事なので、ビルトインパイプラインとURP(Universal Render Pipeline)について調べてみた。
Unityでのグラフィクスパイプライン
まずは公式でどのように書かれているか、ということでグラフィクスパイプラインについてUnityの公式マニュアルをみると
レンダーパイプラインは、シーンのコンテンツを取得し、それを画面に表示する一連の操作を行います。簡単に説明すると、以下のような操作です。
- カリング
- レンダリング
- ポストプロセッシング
使用するレンダリングパイプラインの選択
Unity は以下のレンダリングパイプラインを提供します。ビルトインレンダーパイプラインは Unity のデフォルトの レンダリングパイプラインです。これは汎用レンダリングパイプラインで、カスタマイズのオプションが限られています。
ユニバーサルレンダーパイプライン (URP) はスクリプタブルレンダーパイプラインの 1 つです。素早く簡単にカスタマイズでき、幅広いプラットフォームで最適化されたグラフィックスを作成できます。
HD レンダーパイプライン (HDRP) はスクリプタブルレンダーパイプラインの 1 つです。ハイエンドプラットフォームで最先端の忠実度の高いグラフィックスを作成できます。
Unity のスクリプタブルレンダーパイプライン API を使って、独自の カスタムレンダーパイプライン を作成することができます。
https://docs.unity3d.com/ja/2021.3/Manual/render-pipelines-overview.html
用語説明
カリング:シーンの内、描画するオブジェクトを選別すること
レンダリング:ピクセル当たりの色を決めること
ポストプロセッシング:レンダリングする画像を作成した後に、その画像を加工すること
ということで、構造的には
- ビルトインパイプライン
- SRP (スクリプタブルレンダーパイプライン)
- URP (ユニバーサルレンダーパイプライン) (ローエンド向け)
- HDRP (HDレンダーパイプライン) (ハイエンド向け)
という区分になっている。
SRP (URP)でRenderPassの追加について
色々調べてみたが、この記事が一番わかりやすかったので引用する。
https://shibuya24.info/entry/unity-urp-add-pass
基本的なclassの簡単な相関図は以下のようになっている模様。
スクリプトリファレンスに各クラスの簡単な説明があるので抜粋する。
Class | 説明 | リンク |
---|---|---|
ScriptableRenderer | rendering戦略を決めるもので、どのようにcullingが実行されるかやlightingがされるかを決めるもの | Class ScriptableRenderer | Universal RP | 7.1.8 |
ScriptableRenderPass | URP rendererで使用されるrendering passを定義するもの | Class ScriptableRenderPass | Universal RP | 7.1.8 |
ScriptableRendererFeature | RenderPassをRendererに追加するもの | Class ScriptableRendererFeature | Universal RP | 7.1.8 |
RenderPipeline | Unityがframeを描画する一連のコマンドや設定を定義するもの | Rendering.RenderPipeline - Unity スクリプトリファレンス |
ScriptableRenderContext | custom render pipelineが用いるコマンドや状態を定義するもの | Rendering.ScriptableRenderContext - Unity スクリプトリファレンス |
Frame Debugとドローコールについて
Unityの機能のFrame Debugを使うと、ドローコールの順が見える。
どの順で何の命令が実行されているかが見えるので、処理の理解と最適化に役立つと思う。
https://docs.unity3d.com/ja/current/Manual/FrameDebugger.html
Frame Debugをみると、実行されているRendererが確認できる。
参考リンク集
SRPについての公式マニュアル:https://docs.unity3d.com/ja/2021.2/Manual/srp-using-scriptable-render-context.html
SRPについてのUnity公式ブログ:https://blog.unity.com/ja/technology/srp-overview
スクリプトリファレンス:Rendering.ScriptableRenderContext - Unity スクリプトリファレンス
Rendering.RenderPipeline - Unity スクリプトリファレンス
SRP Core | Core RP Library | 10.7.0
終わりに
これからもUnityのグラフィクスについての調査をして、まとめていきたい。
各Classについても詳細に調べたり、Shaderとの関係や処理についても調べてまとめたい。
オブジェクトが途中から描画されない場合
概要
オブジェクトが途中から描画されない場合があった。
原因
Top Level ASの更新漏れ
詳細
Khronos Blog - The Khronos Group Inc
に
the triangles or axis-aligned bounding boxes (AABBs)
とある通り、ray tracingのオブジェクトの範囲はboxで指定されている。
The upper level, the top-level acceleration structure, contains references to a set of bottom-level acceleration structures, each reference including shading and transform information for that reference.
とあり、TLASはBLASの参照をもっているので、BLAS全体を統合し、描画するAABBを決めるものと思われる。
なので、TLASを更新しなければ、最初のAABBの範囲内しか描画されず、上動画のような挙動になってしまう。
引用:
https://www.khronos.org/blog/ray-tracing-in-vulkan
上記絵の物体は、AABBも更新されることを表しているものと思われる。
3Dオブジェクトをタッチしているかの判定方法
結論
カメラーオブジェクトのベクトルとカメラータッチ位置をワールド座標に変換したベクトルの内積を計算し、1に近ければタッチしていると判定
補足
点と平面の距離を計算して、その距離が0に近ければ、なども考えたが、内積を考えるのが速そう。
Unityであれば、Rayを飛ばすという方法があるらしい。
クリック(スマホではタップ)したゲームオブジェクトを判定する方法 | ソフトライム
3D空間でタッチした位置というのは、1点に定まらないので、カメラータッチ位置の直線上にオブジェクトがあるかどうかを判断するしかないと思う。
レイトレーシングの構造体(AS)を準備しているのであれば、判定するだけのパイプラインを作成してもよいかもしれない。
オブジェクトが重なったときに前面のものだけタッチしているかどうかを判定したければ、空間上のオブジェクトをすべて認識している必要があるので、
レイトレーシングのアーキテクチャーを使用するのがよさそうか。
glTFモーフィング描画(アルファテストあり)
glTFモーフィング(アルファテストあり)
アルファテストを用いて透明 or notを判定することにより、必要な部分だけを取り出してモーフィングアニメーションすることができた。
モデルの権利表記
https://sketchfab.com/3d-models/yard-grass-3a67e76decc849c694c228eb590a9902
ライセンス:CC Atribution
https://creativecommons.org/licenses/by/4.0/legalcode
レイトレーシングでのアルファテスト
Googleで調べてみると色々な人が書いているが、レイトレーシングでのアルファテストはanyhit shaderを用いることで達成できる。
anyhit shader内でアルファテストを行い、もし透明な部分にヒットしている場合には
ignoreIntersectionEXT
を用いて交差判定を無視する。
これを用いると、その判定は無視してrayは直進し直し、次の判定に進む。
注意点としては
Khronos Blog - The Khronos Group Inc
にある通り、ではなくを用いる。
instead of appearing as ignoreIntersectionEXT(); it is now simply ignoreIntersectionEXT; when used in a shader.
その他、any hit shaderの実装方法についてはnvidia様が作成しているvulkan raytracing tutorialが参考になる。
github.com