-
-
Save NedMakesGames/13e64bed3a84e81826b05e5fb0214e70 to your computer and use it in GitHub Desktop.
https://youtu.be/GQyCPaThQnA or https://nedmakesgames.medium.com/creating-custom-lighting-in-unitys-shader-graph-with-universal-render-pipeline-5ad442c27276
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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