Skip to content

Instantly share code, notes, and snippets.

@NedMakesGames
Last active January 21, 2024 15:38
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save NedMakesGames/13e64bed3a84e81826b05e5fb0214e70 to your computer and use it in GitHub Desktop.
Save NedMakesGames/13e64bed3a84e81826b05e5fb0214e70 to your computer and use it in GitHub Desktop.
// MIT License
// Copyright (c) 2021 NedMakesGames
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef CUSTOM_LIGHTING_INCLUDED
#define CUSTOM_LIGHTING_INCLUDED
// This is a neat trick to work around a bug in the shader graph when
// enabling shadow keywords. Created by @cyanilux
// https://github.com/Cyanilux/URP_ShaderGraphCustomLighting
// Licensed under the MIT License, Copyright (c) 2020 Cyanilux
#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
struct CustomLightingData {
// Position and orientation
float3 positionWS;
float3 normalWS;
float3 viewDirectionWS;
float4 shadowCoord;
// Surface attributes
float3 albedo;
float smoothness;
float ambientOcclusion;
// Baked lighting
float3 bakedGI;
float4 shadowMask;
float fogFactor;
};
// Translate a [0, 1] smoothness value to an exponent
float GetSmoothnessPower(float rawSmoothness) {
return exp2(10 * rawSmoothness + 1);
}
#ifndef SHADERGRAPH_PREVIEW
float3 CustomGlobalIllumination(CustomLightingData d) {
float3 indirectDiffuse = d.albedo * d.bakedGI * d.ambientOcclusion;
float3 reflectVector = reflect(-d.viewDirectionWS, d.normalWS);
// This is a rim light term, making reflections stronger along
// the edges of view
float fresnel = Pow4(1 - saturate(dot(d.viewDirectionWS, d.normalWS)));
// This function samples the baked reflections cubemap
// It is located in URP/ShaderLibrary/Lighting.hlsl
float3 indirectSpecular = GlossyEnvironmentReflection(reflectVector,
RoughnessToPerceptualRoughness(1 - d.smoothness),
d.ambientOcclusion) * fresnel;
return indirectDiffuse + indirectSpecular;
}
float3 CustomLightHandling(CustomLightingData d, Light light) {
float3 radiance = light.color * (light.distanceAttenuation * light.shadowAttenuation);
float diffuse = saturate(dot(d.normalWS, light.direction));
float specularDot = saturate(dot(d.normalWS, normalize(light.direction + d.viewDirectionWS)));
float specular = pow(specularDot, GetSmoothnessPower(d.smoothness)) * diffuse;
float3 color = d.albedo * radiance * (diffuse + specular);
return color;
}
#endif
float3 CalculateCustomLighting(CustomLightingData d) {
#ifdef SHADERGRAPH_PREVIEW
// In preview, estimate diffuse + specular
float3 lightDir = float3(0.5, 0.5, 0);
float intensity = saturate(dot(d.normalWS, lightDir)) +
pow(saturate(dot(d.normalWS, normalize(d.viewDirectionWS + lightDir))), GetSmoothnessPower(d.smoothness));
return d.albedo * intensity;
#else
// Get the main light. Located in URP/ShaderLibrary/Lighting.hlsl
Light mainLight = GetMainLight(d.shadowCoord, d.positionWS, d.shadowMask);
// In mixed subtractive baked lights, the main light must be subtracted
// from the bakedGI value. This function in URP/ShaderLibrary/Lighting.hlsl takes care of that.
MixRealtimeAndBakedGI(mainLight, d.normalWS, d.bakedGI);
float3 color = CustomGlobalIllumination(d);
// Shade the main light
color += CustomLightHandling(d, mainLight);
#ifdef _ADDITIONAL_LIGHTS
// Shade additional cone and point lights. Functions in URP/ShaderLibrary/Lighting.hlsl
uint numAdditionalLights = GetAdditionalLightsCount();
for (uint lightI = 0; lightI < numAdditionalLights; lightI++) {
Light light = GetAdditionalLight(lightI, d.positionWS, d.shadowMask);
color += CustomLightHandling(d, light);
}
#endif
color = MixFog(color, d.fogFactor);
return color;
#endif
}
void CalculateCustomLighting_float(float3 Position, float3 Normal, float3 ViewDirection,
float3 Albedo, float Smoothness, float AmbientOcclusion,
float2 LightmapUV,
out float3 Color) {
CustomLightingData d;
d.positionWS = Position;
d.normalWS = Normal;
d.viewDirectionWS = ViewDirection;
d.albedo = Albedo;
d.smoothness = Smoothness;
d.ambientOcclusion = AmbientOcclusion;
#ifdef SHADERGRAPH_PREVIEW
// In preview, there's no shadows or bakedGI
d.shadowCoord = 0;
d.bakedGI = 0;
d.shadowMask = 0;
d.fogFactor = 0;
#else
// Calculate the main light shadow coord
// There are two types depending on if cascades are enabled
float4 positionCS = TransformWorldToHClip(Position);
#if SHADOWS_SCREEN
d.shadowCoord = ComputeScreenPos(positionCS);
#else
d.shadowCoord = TransformWorldToShadowCoord(Position);
#endif
// The following URP functions and macros are all located in
// URP/ShaderLibrary/Lighting.hlsl
// Technically, OUTPUT_LIGHTMAP_UV, OUTPUT_SH and ComputeFogFactor
// should be called in the vertex function of the shader. However, as of
// 2021.1, we do not have access to custom interpolators in the shader graph.
// The lightmap UV is usually in TEXCOORD1
// If lightmaps are disabled, OUTPUT_LIGHTMAP_UV does nothing
float2 lightmapUV;
OUTPUT_LIGHTMAP_UV(LightmapUV, unity_LightmapST, lightmapUV);
// Samples spherical harmonics, which encode light probe data
float3 vertexSH;
OUTPUT_SH(Normal, vertexSH);
// This function calculates the final baked lighting from light maps or probes
d.bakedGI = SAMPLE_GI(lightmapUV, vertexSH, Normal);
// This function calculates the shadow mask if baked shadows are enabled
d.shadowMask = SAMPLE_SHADOWMASK(lightmapUV);
// This returns 0 if fog is turned off
// It is not the same as the fog node in the shader graph
d.fogFactor = ComputeFogFactor(positionCS.z);
#endif
Color = CalculateCustomLighting(d);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment