Die Mid-Lane steht auf Zielqualität (stilisierter Realismus). Die übrige Karte bleibt auf dem U2-Stand, bis über den Weg entschieden ist. - U5A: tools/blender/bake_pbr.py backt sechs nahtlose PBR-Sätze (limestone, soil, bark, leaf, rock, water) mit Albedo, Normal aus dem Höhenfeld (Sobel) und ORM (R AO, G Rauigkeit, B Metall), je 2k. Torus-Mapping für Kantenfluss wie phase10/bake_bark.py. - U5B: Luneraria/Surface trägt _AlbedoMap, _NormalMap, _OrmMap triplanar über den Godot-Weltfarben; ORM steuert Rauigkeit, Metall und AO. LuneMaterialFactory bindet je Oberfläche den passenden Satz, LN_Rock den Felsensatz. - U5C: Mid-Lane-Licht — Nebel (ExponentialSquared, Dichte 0,0085), scharfe Schatten (Bias 0,02), Weißabgleich und Vignette, ACES und Bloom leicht angehoben. - U5D: Hit- und Angriffs-Flash über MaterialPropertyBlock (warm beim Angriff, weißglühend beim Treffer), Turmblitze als dreipunktiger Funke mit Breitenkurve und Farbverlauf. CaptureMidLane schreibt fünf Nachweisbilder nach docs/port/screenshots/u5/. - Leistung (macOS-Player, 116 Einheiten): 132 fps Übersicht, 182 fps Mid nah — 20–25 % unter U3 durch PBR, Normals und Nebel. Mid-Lane bleibt über 120 fps. - Tests: EditMode 29/29, PlayMode 13/13, Kerntests 457/457. Keine Regeländerung; Golden 51.221 Werte unverändert. - Grenze eingehalten: keine prozeduralen Gesichter, Haare oder Anatomie. Sculpts bleiben vorbehalten (Freigabe und Lizenzprüfung). - Dokumentation: U5-VISUAL (Umsetzung, Nachweis, Entscheidungsvorlage für die ganze Karte), PORT-QA (U5), PORT-STATUS, KNOWN-BEHAVIOR- DIFFERENCES. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
466 lines
20 KiB
Text
466 lines
20 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.
|
|
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
|
|
_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 _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 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;
|
|
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.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;
|
|
float3 weights = pow(abs(n), 5.0);
|
|
weights /= max(dot(weights, 1.0), 0.0001);
|
|
float3 p = world * _StoneScale;
|
|
// U5 PBR set: triplanar albedo, ORM (ao, roughness, metallic) and tangent normal.
|
|
half3 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;
|
|
half3 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;
|
|
half3 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;
|
|
int mode = (int)round(_Mode);
|
|
// 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 = lerp(0.93, 0.84, rock) * texOrm.g;
|
|
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);
|
|
albedo = lerp(texAlbedo * 0.55, texAlbedo, waves) + 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; PBR set multiplies albedo only.
|
|
roughness = _Roughness * texOrm.g;
|
|
metallic = _Metallic * texOrm.b;
|
|
}
|
|
if (_VertexColor > 0.5)
|
|
albedo *= input.color.rgb;
|
|
// Tangent-space normal of the PBR set, triplanar, on top of the geometric normal.
|
|
half3 nX = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, p.zy), _NormalStrength);
|
|
half3 nY = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, p.xz), _NormalStrength);
|
|
half3 nZ = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, p.xy), _NormalStrength);
|
|
// Whiteout blend of the three projections into world space.
|
|
nX = half3(nX.xy + n.zy, abs(nX.z) * n.x);
|
|
nY = half3(nY.xy + n.xz, abs(nY.z) * n.y);
|
|
nZ = half3(nZ.xy + n.xy, abs(nZ.z) * n.z);
|
|
n = normalize(nX.zyx * weights.x + nY.xzy * weights.y + nZ.xyz * weights.z);
|
|
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);
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|