〇カリングとは?
カリング(Culling)とは摘み取るという意味の言葉になります。
Shaderは3Dモデルのメッシュに対して描画を行っていますが、メッシュは裏と表の情報を持つことができます。
Blenderなどのモデリングツールではメッシュの向きを確認することができます。
シェーダーでは描画を行う際に片面を描画せずに描画コストを下げることができます。
これは例えばボールのように見える面がすべて表面で構成されており、決して裏面が見えることがないといった場合などに裏面を描画することは無駄な計算が走ることに等しいためこういった場合裏面を描画せずに描画コストを下げます。
このように描画される面のどちらかを摘み取る機能がカリングです。
また、上記のように決して裏面が見えることがないといった3Dモデルのことを『閉じたメッシュ』と呼ぶこともあります。
〇カリングの実装
カリングはShaderLab側に提供されている機能です。
カリングを定義していない状態でも通常裏面がカリングされ、表面のみが描画されるような仕組みとなっています。
カリングを使用するためにはSubShaderないにCull ○○という形で記述します。
Shader "Unlit/NewUnlitShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Cull Back//追加 Pass//Shaderのパス { HLSLPROGRAM ・・・ ENDHLSL } } }
Cull ○○の形でモードを指定します。
指定できるモードは次のように提供されています。
モード | 説明 | 結果 |
---|---|---|
Back | 裏面がカリングされます。(Default) | 表面のみが描画されます。 |
Front | 表面がカリングされます。 | 裏面のみが描画されます。 |
Off | カリングを無効化します。 | 両面が描画されます。 |
またPropertiesブロックで次のように定義することでマテリアルごとに設定を変えることができます。
Properties { _MainTex ("Texture", 2D) = "white" {} [Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull Mode", Float) = 2 }
UnityEngine.Rendering.CullModeはUnityから提供されているC#スクリプトで、Enum型でBack、Front、Offが定義されています。
SubShader側で[_CullMode]の形で定義することでマテリアル側で指定したモードをシェーダーと紐づけることができます。
SubShader { Tags { "RenderType"="Opaque" } LOD 100 Cull [_CullMode] ・・・ }
このようにシェーダーを記述する際はマテリアル側でCullModeを変更できるように作成すると非常に汎用性が高いシェーダーを作れます。
〇シェーダーコード全文
今回は前回のワールド座標の取得シェーダーを使用しています。
Shader "Unlit/NewUnlitShader" { Properties { _MainTex ("Texture", 2D) = "white" {} [Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull Mode", Float) = 2 } SubShader { Tags { "RenderType"="Opaque" }//Shader属性 LOD 100 Cull [_CullMode] Pass//Shaderのパス { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float3 worldPos : TEXCOORD3; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = TransformObjectToHClip(v.vertex); o.worldPos = TransformObjectToWorld( v.vertex.xyz); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } float4 frag (v2f i) : SV_Target { // sample the texture float4 col = tex2D(_MainTex, i.uv); col *= ( i.worldPos.y <0 )? 0:1; return col; } ENDHLSL } } }