// Crest Water System // Copyright © 2024 Wave Harmonic. All rights reserved. // Based on tutorial: https://connect.unity.com/p/adding-your-own-hlsl-code-to-shader-graph-the-custom-function-node #ifndef CREST_LIGHTING_H #define CREST_LIGHTING_H #include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl" #include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl" #if CREST_URP #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" // Unity renamed keyword. #ifdef USE_FORWARD_PLUS #define USE_CLUSTER_LIGHT_LOOP USE_FORWARD_PLUS #endif // USE_FORWARD_PLUS #ifdef FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK #define CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK #endif // FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK #if UNITY_VERSION >= 60000000 #if defined(STEREO_INSTANCING_ON) || defined(STEREO_MULTIVIEW_ON) #if _ALPHATEST_ON #if !USE_CLUSTER_LIGHT_LOOP // If not clustered and additional light shadows and XR, the shading model // completely breaks. It is like shadow attenuation is NaN or some obscure // compiler issue. For 2022.3, it is broken for forward+ only, but cannot be fixed. #define d_ShadowMaskBroken 1 #else #if _RECEIVE_SHADOWS_OFF // Right eye broken rendering similar to above. #define d_AdditionalLightsBroken 1 #endif #endif #endif #endif #endif #endif // CREST_URP #if CREST_HDRP #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #if UNITY_VERSION < 202310 #define GetMeshRenderingLayerMask GetMeshRenderingLightLayer #endif // UNITY_VERSION #if UNITY_VERSION < 60000000 #if PROBE_VOLUMES_L1 #define AMBIENT_PROBE_BUFFER 1 #endif // PROBE_VOLUMES_L1 #endif // UNITY_VERSION #endif // CREST_HDRP m_CrestNameSpace void PrimaryLight ( const float3 i_PositionWS, out half3 o_Color, out half3 o_Direction ) { #if CREST_HDRP // We could get the main light the same way we get the main light shadows, // but most of the data would be missing (including below horizon // attenuation) which would require re-running the light loop which is expensive. o_Direction = g_Crest_PrimaryLightDirection; o_Color = g_Crest_PrimaryLightIntensity; #elif CREST_URP // Actual light data from the pipeline. Light light = GetMainLight(); o_Direction = light.direction; o_Color = light.color; #elif CREST_BIRP #ifndef USING_DIRECTIONAL_LIGHT // Yes. This function wants the world position of the surface. o_Direction = normalize(UnityWorldSpaceLightDir(i_PositionWS)); #else o_Direction = _WorldSpaceLightPos0.xyz; // Prevents divide by zero. if (all(o_Direction == 0)) o_Direction = half3(0.0, 1.0, 0.0); #endif o_Color = _LightColor0.rgb; #if SHADERPASS == SHADERPASS_FORWARD_ADD #if !SHADOWS_SCREEN // FIXME: undeclared identifier 'IN' in Pass: BuiltIn ForwardAdd, Vertex program with DIRECTIONAL SHADOWS_SCREEN UNITY_LIGHT_ATTENUATION(attenuation, IN, i_PositionWS) o_Color *= attenuation; #endif #endif #endif } half3 AmbientLight(const half3 i_AmbientLight) { half3 ambient = i_AmbientLight; #ifndef SHADERGRAPH_PREVIEW #if CREST_HDRP // Allows control of baked lighting through volume framework. // We could create a BuiltinData struct which would have rendering layers on it, but it seems more complicated. ambient *= GetIndirectDiffuseMultiplier(GetMeshRenderingLayerMask()); #endif // CREST_HDRP #endif // SHADERGRAPH_PREVIEW return ambient; } half3 AmbientLight() { // Use the constant term (0th order) of SH stuff - this is the average. const half3 ambient = #if AMBIENT_PROBE_BUFFER half3(_AmbientProbeData[0].w, _AmbientProbeData[1].w, _AmbientProbeData[2].w); #else half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); #endif return AmbientLight(ambient); } half3 AdditionalLighting(const float3 i_PositionWS, const float4 i_ScreenPosition, const float2 i_StaticLightMapUV) { half3 color = 0.0; #if CREST_URP #if defined(_ADDITIONAL_LIGHTS) InputData inputData = (InputData)0; inputData.normalizedScreenSpaceUV = i_ScreenPosition.xy / i_ScreenPosition.w; inputData.positionWS = i_PositionWS; // Shadowmask. #if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON) inputData.shadowMask = SAMPLE_SHADOWMASK(i_StaticLightMapUV); #endif const half4 shadowMask = CalculateShadowMask(inputData); // No AO, but we need the struct. AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData.normalizedScreenSpaceUV, 0.0); uint pixelLightCount = GetAdditionalLightsCount(); #ifdef _LIGHT_LAYERS uint meshRenderingLayers = GetMeshRenderingLayer(); #endif LIGHT_LOOP_BEGIN(pixelLightCount) // Includes shadows and cookies. Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor); #if d_ShadowMaskBroken light.shadowAttenuation = 1.0; #endif #if d_AdditionalLightsBroken light.color = 0.0; #endif #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers)) #endif { color += light.color * (light.distanceAttenuation * light.shadowAttenuation); } LIGHT_LOOP_END #if USE_CLUSTER_LIGHT_LOOP // Additional directional lights. [loop] for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++) { CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor); #ifdef _LIGHT_LAYERS if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers)) #endif { color += light.color * (light.distanceAttenuation * light.shadowAttenuation); } } #endif // USE_CLUSTER_LIGHT_LOOP #endif // _ADDITIONAL_LIGHTS #endif // CREST_URP // HDRP todo. // BIRP has additional lights as additional passes. Handled elsewhere. return color; } m_CrestNameSpaceEnd #endif