champions-of-luneraria/Assets/Luneraria/Shaders/LuneSurface.shader
Martin Stickelbroeck 4883d95a2f U5.4 Figuren: Surface-Materialien, Randlicht, SSAO
Die Figuren (Einheiten, Monster, Völker, Helden) bekommen den Materialweg
der Welt; dazu Umgebungsverdeckung für die ganze Szene.

- Surface-Materialien für alle 146 Figurenmaterialien (142 neu unter
  Materials/Units/, die LN_Boss_* gehörten schon zu den Gebäuden). Farbe,
  Rauigkeit und Emission bleiben die Blender-Werte; Metalle werden
  metallisch (vorher war keines der 414 Figurenmaterialien metallisch),
  ein Randlicht hebt die Silhouetten im Draufblick vom Boden ab.
- Oberflächenstruktur je Materialfamilie im eigenen Raum der Figur, nur
  in den HUD-Porträts. Im Feld (30-60 px hohe Figuren) war sie nicht zu
  sehen und kostete rund 10 % Bildrate.
- Ringborkes 4k-Satz liegt am Schnittholz (RB_Cutwood), wohin er gehört;
  U5.3 hatte ihn an die Rinde gebunden. Verwaistes RB_Bark.mat entfernt.
- SSAO über LuneProjectSetup: nach den opaken Objekten, halbe Auflösung,
  Radius 0,35 m, Ausblendung ab 260 m. Standardmäßig an (Entscheidung des
  Projektinhabers), in den Optionen abschaltbar, -luneSsao 0 für eine
  Sitzung. Die Variante mit Tiefen-Normalen-Vorpass kostete 19-28 %.
- Shader: Steinreliefkarte nur noch für Gelände, Stein, Pflaster, Erde.
- Werkzeug: Übersichtsbilder mit LUNE_DRESS=1 eingekleidet wie im Spiel;
  das Materialset wird nach der leeren Vorschauszene geladen (sie entlädt
  unreferenzierte Assets).
- Tests: EditMode 29/29, PlayMode 14/14, Verify 718/0, Player-Selbsttest
  30/30 (4 neue zur SSAO-Option), Fingerabdrücke unverändert
  (DCE95C96556F3A1A, 7B8E43AEFC0D60C5).
- Leistung (A/B mit U5.3 im selben Lauf): Mid nah 177,7 -> 148,5 fps
  (-16 %), Karte 127,8 -> 111,5 fps (-13 %); ohne SSAO -3,5 / -4,5 %.
- Doku: U5-VISUAL (U5.4), PORT-STATUS, PORT-QA; Bilder screenshots/u5.4/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:07:28 +02:00

550 lines
25 KiB
Text

// Shared surface shader of Champions of Luneraria in URP (U2B, PBR since U5). Ports the Godot
// world shaders (scripts/luneraria/view/lune_terrain.gdshader, scripts/presentation/sanctuary.gdshader,
// river.gdshader, materials/lune_vein.gdshader) and a simplified G2 building look: one
// shader, the look chosen per material with _Mode.
// 0 plain base colour (x vertex colour with _VertexColor), metal/emission from parameters
// 1 terrain zone colour from the vertex colour, rockiness in vertex alpha, triplanar limestone
// 2 stone Kluft stone: triplanar limestone relief
// 3 paving lane paving
// 4 soil packed earth
// 5 bark tree bark ridges
// 6 foliage leaves with wind
// 7 water river surface with moving waves
// 8 vein energy vein of the Ancient plaza (UV.x along, UV.y across)
// 9 crystal glowing crystal with rim light
// World-space patterns use Unity world coordinates (Godot x is mirrored); the look is the same.
// U5 PBR set (tools/blender/bake_pbr.py): albedo, tangent normal, ORM (R ao, G roughness,
// B metallic), triplanar like the stone map. _StoneMap stays as a cheap relief fallback.
// U5.3: the maps are detail around the Godot look. Albedo is divided by its mean colour
// (_AlbedoMean) and roughness by its mean (_OrmMean.g) where the material keeps its own
// roughness, so the Godot colours and roughness stay the average and the maps add variation.
// U5.4: _ObjectSpace samples the triplanar maps in the mesh's own space, so the detail of a unit
// stays on the moving, turning figure (world space would slide it over the body). _Rim adds a
// view-dependent rim light (Fresnel) that lifts the figures' silhouettes off the ground in the
// top-down view, the readability device of the reference MOBAs.
Shader "Luneraria/Surface"
{
Properties
{
_BaseColor("Base Colour", Color) = (1, 1, 1, 1)
[NoScaleOffset] _AlbedoMap("Albedo", 2D) = "white" {}
[NoScaleOffset] _NormalMap("Normal", 2D) = "bump" {}
[NoScaleOffset] _OrmMap("ORM (ao, rough, metal)", 2D) = "white" {}
[NoScaleOffset] _StoneMap("Stone Map", 2D) = "grey" {}
_StoneScale("Stone Scale", Float) = 0.23
_Mode("Mode", Float) = 0
_VertexColor("Multiply Vertex Colour", Float) = 0
_Metallic("Metallic", Range(0, 1)) = 0
_Roughness("Roughness", Range(0, 1)) = 0.88
[HDR] _EmissionColor("Emission", Color) = (0, 0, 0, 1)
_Relief("Relief Strength", Float) = 0.016
_NormalStrength("Normal Strength", Float) = 1
_Quality("Quality (1 lane PBR, 0 edge)", Float) = 1
_UvMaps("UV Maps (1 character, 0 world triplanar)", Float) = 0
_AlbedoMean("Albedo Mean (linear)", Vector) = (1, 1, 1, 1)
_OrmMean("ORM Mean (linear)", Vector) = (1, 1, 1, 1)
_ObjectSpace("Object Space Triplanar (1 units, 0 world)", Float) = 0
_Rim("Rim Light", Float) = 0
_RimColor("Rim Colour", Color) = (0.8, 0.86, 1, 1)
_Energy("Energy (veins)", Float) = 1
_Flicker("Flicker (veins)", Float) = 0
_Seed("Seed", Float) = 0
[Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull", Float) = 2
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry" }
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
half4 _BaseColor;
float _StoneScale;
float _Mode;
float _VertexColor;
half _Metallic;
half _Roughness;
half4 _EmissionColor;
float _Relief;
float _NormalStrength;
float _Quality;
float _UvMaps;
half4 _AlbedoMean;
half4 _OrmMean;
float _ObjectSpace;
half _Rim;
half4 _RimColor;
float _Energy;
float _Flicker;
float _Seed;
float _Cull;
CBUFFER_END
TEXTURE2D(_AlbedoMap);
SAMPLER(sampler_AlbedoMap);
TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);
TEXTURE2D(_OrmMap);
SAMPLER(sampler_OrmMap);
TEXTURE2D(_StoneMap);
SAMPLER(sampler_StoneMap);
float LuneHash(float3 p)
{
p = frac(p * 0.1031);
p += dot(p, p.yzx + 33.33);
return frac((p.x + p.y) * p.z);
}
float LuneNoise(float3 p)
{
float3 i = floor(p);
float3 f = frac(p);
f = f * f * (3.0 - 2.0 * f);
return lerp(lerp(lerp(LuneHash(i), LuneHash(i + float3(1, 0, 0)), f.x), lerp(LuneHash(i + float3(0, 1, 0)), LuneHash(i + float3(1, 1, 0)), f.x), f.y),
lerp(lerp(LuneHash(i + float3(0, 0, 1)), LuneHash(i + float3(1, 0, 1)), f.x), lerp(LuneHash(i + float3(0, 1, 1)), LuneHash(i + float3(1, 1, 1)), f.x), f.y), f.z);
}
float LuneHash2(float2 p) { return frac(sin(dot(p, float2(127.1, 311.7))) * 43758.5453); }
float LuneNoise2(float2 p)
{
float2 i = floor(p);
float2 f = frac(p);
f = f * f * (3.0 - 2.0 * f);
return lerp(lerp(LuneHash2(i), LuneHash2(i + float2(1, 0)), f.x), lerp(LuneHash2(i + float2(0, 1)), LuneHash2(i + float2(1, 1)), f.x), f.y);
}
// Foliage sways a little with height (Godot: VERTEX.x += wind * 0.065 * clamp(y * 0.3)).
float3 LuneWind(float3 positionWS)
{
if (_Mode > 5.5 && _Mode < 6.5)
{
float t = _Time.y;
float wind = sin(t * 0.8 + positionWS.x * 0.55 + positionWS.z * 0.32) * sin(t * 0.37 + positionWS.z * 0.6);
positionWS.x += wind * 0.065 * clamp(positionWS.y * 0.3, 0.15, 1.0);
}
return positionWS;
}
ENDHLSL
Pass
{
Name "ForwardLit"
Tags { "LightMode" = "UniversalForward" }
Cull [_Cull]
HLSLPROGRAM
#pragma target 3.0
#pragma vertex Vert
#pragma fragment Frag
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile _ _CLUSTER_LIGHT_LOOP
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
#pragma multi_compile_fog
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float4 color : COLOR;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 positionWS : TEXCOORD0;
float3 normalWS : TEXCOORD1;
float4 color : TEXCOORD2;
float2 uv : TEXCOORD3;
float fogFactor : TEXCOORD4;
// Mesh tangent (xyz) and bitangent sign (w) for the authored UV normal maps (U5.3).
float4 tangentWS : TEXCOORD5;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vert(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
float3 positionWS = LuneWind(TransformObjectToWorld(input.positionOS.xyz));
output.positionWS = positionWS;
output.normalWS = TransformObjectToWorldNormal(input.normalOS);
output.tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w * GetOddNegativeScale());
output.positionCS = TransformWorldToHClip(positionWS);
output.color = input.color;
output.uv = input.uv;
output.fogFactor = ComputeFogFactor(output.positionCS.z);
return output;
}
half4 Frag(Varyings input, bool frontFace : SV_IsFrontFace) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(input);
float3 world = input.positionWS;
float3 n = normalize(input.normalWS);
if (!frontFace)
n = -n;
// Triplanar space: the world, or the mesh's own space for units (U5.4). Object space
// comes back from the world through the draw's matrix, so no extra interpolators.
bool objectSpace = _ObjectSpace > 0.5;
float3 triPosition = world;
float3 triNormal = n;
if (objectSpace)
{
triPosition = TransformWorldToObject(world);
triNormal = normalize(TransformWorldToObjectNormal(n));
}
float3 weights = pow(abs(triNormal), 5.0);
weights /= max(dot(weights, 1.0), 0.0001);
float3 p = triPosition * _StoneScale;
// U5 PBR set (lane tier): triplanar albedo, ORM and normal. Edge tier (Weg 2
// Stufen) skips the maps and keeps the flat U2 response of colour + stone relief.
// _UvMaps samples the authored UVs of a character (Ringborke bark) instead.
half3 texAlbedo = half3(1, 1, 1);
half3 texOrm = half3(1.0, _Roughness, _Metallic);
half3 nX = half3(0, 0, 1), nY = half3(0, 0, 1), nZ = half3(0, 0, 1);
// Variation of the map around its mean; 1 where no map is sampled (edge tier).
half roughDetail = 1.0;
half metalDetail = 1.0;
if (_Quality > 0.5)
{
if (_UvMaps > 0.5)
{
texAlbedo = SAMPLE_TEXTURE2D(_AlbedoMap, sampler_AlbedoMap, input.uv).rgb;
texOrm = SAMPLE_TEXTURE2D(_OrmMap, sampler_OrmMap, input.uv).rgb;
// Authored UV normal (Ringborke bark) in the mesh's own tangent frame
// (Mikktspace tangents of the FBX import, skinned with the figure).
float3 tangent = normalize(input.tangentWS.xyz - n * dot(n, input.tangentWS.xyz));
float3 bitangent = cross(n, tangent) * (input.tangentWS.w < 0.0 ? -1.0 : 1.0);
half3 uvNormal = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.uv), _NormalStrength);
n = normalize(uvNormal.x * tangent + uvNormal.y * bitangent + uvNormal.z * n);
}
else
{
texAlbedo = SAMPLE_TEXTURE2D(_AlbedoMap, sampler_AlbedoMap, p.zy).rgb * weights.x
+ SAMPLE_TEXTURE2D(_AlbedoMap, sampler_AlbedoMap, p.xz).rgb * weights.y
+ SAMPLE_TEXTURE2D(_AlbedoMap, sampler_AlbedoMap, p.xy).rgb * weights.z;
texOrm = SAMPLE_TEXTURE2D(_OrmMap, sampler_OrmMap, p.zy).rgb * weights.x
+ SAMPLE_TEXTURE2D(_OrmMap, sampler_OrmMap, p.xz).rgb * weights.y
+ SAMPLE_TEXTURE2D(_OrmMap, sampler_OrmMap, p.xy).rgb * weights.z;
nX = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, p.zy), _NormalStrength);
nY = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, p.xz), _NormalStrength);
nZ = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, p.xy), _NormalStrength);
}
// Detail around the Godot colour: the map's mean becomes 1.
texAlbedo /= max(_AlbedoMean.rgb, half3(0.002, 0.002, 0.002));
roughDetail = texOrm.g / max(_OrmMean.g, 0.05);
metalDetail = texOrm.b / max(_OrmMean.b, 0.05);
}
int mode = (int)round(_Mode);
// The stone relief map only for the modes that use it (terrain, stone, paving, soil):
// plain surfaces (figures, building parts, props) save three samples (U5.4).
half3 stone = half3(0.5, 0.5, 0.5);
if (mode >= 1 && mode <= 4)
{
stone = SAMPLE_TEXTURE2D(_StoneMap, sampler_StoneMap, p.zy).rgb * weights.x
+ SAMPLE_TEXTURE2D(_StoneMap, sampler_StoneMap, p.xz).rgb * weights.y
+ SAMPLE_TEXTURE2D(_StoneMap, sampler_StoneMap, p.xy).rgb * weights.z;
}
float relief = dot(stone, 0.3333);
half3 albedo = _BaseColor.rgb * texAlbedo;
half roughness = texOrm.g;
half metallic = texOrm.b;
half ao = texOrm.r;
half3 emission = _EmissionColor.rgb;
float bump = 0.0;
// World-space modes keep their Godot look on top of the PBR set.
if (mode == 1)
{
float broad = LuneNoise(world * 0.35);
float grain = LuneNoise(world * 6.0);
float rock = input.color.a;
half3 soil = input.color.rgb * texAlbedo * lerp(0.84, 1.14, broad) * lerp(0.9, 1.07, grain);
half3 rocky = input.color.rgb * texAlbedo * lerp(0.72, 1.45, stone);
albedo = lerp(soil, rocky, rock);
roughness = saturate(lerp(0.93, 0.84, rock) * roughDetail);
metallic = texOrm.b;
bump = 0.006 + rock * 0.014;
}
else if (mode == 2)
{
albedo = _BaseColor.rgb * texAlbedo * lerp(0.65, 1.6, stone);
roughness = texOrm.g;
bump = _Relief;
}
else if (mode == 3)
{
albedo = _BaseColor.rgb * texAlbedo * lerp(0.82, 1.3, stone);
roughness = texOrm.g;
bump = _Relief;
}
else if (mode == 4)
{
float broad = LuneNoise(world * 0.8);
albedo = _BaseColor.rgb * texAlbedo * lerp(0.82, 1.12, broad);
albedo = lerp(albedo, half3(0.12, 0.17, 0.075) * texAlbedo, smoothstep(0.54, 0.8, broad) * 0.16);
roughness = texOrm.g;
bump = _Relief;
}
else if (mode == 5)
{
float ridges = LuneNoise(world * float3(13, 1.2, 13));
float grain = LuneNoise(world * 21.0);
albedo = _BaseColor.rgb * texAlbedo * lerp(0.45, 1.2, ridges) * lerp(0.8, 1.08, grain);
relief = ridges;
roughness = texOrm.g;
bump = 0.025;
}
else if (mode == 6)
{
float broad = LuneNoise(world * 0.8);
albedo = _BaseColor.rgb * texAlbedo * lerp(0.75, 1.2, broad);
roughness = texOrm.g;
// Godot BACKLIGHT (albedo * 0.32): light through thin leaves, approximated as a small glow.
emission += albedo * 0.32 * saturate(dot(-n, _MainLightPosition.xyz)) * _MainLightColor.rgb;
}
else if (mode == 7)
{
float2 flow = world.xz * 0.75 + float2(_Time.y * 0.037, -_Time.y * 0.075);
float waves = LuneNoise2(flow) * 0.6 + LuneNoise2(flow * 2.13 + float2(-_Time.y * 0.06, 0)) * 0.3 + LuneNoise2(flow * 4.17) * 0.1;
float fresnel = pow(1.0 - saturate(dot(n, GetWorldSpaceNormalizeViewDir(world))), 4.0);
// Godot river colours (U2/U3) with the water set as detail.
albedo = lerp(half3(0.022, 0.094, 0.098), half3(0.042, 0.145, 0.15), waves) * texAlbedo + half3(0.045, 0.07, 0.075) * fresnel;
roughness = lerp(texOrm.g, 0.22, fresnel * 0.5);
metallic = texOrm.b;
relief = waves;
bump = 0.055;
}
else if (mode == 8)
{
float across = abs(input.uv.y - 0.5) * 2.0;
float core = 1.0 - smoothstep(0.15, 0.7, across);
float lip = smoothstep(0.72, 0.95, across);
float flow = frac(input.uv.x * 0.35 + _Time.y * 0.45 + _Seed);
float pulse = smoothstep(0.0, 0.12, flow) * (1.0 - smoothstep(0.12, 0.45, flow));
float live = _Energy;
if (_Flicker > 0.0)
live *= lerp(1.0, step(0.4, LuneNoise(float3(_Time.y * 4.0, input.uv.x * 0.3, _Seed))), _Flicker);
half3 carved = half3(0.08, 0.08, 0.1) + half3(0.3, 0.29, 0.27) * lip;
albedo = lerp(carved, _BaseColor.rgb * 0.2, core * 0.6);
roughness = lerp(0.85, 0.3, core);
metallic = 0.0;
ao = 1.0;
emission = _BaseColor.rgb * core * live * (0.55 + pulse * 1.6);
}
else if (mode == 9)
{
float rim = pow(1.0 - saturate(dot(n, GetWorldSpaceNormalizeViewDir(world))), 2.5);
albedo = _BaseColor.rgb * 0.35;
roughness = 0.08;
metallic = 0.0;
ao = 1.0;
emission = _EmissionColor.rgb * (0.75 + rim * 1.2);
}
else
{
// plain: keep the material's own metal/roughness; the set adds variation around them.
roughness = saturate(_Roughness * roughDetail);
metallic = saturate(_Metallic * metalDetail);
}
if (_VertexColor > 0.5)
albedo *= input.color.rgb;
// Tangent-space normal of the PBR set (lane tier only), triplanar, on top of the
// geometric normal. UV characters (Ringborke) already blended their normal above.
if (_Quality > 0.5 && _UvMaps < 0.5)
{
// Whiteout blend of the three projections in the triplanar space, then to world.
float3 tn = triNormal;
nX = half3(nX.xy + tn.zy, abs(nX.z) * tn.x);
nY = half3(nY.xy + tn.xz, abs(nY.z) * tn.y);
nZ = half3(nZ.xy + tn.xy, abs(nZ.z) * tn.z);
float3 blended = normalize(nX.zyx * weights.x + nY.xzy * weights.y + nZ.xyz * weights.z);
n = objectSpace ? normalize(TransformObjectToWorldNormal(blended)) : blended;
}
if (bump > 0.0)
{
// Relief from the pattern's screen derivatives (surface gradient, as in Godot).
float3 dx = ddx(world);
float3 dy = ddy(world);
float3 rx = cross(dy, n);
float3 ry = cross(n, dx);
float det = dot(dx, rx);
float3 gradient = ddx(relief) * rx + ddy(relief) * ry;
n = normalize(abs(det) * n - sign(det) * gradient * bump);
}
if (_Rim > 0.0)
{
// Rim light: grazing view angles of the shaded normal, scaled by the main light so it stays out of shadowless night.
half rim = pow(1.0 - saturate(dot(n, GetWorldSpaceNormalizeViewDir(world))), 3.0);
emission += _RimColor.rgb * rim * _Rim * saturate(dot(_MainLightColor.rgb, half3(0.3333, 0.3333, 0.3333)));
}
InputData inputData = (InputData)0;
inputData.positionWS = world;
inputData.positionCS = input.positionCS;
inputData.normalWS = n;
inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(world);
inputData.shadowCoord = TransformWorldToShadowCoord(world);
inputData.fogCoord = input.fogFactor;
inputData.bakedGI = SampleSH(n);
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS);
inputData.shadowMask = half4(1, 1, 1, 1);
SurfaceData surface = (SurfaceData)0;
surface.albedo = albedo;
surface.metallic = metallic;
surface.specular = half3(0, 0, 0);
surface.smoothness = 1.0 - roughness;
surface.occlusion = ao;
surface.emission = emission;
surface.alpha = 1.0;
surface.normalTS = half3(0, 0, 1);
half4 color = UniversalFragmentPBR(inputData, surface);
color.rgb = MixFog(color.rgb, inputData.fogCoord);
return color;
}
ENDHLSL
}
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On
ZTest LEqual
ColorMask 0
Cull [_Cull]
HLSLPROGRAM
#pragma target 3.0
#pragma vertex ShadowVert
#pragma fragment ShadowFrag
#pragma multi_compile_instancing
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
float3 _LightDirection;
float3 _LightPosition;
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
float4 ShadowVert(Attributes input) : SV_POSITION
{
UNITY_SETUP_INSTANCE_ID(input);
float3 positionWS = LuneWind(TransformObjectToWorld(input.positionOS.xyz));
float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
float3 lightDirectionWS = normalize(_LightPosition - positionWS);
#else
float3 lightDirectionWS = _LightDirection;
#endif
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
return ApplyShadowClamping(positionCS);
}
half4 ShadowFrag() : SV_Target { return 0; }
ENDHLSL
}
Pass
{
Name "DepthOnly"
Tags { "LightMode" = "DepthOnly" }
ZWrite On
ColorMask R
Cull [_Cull]
HLSLPROGRAM
#pragma target 3.0
#pragma vertex DepthVert
#pragma fragment DepthFrag
#pragma multi_compile_instancing
struct Attributes
{
float4 positionOS : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
float4 DepthVert(Attributes input) : SV_POSITION
{
UNITY_SETUP_INSTANCE_ID(input);
return TransformWorldToHClip(LuneWind(TransformObjectToWorld(input.positionOS.xyz)));
}
half DepthFrag() : SV_Target { return 0; }
ENDHLSL
}
Pass
{
Name "DepthNormals"
Tags { "LightMode" = "DepthNormals" }
ZWrite On
Cull [_Cull]
HLSLPROGRAM
#pragma target 3.0
#pragma vertex NormalsVert
#pragma fragment NormalsFrag
#pragma multi_compile_instancing
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 normalWS : TEXCOORD0;
};
Varyings NormalsVert(Attributes input)
{
UNITY_SETUP_INSTANCE_ID(input);
Varyings output;
output.positionCS = TransformWorldToHClip(LuneWind(TransformObjectToWorld(input.positionOS.xyz)));
output.normalWS = TransformObjectToWorldNormal(input.normalOS);
return output;
}
half4 NormalsFrag(Varyings input) : SV_Target
{
float3 normalWS = NormalizeNormalPerPixel(input.normalWS);
#if defined(_GBUFFER_NORMALS_OCT)
float2 octNormalWS = PackNormalOctQuadEncode(normalWS);
float2 remapped = saturate(octNormalWS * 0.5 + 0.5);
return half4(PackFloat2To888(remapped), 0.0);
#else
return half4(normalWS, 0.0);
#endif
}
ENDHLSL
}
}
}