Unity Custom Shader 記述におけるライティングの基礎 (URP 環境)
Unity シェーダーでライティングを記述する際の要点について覚え書き.
今回はテクスチャを使わず頂点ごとに色が設定されている場合に対するライティングの設定を行う
なお, レンダーパイプラインについては URP 環境で開発を行う.
検証環境
- Windows 11 Home
- Unity 6000.0.50f1
- Universal Render Pipline
最低限のテンプレート
- URP の書き方についての過去の記事 より, 以下を最小限のテンプレートとして使用する
Shader "LightingURP/LambertLighting" { Properties { } SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" } Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { // vertices position of object space float4 positionOS : POSITION; }; struct Varyings { // vertices position of screen space float4 positionHCS : SV_POSITION; }; // vertex shader Varyings vert(Attributes IN) { // output object Varyings OUT; // position change with noise float3 outPos = IN.positionOS.xyz; // to clip space OUT.positionHCS = TransformObjectToHClip(outPos); return OUT; } // fragment shader half4 frag() : SV_Target { // return color half4 customColor = half4(0.5, 0, 0, 1); return customColor; } ENDHLSL } } }
- 今回はライティングを用いるため先頭の Shader の指定を
Shader "LightingURP/LambertLighting"
というように LambertLighting に設定している
ライティングに必要なファイルのインポート
- 以下をインクルード部分に追加する
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
必要な変数の定義
- 今回 Attributes (頂点シェーダーの引数) は変えない
- Varyings (頂点シェーダーのアウトプット・フラグメントシェーダーのインプット) に頂点色と光量の変数を定義
struct Varyings { // vertices position of screen space float4 positionHCS : SV_POSITION; half3 lightAmount : TEXCOORD2; float4 color : COLOR; };
頂点シェーダーに各頂点の色の編集とライティングの計算を追加
- 今回はテクスチャを用いないで色の編集を行うため, 各頂点の x 座標に基づいて色の変化を加える (見やすさのため)
float xNormalized = saturate((IN.positionOS.x + 1.0) * 0.5); OUT.color = float4(xNormalized, 0.0, 1.0 - xNormalized, 1.0);
- また, 法線方向を取得したうえで光量を設定する
// lighting VertexNormalInputs positions = GetVertexNormalInputs(IN.positionOS); Light light = GetMainLight(); OUT.lightAmount = LightingLambert(light.color, light.direction, positions.normalWS.xyz);
LightingLambert
を用いてランバート反射の計算を行っている
フラグメントシェーダーで光量に応じて色を変化させる
- フラグメントシェーダーで各頂点の色を受け取り, 光量に応じて色の RGB 値を変化させる
// fragment shader half4 frag(Varyings IN) : SV_Target { // lighting float3 litColor = IN.color.rgb * IN.lightAmount; return float4(litColor, 1.0); }
球に反映させる
- マテリアルを作成しシェーダーを反映させ, デフォルトの球に適用する. 球に影がしっかりとできている
サンプルコード
- 以下が全体のコード
Shader "LightingURP/LambertLighting" { Properties { } SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" } Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { // vertices position of object space float4 positionOS : POSITION; // float4 color : COLOR; // vertex color }; struct Varyings { // vertices position of screen space float4 positionHCS : SV_POSITION; half3 lightAmount : TEXCOORD2; float4 color : COLOR; }; // vertex shader Varyings vert(Attributes IN) { // output object Varyings OUT; // position change with noise float3 outPos = IN.positionOS.xyz; // to clip space OUT.positionHCS = TransformObjectToHClip(outPos); // vertex processing float xNormalized = saturate((IN.positionOS.x + 1.0) * 0.5); OUT.color = float4(xNormalized, 0.0, 1.0 - xNormalized, 1.0); // lighting VertexNormalInputs positions = GetVertexNormalInputs(IN.positionOS); Light light = GetMainLight(); OUT.lightAmount = LightingLambert(light.color, light.direction, positions.normalWS.xyz); return OUT; } // fragment shader half4 frag(Varyings IN) : SV_Target { // lighting float3 litColor = IN.color.rgb * IN.lightAmount; return float4(litColor, 1.0); } ENDHLSL } } }