Aetheria/Assets/Shaders/Terrain/My Lighting.cginc
Reinier Vens c6ffcad3f1 Shields
Created field bubble shields / propulsion, currently just a prototype with its own test scene
2025-01-30 01:58:05 +00:00

502 lines
14 KiB
HLSL

#if !defined(MY_LIGHTING_INCLUDED)
#define MY_LIGHTING_INCLUDED
#include "My Lighting Input.cginc"
#if !defined(ALBEDO_FUNCTION)
#define ALBEDO_FUNCTION GetAlbedo
#endif
void ComputeVertexLightColor (inout InterpolatorsVertex i) {
#if defined(VERTEXLIGHT_ON)
i.vertexLightColor = Shade4PointLights(
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb,
unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, i.worldPos.xyz, i.normal
);
#endif
}
float3 CreateBinormal (float3 normal, float3 tangent, float binormalSign) {
return cross(normal, tangent.xyz) *
(binormalSign * unity_WorldTransformParams.w);
}
InterpolatorsVertex MyVertexProgram (VertexData v) {
InterpolatorsVertex i;
UNITY_INITIALIZE_OUTPUT(InterpolatorsVertex, i);
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, i);
i.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
i.uv.zw = TRANSFORM_TEX(v.uv, _DetailTex);
float displacement = tex2Dlod(_DisplacementMap, float4(i.uv.xy, 0, 0)).r * _DisplacementStrength;
//v.normal = normalize(v.normal);
//v.vertex.xyz += v.normal * displacement;
v.vertex.y += displacement;
i.pos = UnityObjectToClipPos(v.vertex);
i.worldPos.xyz = mul(unity_ObjectToWorld, v.vertex);
#if FOG_DEPTH
i.worldPos.w = i.pos.z;
#endif
i.normal = UnityObjectToWorldNormal(v.normal);
#if defined(BINORMAL_PER_FRAGMENT)
i.tangent = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
#else
i.tangent = UnityObjectToWorldDir(v.tangent.xyz);
i.binormal = CreateBinormal(i.normal, i.tangent, v.tangent.w);
#endif
#if defined(LIGHTMAP_ON) || ADDITIONAL_MASKED_DIRECTIONAL_SHADOWS
i.lightmapUV = v.uv1 * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
#if defined(DYNAMICLIGHTMAP_ON)
i.dynamicLightmapUV =
v.uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
UNITY_TRANSFER_SHADOW(i, v.uv1);
ComputeVertexLightColor(i);
return i;
}
float FadeShadows (Interpolators i, float attenuation) {
#if HANDLE_SHADOWS_BLENDING_IN_GI || ADDITIONAL_MASKED_DIRECTIONAL_SHADOWS
// UNITY_LIGHT_ATTENUATION doesn't fade shadows for us.
#if ADDITIONAL_MASKED_DIRECTIONAL_SHADOWS
attenuation = SHADOW_ATTENUATION(i);
#endif
float viewZ =
dot(_WorldSpaceCameraPos - i.worldPos, UNITY_MATRIX_V[2].xyz);
float shadowFadeDistance =
UnityComputeShadowFadeDistance(i.worldPos, viewZ);
float shadowFade = UnityComputeShadowFade(shadowFadeDistance);
float bakedAttenuation =
UnitySampleBakedOcclusion(i.lightmapUV, i.worldPos);
attenuation = UnityMixRealtimeAndBakedShadows(
attenuation, bakedAttenuation, shadowFade
);
#endif
return attenuation;
}
UnityLight CreateLight (Interpolators i) {
UnityLight light;
#if defined(DEFERRED_PASS) || SUBTRACTIVE_LIGHTING
light.dir = float3(0, 1, 0);
light.color = 0;
#else
#if defined(POINT) || defined(POINT_COOKIE) || defined(SPOT)
light.dir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
#else
light.dir = _WorldSpaceLightPos0.xyz;
#endif
UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos.xyz);
attenuation = FadeShadows(i, attenuation);
light.color = _LightColor0.rgb * attenuation;
#endif
return light;
}
float3 BoxProjection (
float3 direction, float3 position,
float4 cubemapPosition, float3 boxMin, float3 boxMax
) {
#if UNITY_SPECCUBE_BOX_PROJECTION
UNITY_BRANCH
if (cubemapPosition.w > 0) {
float3 factors =
((direction > 0 ? boxMax : boxMin) - position) / direction;
float scalar = min(min(factors.x, factors.y), factors.z);
direction = direction * scalar + (position - cubemapPosition);
}
#endif
return direction;
}
void ApplySubtractiveLighting (
Interpolators i, inout UnityIndirect indirectLight
) {
#if SUBTRACTIVE_LIGHTING
UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos.xyz);
attenuation = FadeShadows(i, attenuation);
float ndotl = saturate(dot(i.normal, _WorldSpaceLightPos0.xyz));
float3 shadowedLightEstimate =
ndotl * (1 - attenuation) * _LightColor0.rgb;
float3 subtractedLight = indirectLight.diffuse - shadowedLightEstimate;
subtractedLight = max(subtractedLight, unity_ShadowColor.rgb);
subtractedLight =
lerp(subtractedLight, indirectLight.diffuse, _LightShadowData.x);
indirectLight.diffuse = min(subtractedLight, indirectLight.diffuse);
#endif
}
UnityIndirect CreateIndirectLight (Interpolators i, float3 viewDir) {
UnityIndirect indirectLight;
indirectLight.diffuse = 0;
indirectLight.specular = 0;
#if defined(VERTEXLIGHT_ON)
indirectLight.diffuse = i.vertexLightColor;
#endif
#if defined(FORWARD_BASE_PASS) || defined(DEFERRED_PASS)
#if defined(LIGHTMAP_ON)
indirectLight.diffuse =
DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lightmapUV));
#if defined(DIRLIGHTMAP_COMBINED)
float4 lightmapDirection = UNITY_SAMPLE_TEX2D_SAMPLER(
unity_LightmapInd, unity_Lightmap, i.lightmapUV
);
indirectLight.diffuse = DecodeDirectionalLightmap(
indirectLight.diffuse, lightmapDirection, i.normal
);
#endif
ApplySubtractiveLighting(i, indirectLight);
#endif
#if defined(DYNAMICLIGHTMAP_ON)
float3 dynamicLightDiffuse = DecodeRealtimeLightmap(
UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, i.dynamicLightmapUV)
);
#if defined(DIRLIGHTMAP_COMBINED)
float4 dynamicLightmapDirection = UNITY_SAMPLE_TEX2D_SAMPLER(
unity_DynamicDirectionality, unity_DynamicLightmap,
i.dynamicLightmapUV
);
indirectLight.diffuse += DecodeDirectionalLightmap(
dynamicLightDiffuse, dynamicLightmapDirection, i.normal
);
#else
indirectLight.diffuse += dynamicLightDiffuse;
#endif
#endif
#if !defined(LIGHTMAP_ON) && !defined(DYNAMICLIGHTMAP_ON)
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
if (unity_ProbeVolumeParams.x == 1) {
indirectLight.diffuse = SHEvalLinearL0L1_SampleProbeVolume(
float4(i.normal, 1), i.worldPos
);
indirectLight.diffuse = max(0, indirectLight.diffuse);
#if defined(UNITY_COLORSPACE_GAMMA)
indirectLight.diffuse =
LinearToGammaSpace(indirectLight.diffuse);
#endif
}
else {
indirectLight.diffuse +=
max(0, ShadeSH9(float4(i.normal, 1)));
}
#else
indirectLight.diffuse += max(0, ShadeSH9(float4(i.normal, 1)));
#endif
#endif
float3 reflectionDir = reflect(-viewDir, i.normal);
Unity_GlossyEnvironmentData envData;
envData.roughness = 1 - GetSmoothness(i);
envData.reflUVW = BoxProjection(
reflectionDir, i.worldPos.xyz,
unity_SpecCube0_ProbePosition,
unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax
);
float3 probe0 = Unity_GlossyEnvironment(
UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData
);
envData.reflUVW = BoxProjection(
reflectionDir, i.worldPos.xyz,
unity_SpecCube1_ProbePosition,
unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax
);
#if UNITY_SPECCUBE_BLENDING
float interpolator = unity_SpecCube0_BoxMin.w;
UNITY_BRANCH
if (interpolator < 0.99999) {
float3 probe1 = Unity_GlossyEnvironment(
UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0),
unity_SpecCube0_HDR, envData
);
indirectLight.specular = lerp(probe1, probe0, interpolator);
}
else {
indirectLight.specular = probe0;
}
#else
indirectLight.specular = probe0;
#endif
float occlusion = GetOcclusion(i);
indirectLight.diffuse *= occlusion;
indirectLight.specular *= occlusion;
#if defined(DEFERRED_PASS) && UNITY_ENABLE_REFLECTION_BUFFERS
indirectLight.specular = 0;
#endif
#endif
return indirectLight;
}
float3 calcNormal (float3 pos, float2 uv)
{
float3 n = float3(pos.x,
tex2D(_DisplacementMap, float2(uv.x, uv.y + _DisplacementMap_TexelSize.y * _DisplacementStep)).x * -_DisplacementStrength,
pos.z + _DisplacementMap_TexelSize.y * unity_ObjectToWorld._m00 * _DisplacementStep);
float3 me = float3(pos.x,
tex2D(_DisplacementMap, float2(uv.x, uv.y)).x * -_DisplacementStrength,
pos.z);
float3 e = float3(pos.x + _DisplacementMap_TexelSize.x * unity_ObjectToWorld._m00 * _DisplacementStep,
tex2D(_DisplacementMap, float2(uv.x + _DisplacementMap_TexelSize.x * _DisplacementStep, uv.y)).x * -_DisplacementStrength,
pos.z);
float3 norm = cross(normalize(n-me),normalize(e-me));
return norm;
}
void InitializeFragmentNormal(inout Interpolators i) {
/* float3 tangentSpaceNormal = GetTangentSpaceNormal(i);
#if defined(BINORMAL_PER_FRAGMENT)
float3 binormal =
CreateBinormal(i.normal, i.tangent.xyz, i.tangent.w);
#else
float3 binormal = i.binormal;
#endif
i.normal = normalize(
tangentSpaceNormal.x * i.tangent +
tangentSpaceNormal.y * binormal +
tangentSpaceNormal.z * i.normal
);*/
i.normal = calcNormal(i.worldPos.xyz,i.uv.xy);
}
float4 ApplyFog (float4 color, Interpolators i) {
#if FOG_ON
float viewDistance = length(_WorldSpaceCameraPos - i.worldPos.xyz);
#if FOG_DEPTH
viewDistance = UNITY_Z_0_FAR_FROM_CLIPSPACE(i.worldPos.w);
#endif
UNITY_CALC_FOG_FACTOR_RAW(viewDistance);
float3 fogColor = 0;
#if defined(FORWARD_BASE_PASS)
fogColor = unity_FogColor.rgb;
#endif
color.rgb = lerp(fogColor, color.rgb, saturate(unityFogFactor));
#endif
return color;
}
/*
float GetParallaxHeight (float2 uv) {
return tex2D(_ParallaxMap, uv).g;
}
float2 ParallaxOffset (float2 uv, float2 viewDir) {
float height = GetParallaxHeight(uv);
height -= 0.5;
height *= _ParallaxStrength;
return viewDir * height;
}
float2 ParallaxRaymarching (float2 uv, float2 viewDir) {
#if !defined(PARALLAX_RAYMARCHING_STEPS)
#define PARALLAX_RAYMARCHING_STEPS 10
#endif
float2 uvOffset = 0;
float stepSize = 1.0 / PARALLAX_RAYMARCHING_STEPS;
float2 uvDelta = viewDir * (stepSize * _ParallaxStrength);
float stepHeight = 1;
float surfaceHeight = GetParallaxHeight(uv);
float2 prevUVOffset = uvOffset;
float prevStepHeight = stepHeight;
float prevSurfaceHeight = surfaceHeight;
for (
int i = 1;
i < PARALLAX_RAYMARCHING_STEPS && stepHeight > surfaceHeight;
i++
) {
prevUVOffset = uvOffset;
prevStepHeight = stepHeight;
prevSurfaceHeight = surfaceHeight;
uvOffset -= uvDelta;
stepHeight -= stepSize;
surfaceHeight = GetParallaxHeight(uv + uvOffset);
}
#if !defined(PARALLAX_RAYMARCHING_SEARCH_STEPS)
#define PARALLAX_RAYMARCHING_SEARCH_STEPS 0
#endif
#if PARALLAX_RAYMARCHING_SEARCH_STEPS > 0
for (int i = 0; i < PARALLAX_RAYMARCHING_SEARCH_STEPS; i++) {
uvDelta *= 0.5;
stepSize *= 0.5;
if (stepHeight < surfaceHeight) {
uvOffset += uvDelta;
stepHeight += stepSize;
}
else {
uvOffset -= uvDelta;
stepHeight -= stepSize;
}
surfaceHeight = GetParallaxHeight(uv + uvOffset);
}
#elif defined(PARALLAX_RAYMARCHING_INTERPOLATE)
float prevDifference = prevStepHeight - prevSurfaceHeight;
float difference = surfaceHeight - stepHeight;
float t = prevDifference / (prevDifference + difference);
uvOffset = prevUVOffset - uvDelta * t;
#endif
return uvOffset;
}
void ApplyParallax (inout Interpolators i) {
#if defined(_PARALLAX_MAP)
i.tangentViewDir = normalize(i.tangentViewDir);
#if !defined(PARALLAX_OFFSET_LIMITING)
#if !defined(PARALLAX_BIAS)
#define PARALLAX_BIAS 0.42
#endif
i.tangentViewDir.xy /= (i.tangentViewDir.z + PARALLAX_BIAS);
#endif
#if !defined(PARALLAX_FUNCTION)
#define PARALLAX_FUNCTION ParallaxOffset
#endif
float2 uvOffset = PARALLAX_FUNCTION(i.uv.xy, i.tangentViewDir.xy);
i.uv.xy += uvOffset;
i.uv.zw += uvOffset * (_DetailTex_ST.xy / _MainTex_ST.xy);
#endif
}*/
struct FragmentOutput {
#if defined(DEFERRED_PASS)
float4 gBuffer0 : SV_Target0;
float4 gBuffer1 : SV_Target1;
float4 gBuffer2 : SV_Target2;
float4 gBuffer3 : SV_Target3;
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
float4 gBuffer4 : SV_Target4;
#endif
#else
float4 color : SV_Target;
#endif
};
float cells( float3 p )
{
// find distance to closest "white checker" in checkerboard pattern
p = frac(p/2.0)*2.0;
p = min( p, 2.0-p );
//return -abs(1-(p.x+p.y+p.z));
return min((p.x+p.y+p.z),length((p.x+p.y+p.z)-3.0));
return min(length(p),length(p-1.0));
}
FragmentOutput MyFragmentProgram (Interpolators i) {
UNITY_SETUP_INSTANCE_ID(i);
#if defined(LOD_FADE_CROSSFADE)
UnityApplyDitherCrossFade(i.vpos);
#endif
//ApplyParallax(i);
InitializeFragmentNormal(i);
float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos.xyz);
half inclination = 1 - saturate(dot (float3(0,1,0), i.normal));
i.normal = dot(viewDir, i.normal) > 0 ? i.normal : -i.normal;
half rim = saturate(dot (normalize(viewDir), i.normal));
float alpha = tex2D (_AlphaMask, i.uv).r *
(1 - saturate(max(0, abs(i.worldPos.y - _AlphaRangeCenter) - _AlphaRange) / _AlphaRangeFeather)) *
(cells(i.worldPos * _AlphaTiling) +
(pow((rim), _FresnelClipPower) + _FresnelClipOffset) * _FresnelClip);// * inclination
#if defined(_RENDERING_CUTOUT)
clip(alpha - _AlphaClip);
#endif
float3 specularTint;
float oneMinusReflectivity;
float3 albedo = DiffuseAndSpecularFromMetallic(
ALBEDO_FUNCTION(i), GetMetallic(i), specularTint, oneMinusReflectivity
);
#if defined(_RENDERING_TRANSPARENT)
albedo *= alpha;
alpha = 1 - oneMinusReflectivity + alpha * oneMinusReflectivity;
#endif
float4 color = UNITY_BRDF_PBS(
albedo, specularTint,
oneMinusReflectivity, GetSmoothness(i),
i.normal, viewDir,
CreateLight(i), CreateIndirectLight(i, viewDir)
);
float3 dir = refract(viewDir,i.normal,_BackgroundFresnel);
color.rgb += texCUBElod(_Background, float4(dir, _BackgroundBlur)).rgb * _Emission * pow(rim,_EmissionFresnel) * _EmissionColor;// * (max(sign(alpha - _AlphaClip),0)/2+.5);
#if defined(_RENDERING_FADE) || defined(_RENDERING_TRANSPARENT)
color.a = alpha;
#endif
FragmentOutput output;
#if defined(DEFERRED_PASS)
#if !defined(UNITY_HDR_ON)
color.rgb = exp2(-color.rgb);
#endif
output.gBuffer0.rgb = albedo;
output.gBuffer0.a = GetOcclusion(i);
output.gBuffer1.rgb = specularTint;
output.gBuffer1.a = GetSmoothness(i);
output.gBuffer2 = float4(i.normal * 0.5 + 0.5, 1);
output.gBuffer3 = color;
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
float2 shadowUV = 0;
#if defined(LIGHTMAP_ON)
shadowUV = i.lightmapUV;
#endif
output.gBuffer4 =
UnityGetRawBakedOcclusions(shadowUV, i.worldPos.xyz);
#endif
#else
output.color = ApplyFog(color, i);
#endif
return output;
}
#endif