123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- #ifndef CUSTOM_LIGHTING_INCLUDED
- #define CUSTOM_LIGHTING_INCLUDED
- // @Cyanilux | https://github.com/Cyanilux/URP_ShaderGraphCustomLighting
- // Note this version of the package assumes v12+ due to usage of "Branch on Input Connection" node
- // For older versions, see branches on github repo!
- //------------------------------------------------------------------------------------------------------
- // Main Light
- //------------------------------------------------------------------------------------------------------
- /*
- - Obtains the Direction, Color and Distance Atten for the Main Light.
- - (DistanceAtten is either 0 or 1 for directional light, depending if the light is in the culling mask or not)
- - If you want shadow attenutation, see MainLightShadows_float, or use MainLightFull_float instead
- */
- void MainLight_float (out float3 Direction, out float3 Color, out float DistanceAtten){
- #ifdef SHADERGRAPH_PREVIEW
- Direction = normalize(float3(1,1,-0.4));
- Color = float4(1,1,1,1);
- DistanceAtten = 1;
- #else
- Light mainLight = GetMainLight();
- Direction = mainLight.direction;
- Color = mainLight.color;
- DistanceAtten = mainLight.distanceAttenuation;
- #endif
- }
- //------------------------------------------------------------------------------------------------------
- // Main Light Layer Test
- //------------------------------------------------------------------------------------------------------
- #ifndef SHADERGRAPH_PREVIEW
- #if UNITY_VERSION < 202220
- /*
- GetMeshRenderingLayer() is only available in 2022.2+
- Previous versions need to use GetMeshRenderingLightLayer()
- */
- uint GetMeshRenderingLayer(){
- return GetMeshRenderingLightLayer();
- }
- #endif
- #endif
-
- /*
- - Tests whether the Main Light Layer Mask appears in the Rendering Layers from renderer
- - (Used to support Light Layers, pass your shading from Main Light into this)
- - To work in an Unlit Graph, requires keywords :
- - Boolean Keyword, Global Multi-Compile "_LIGHT_LAYERS"
- */
- void MainLightLayer_float(float3 Shading, out float3 Out){
- #ifdef SHADERGRAPH_PREVIEW
- Out = Shading;
- #else
- Out = 0;
- uint meshRenderingLayers = GetMeshRenderingLayer();
- #ifdef _LIGHT_LAYERS
- if (IsMatchingLightLayer(GetMainLight().layerMask, meshRenderingLayers))
- #endif
- {
- Out = Shading;
- }
- #endif
- }
- /*
- - Obtains the Light Cookie assigned to the Main Light
- - (For usage, You'd want to Multiply the result with your Light Colour)
- - To work in an Unlit Graph, requires keywords :
- - Boolean Keyword, Global Multi-Compile "_LIGHT_COOKIES"
- */
- void MainLightCookie_float(float3 WorldPos, out float3 Cookie){
- Cookie = 1;
- #if defined(_LIGHT_COOKIES)
- Cookie = SampleMainLightCookie(WorldPos);
- #endif
- }
- //------------------------------------------------------------------------------------------------------
- // Main Light Shadows
- //------------------------------------------------------------------------------------------------------
- /*
- - This undef (un-define) is required to prevent the "invalid subscript 'shadowCoord'" error,
- which occurs when _MAIN_LIGHT_SHADOWS is used with 1/No Shadow Cascades with the Unlit Graph.
- - It's not required for the PBR/Lit graph, so I'm using the SHADERPASS_FORWARD to ignore it for that pass
- */
- #ifndef SHADERGRAPH_PREVIEW
- #include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
- #if (SHADERPASS != SHADERPASS_FORWARD)
- #undef REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR
- #endif
- #endif
- /*
- - Samples the Shadowmap for the Main Light, based on the World Position passed in. (Position node)
- - For shadows to work in the Unlit Graph, the following keywords must be defined in the blackboard :
- - Enum Keyword, Global Multi-Compile "_MAIN_LIGHT", with entries :
- - "SHADOWS"
- - "SHADOWS_CASCADE"
- - "SHADOWS_SCREEN"
- - Boolean Keyword, Global Multi-Compile "_SHADOWS_SOFT"
- - For a PBR/Lit Graph, these keywords are already handled for you.
- */
- void MainLightShadows_float (float3 WorldPos, half4 Shadowmask, out float ShadowAtten){
- #ifdef SHADERGRAPH_PREVIEW
- ShadowAtten = 1;
- #else
- #if defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
- float4 shadowCoord = ComputeScreenPos(TransformWorldToHClip(WorldPos));
- #else
- float4 shadowCoord = TransformWorldToShadowCoord(WorldPos);
- #endif
- ShadowAtten = MainLightShadow(shadowCoord, WorldPos, Shadowmask, _MainLightOcclusionProbes);
- #endif
- }
- void MainLightShadows_float (float3 WorldPos, out float ShadowAtten){
- MainLightShadows_float(WorldPos, half4(1,1,1,1), ShadowAtten);
- }
- //------------------------------------------------------------------------------------------------------
- // Shadowmask (v10+)
- //------------------------------------------------------------------------------------------------------
- /*
- - Used to support "Shadowmask" mode in Lighting window.
- - Should be sampled once in graph, then input into the Main Light Shadows and/or Additional Light subgraphs/functions.
- - To work in an Unlit Graph, likely requires keywords :
- - Boolean Keyword, Global Multi-Compile "SHADOWS_SHADOWMASK"
- - Boolean Keyword, Global Multi-Compile "LIGHTMAP_SHADOW_MIXING"
- - (also LIGHTMAP_ON, but I believe Shader Graph is already defining this one)
- */
- void Shadowmask_half (float2 lightmapUV, out half4 Shadowmask){
- #ifdef SHADERGRAPH_PREVIEW
- Shadowmask = half4(1,1,1,1);
- #else
- OUTPUT_LIGHTMAP_UV(lightmapUV, unity_LightmapST, lightmapUV);
- Shadowmask = SAMPLE_SHADOWMASK(lightmapUV);
- #endif
- }
- //------------------------------------------------------------------------------------------------------
- // Ambient Lighting
- //------------------------------------------------------------------------------------------------------
- /*
- - Uses "SampleSH", the spherical harmonic stuff that ambient lighting / light probes uses.
- - Will likely be used in the fragment, so will be per-pixel.
- - Alternatively could use the Baked GI node, as it'll also handle this for you.
- - Could also use the Ambient node, would be cheaper but the result won't automatically adapt based on the Environmental Lighting Source (Lighting tab).
- */
- void AmbientSampleSH_float (float3 WorldNormal, out float3 Ambient){
- #ifdef SHADERGRAPH_PREVIEW
- Ambient = float3(0.1, 0.1, 0.1); // Default ambient colour for previews
- #else
- Ambient = SampleSH(WorldNormal);
- #endif
- }
- //------------------------------------------------------------------------------------------------------
- // Subtractive Baked GI
- //------------------------------------------------------------------------------------------------------
- /*
- - Used to support "Subtractive" mode in Lighting window.
- - To work in an Unlit Graph, likely requires keywords :
- - Boolean Keyword, Global Multi-Compile "LIGHTMAP_SHADOW_MIXING"
- - (also LIGHTMAP_ON, but I believe Shader Graph is already defining this one)
- */
- void SubtractiveGI_float (float ShadowAtten, float3 normalWS, float3 bakedGI, out half3 result){
- #ifdef SHADERGRAPH_PREVIEW
- result = half3(1,1,1);
- #else
- Light mainLight = GetMainLight();
- mainLight.shadowAttenuation = ShadowAtten;
- MixRealtimeAndBakedGI(mainLight, normalWS, bakedGI);
- result = bakedGI;
- #endif
- }
- //------------------------------------------------------------------------------------------------------
- // Mix Fog
- //------------------------------------------------------------------------------------------------------
- /*
- - Adds fog to the colour, based on the Fog settings in the Lighting tab.
- - Note : Not required for v12, can use Lerp instead. See "Mix Fog" SubGraph
- */
- void MixFog_float (float3 Colour, float Fog, out float3 Out){
- #ifdef SHADERGRAPH_PREVIEW
- Out = Colour;
- #else
- Out = MixFog(Colour, Fog);
- #endif
- }
- //------------------------------------------------------------------------------------------------------
- // Default Additional Lights
- //------------------------------------------------------------------------------------------------------
- /*
- - Handles additional lights (e.g. additional directional, point, spotlights)
- - For custom lighting, you may want to duplicate this and swap the LightingLambert / LightingSpecular functions out. See Toon Example below!
- - To work in the Unlit Graph, the following keywords must be defined in the blackboard :
- - Boolean Keyword, Global Multi-Compile "_ADDITIONAL_LIGHT_SHADOWS"
- - Boolean Keyword, Global Multi-Compile "_ADDITIONAL_LIGHTS"
- - To support Forward+ path,
- - Boolean Keyword, Global Multi-Compile "_FORWARD_PLUS" (2022.2+)
- */
- void AdditionalLights_float(float3 SpecColor, float Smoothness, float3 WorldPosition, float3 WorldNormal, float3 WorldView, half4 Shadowmask,
- out float3 Diffuse, out float3 Specular) {
- float3 diffuseColor = 0;
- float3 specularColor = 0;
- #ifndef SHADERGRAPH_PREVIEW
- Smoothness = exp2(10 * Smoothness + 1);
- uint pixelLightCount = GetAdditionalLightsCount();
- uint meshRenderingLayers = GetMeshRenderingLayer();
- #if USE_FORWARD_PLUS
- for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++) {
- FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
- Light light = GetAdditionalLight(lightIndex, WorldPosition, Shadowmask);
- #ifdef _LIGHT_LAYERS
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- #endif
- {
- // Blinn-Phong
- float3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
- diffuseColor += LightingLambert(attenuatedLightColor, light.direction, WorldNormal);
- specularColor += LightingSpecular(attenuatedLightColor, light.direction, WorldNormal, WorldView, float4(SpecColor, 0), Smoothness);
- }
- }
- #endif
- // For Foward+ the LIGHT_LOOP_BEGIN macro will use inputData.normalizedScreenSpaceUV, inputData.positionWS, so create that:
- InputData inputData = (InputData)0;
- float4 screenPos = ComputeScreenPos(TransformWorldToHClip(WorldPosition));
- inputData.normalizedScreenSpaceUV = screenPos.xy / screenPos.w;
- inputData.positionWS = WorldPosition;
- LIGHT_LOOP_BEGIN(pixelLightCount)
- Light light = GetAdditionalLight(lightIndex, WorldPosition, Shadowmask);
- #ifdef _LIGHT_LAYERS
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- #endif
- {
- // Blinn-Phong
- float3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
- diffuseColor += LightingLambert(attenuatedLightColor, light.direction, WorldNormal);
- specularColor += LightingSpecular(attenuatedLightColor, light.direction, WorldNormal, WorldView, float4(SpecColor, 0), Smoothness);
- }
- LIGHT_LOOP_END
- #endif
- Diffuse = diffuseColor;
- Specular = specularColor;
- }
- // For backwards compatibility (before Shadowmask was introduced)
- void AdditionalLights_float(float3 SpecColor, float Smoothness, float3 WorldPosition, float3 WorldNormal, float3 WorldView,
- out float3 Diffuse, out float3 Specular) {
- AdditionalLights_float(SpecColor, Smoothness, WorldPosition, WorldNormal, WorldView, half4(1,1,1,1), Diffuse, Specular);
- }
- //------------------------------------------------------------------------------------------------------
- // Additional Lights Toon Example
- //------------------------------------------------------------------------------------------------------
- /*
- - Calculates light attenuation values to produce multiple bands for a toon effect. See AdditionalLightsToon function below
- */
- #ifndef SHADERGRAPH_PREVIEW
- float ToonAttenuation(int lightIndex, float3 positionWS, float pointBands, float spotBands){
- #if !USE_FORWARD_PLUS
- lightIndex = GetPerObjectLightIndex(lightIndex);
- #endif
- #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
- float4 lightPositionWS = _AdditionalLightsBuffer[lightIndex].position;
- half4 spotDirection = _AdditionalLightsBuffer[lightIndex].spotDirection;
- half4 distanceAndSpotAttenuation = _AdditionalLightsBuffer[lightIndex].attenuation;
- #else
- float4 lightPositionWS = _AdditionalLightsPosition[lightIndex];
- half4 spotDirection = _AdditionalLightsSpotDir[lightIndex];
- half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[lightIndex];
- #endif
- // Point
- float3 lightVector = lightPositionWS.xyz - positionWS * lightPositionWS.w;
- float distanceSqr = max(dot(lightVector, lightVector), HALF_MIN);
- float range = rsqrt(distanceAndSpotAttenuation.x);
- float dist = sqrt(distanceSqr) / range;
- // Spot
- half3 lightDirection = half3(lightVector * rsqrt(distanceSqr));
- half SdotL = dot(spotDirection.xyz, lightDirection);
- half spotAtten = saturate(SdotL * distanceAndSpotAttenuation.z + distanceAndSpotAttenuation.w);
- spotAtten *= spotAtten;
- float maskSpotToRange = step(dist, 1);
- // Atten
- bool isSpot = (distanceAndSpotAttenuation.z > 0);
- return isSpot ?
- //step(0.01, spotAtten) : // cheaper if you just want "1" band for spot lights
- (floor(spotAtten * spotBands) / spotBands) * maskSpotToRange :
- saturate(1.0 - floor(dist * pointBands) / pointBands);
- }
- #endif
- /*
- - Handles additional lights (e.g. point, spotlights) with banded toon effect
- - For shadows to work in the Unlit Graph, the following keywords must be defined in the blackboard :
- - Boolean Keyword, Global Multi-Compile "_ADDITIONAL_LIGHT_SHADOWS"
- - Boolean Keyword, Global Multi-Compile "_ADDITIONAL_LIGHTS" (required to prevent the one above from being stripped from builds)
- - For a PBR/Lit Graph, these keywords are already handled for you.
- */
- void AdditionalLightsToon_float(float3 SpecColor, float Smoothness, float3 WorldPosition, float3 WorldNormal, float3 WorldView, half4 Shadowmask,
- float PointLightBands, float SpotLightBands,
- out float3 Diffuse, out float3 Specular) {
- float3 diffuseColor = 0;
- float3 specularColor = 0;
- #ifndef SHADERGRAPH_PREVIEW
- Smoothness = exp2(10 * Smoothness + 1);
- uint pixelLightCount = GetAdditionalLightsCount();
- uint meshRenderingLayers = GetMeshRenderingLayer();
- #if USE_FORWARD_PLUS
- for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++) {
- FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
- Light light = GetAdditionalLight(lightIndex, WorldPosition, Shadowmask);
- #ifdef _LIGHT_LAYERS
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- #endif
- {
- if (PointLightBands <= 1 && SpotLightBands <= 1){
- // Solid colour lights
- diffuseColor += light.color * step(0.0001, light.distanceAttenuation * light.shadowAttenuation);
- }else{
- // Multiple bands
- diffuseColor += light.color * light.shadowAttenuation * ToonAttenuation(lightIndex, WorldPosition, PointLightBands, SpotLightBands);
- }
- }
- }
- #endif
- // For Foward+ the LIGHT_LOOP_BEGIN macro will use inputData.normalizedScreenSpaceUV, inputData.positionWS, so create that:
- InputData inputData = (InputData)0;
- float4 screenPos = ComputeScreenPos(TransformWorldToHClip(WorldPosition));
- inputData.normalizedScreenSpaceUV = screenPos.xy / screenPos.w;
- inputData.positionWS = WorldPosition;
- LIGHT_LOOP_BEGIN(pixelLightCount)
- Light light = GetAdditionalLight(lightIndex, WorldPosition, Shadowmask);
- #ifdef _LIGHT_LAYERS
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- #endif
- {
- if (PointLightBands <= 1 && SpotLightBands <= 1){
- // Solid colour lights
- diffuseColor += light.color * step(0.0001, light.distanceAttenuation * light.shadowAttenuation);
- }else{
- // Multiple bands
- diffuseColor += light.color * light.shadowAttenuation * ToonAttenuation(lightIndex, WorldPosition, PointLightBands, SpotLightBands);
- }
- }
- LIGHT_LOOP_END
- #endif
- /*
- #ifndef SHADERGRAPH_PREVIEW
- Smoothness = exp2(10 * Smoothness + 1);
- WorldNormal = normalize(WorldNormal);
- WorldView = SafeNormalize(WorldView);
- int pixelLightCount = GetAdditionalLightsCount();
- for (int i = 0; i < pixelLightCount; ++i) {
- Light light = GetAdditionalLight(i, WorldPosition, Shadowmask);
- // DIFFUSE
- if (PointLightBands <= 1 && SpotLightBands <= 1){
- // Solid colour lights
- diffuseColor += light.color * step(0.0001, light.distanceAttenuation * light.shadowAttenuation);
- }else{
- // Multiple bands :
- diffuseColor += light.color * light.shadowAttenuation * ToonAttenuation(i, WorldPosition, PointLightBands, SpotLightBands);
- }
- }
- #endif
- */
- Diffuse = diffuseColor;
- Specular = specularColor;
- // Didn't really like the look of specular lighting in the toon shader here, so just keeping it at 0
- }
- // For backwards compatibility (before Shadowmask was introduced)
- void AdditionalLightsToon_float(float3 SpecColor, float Smoothness, float3 WorldPosition, float3 WorldNormal, float3 WorldView,
- float PointLightBands, float SpotLightBands,
- out float3 Diffuse, out float3 Specular) {
- AdditionalLightsToon_float(SpecColor, Smoothness, WorldPosition, WorldNormal, WorldView, half4(1,1,1,1),
- PointLightBands, SpotLightBands,Diffuse, Specular);
- }
- //------------------------------------------------------------------------------------------------------
- // Additional Lights Zelda
- //------------------------------------------------------------------------------------------------------
- void AdditionaLightZelda_float(float3 WorldPosition, float3 WorldNormal, float3 WorldView, half4 Shadowmask, float LightStep,
- out float LightMask, out float3 LightColor, out float3 Specular) {
- float lightMask = 0;
- float3 lightColor = 0;
- float3 specularColor = 0;
- #ifndef SHADERGRAPH_PREVIEW
- uint pixelLightCount = GetAdditionalLightsCount();
- uint meshRenderingLayers = GetMeshRenderingLayer();
- //TODO: Fix the Forward Plus block
-
- #if USE_FORWARD_PLUS
- for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++) {
- FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
- Light light = GetAdditionalLight(0, WorldPosition, Shadowmask);
- #ifdef _LIGHT_LAYERS
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- #endif
- {
- float adjustedContribution = step(LightStep, dot(light.direction, WorldNormal));
- lightMask = step(0.001, light.distanceAttenuation) * adjustedContribution; //this distance-based step function makes the light full brightness within its range/gizmo
- lightColor = light.color;
- }
- }
- #endif
- // For Foward+ the LIGHT_LOOP_BEGIN macro will use inputData.normalizedScreenSpaceUV, inputData.positionWS, so create that:
- InputData inputData = (InputData)0;
- float4 screenPos = ComputeScreenPos(TransformWorldToHClip(WorldPosition));
- inputData.normalizedScreenSpaceUV = screenPos.xy / screenPos.w;
- inputData.positionWS = WorldPosition;
- LIGHT_LOOP_BEGIN(min(1, pixelLightCount))
- Light light = GetAdditionalLight(0, WorldPosition, Shadowmask);
- #ifdef _LIGHT_LAYERS
- if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
- #endif
- {
- float adjustedContribution = step(LightStep, dot(light.direction, WorldNormal));
- lightMask = step(0.001, light.distanceAttenuation) * adjustedContribution; //this distance-based step function makes the light full brightness within its range/gizmo
- lightColor = light.color;
- }
- LIGHT_LOOP_END
- #endif
- LightColor = lightColor;
- LightMask = lightMask;
- Specular = specularColor;
- }
- // For backwards compatibility (before Shadowmask was introduced)
- void AdditionaLightZelda_float(float3 WorldPosition, float3 WorldNormal, float3 WorldView, float LightStep,
- out float LightMask, out float3 LightColor, out float3 Specular)
- {
- AdditionaLightZelda_float(WorldPosition, WorldNormal, WorldView, half4(1,1,1,1), LightStep,
- LightMask, LightColor, Specular);
- }
- #endif // CUSTOM_LIGHTING_INCLUDED
|