Skip to content

Instantly share code, notes, and snippets.

@Hotrian
Last active January 2, 2025 23:53
Show Gist options
  • Save Hotrian/d8c7187947df511b672214c1ed8d7242 to your computer and use it in GitHub Desktop.
Save Hotrian/d8c7187947df511b672214c1ed8d7242 to your computer and use it in GitHub Desktop.

Version 2 is out now

Automatic texture desaturation with Unity Light System original color reveal - Textures are converted in realtime to grayscale and Point/Directional/Spot lights reveal the original color of a texture.

img

Quick Example Vid on YouTube

More details in this comment thread probably

Shader "Custom/ColorByLight"
{
Properties
{
_BaseIsMultiplicative ("Base Color Is Multiplicative (1.0 == true)", Range(0, 1)) = 1.0
[HDR] _BaseColor ("Color", Color) = (1,1,1,1)
_BaseMap ("Texture", 2D) = "white" {}
_AmbientIsMultiplicative ("Ambient Is Multiplicative (1.0 == true)", Range(0, 1)) = 0.0
_AmbientMultLuminosity ("Ambient Light Mult (Luminosity)", Range(0, 2)) = 1.0
_AmbientMultColor ("Ambient Light Mult (Color)", Range(0, 2)) = 0.0
_SunIsMultiplicative ("Sun Is Multiplicative (1.0 == true)", Range(0, 1)) = 1.0
_SunMultReveal ("Sun Mult (Reveal)", Range(0, 2)) = 0
_SunMultColor ("Sun Mult (Color)", Range(0, 2)) = 1
_LightMultReveal ("Light Mult (Reveal)", Range(0, 200)) = 100
_LightMultColor ("Light Mult (Color)", Range(0, 2)) = 0
_ClampIntensityMax ("Clamp Intensity (Max)", Range(0, 2)) = 1
}
SubShader
{
Tags { "RenderPipeline" = "UniversalRenderPipeline" }
Pass
{
Name "ForwardLit"
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes
{
float3 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float3 worldPosition : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float2 uv : TEXCOORD2;
};
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
float4 _BaseColor;
float _BaseIsMultiplicative;
float _AmbientIsMultiplicative;
float _AmbientMultLuminosity;
float _AmbientMultColor;
float _SunIsMultiplicative;
float _SunMultReveal;
float _SunMultColor;
float _LightMultReveal;
float _LightMultColor;
float _ClampIntensityMax;
Varyings vert(Attributes IN)
{
// Here we just convert World Space stuff to Object/Texture Space
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS);
OUT.worldPosition = TransformObjectToWorld(IN.positionOS);
OUT.worldNormal = TransformObjectToWorldNormal(IN.normalOS);
OUT.uv = IN.uv;
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
float3 normalWS = normalize(IN.worldNormal);
float4 sampledColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
// Get the Main Light (usually the Sun / first Directional Light which casts shadows)
Light mainLight = GetMainLight();
float mainLightNdotL = max(dot(normalWS, mainLight.direction), 0.0);
float3 mainLightDiffuse = mainLight.color * mainLightNdotL;
float mainLightIntensity = dot(mainLight.color, float3(0.299, 0.587, 0.114)) * mainLightNdotL;
// Calculate the effective Intensity
float intensity = (mainLightIntensity * _SunMultReveal);
float3 lightDiffuse = float3(0, 0, 0);
for (int i = 0; i < GetAdditionalLightsCount(); i++)
{
Light additionalLight = GetAdditionalPerObjectLight(i, IN.worldPosition);
float NdotL = max(dot(normalWS, additionalLight.direction), 0.0); // Calculate N·L (Lambertian shading)
lightDiffuse += additionalLight.color * NdotL * additionalLight.distanceAttenuation;
float lightIntensity = dot(additionalLight.color, float3(0.299, 0.587, 0.114)) * NdotL * additionalLight.distanceAttenuation;
if (lightIntensity <= 0.0) continue;
intensity += (lightIntensity * _LightMultReveal);
}
intensity = clamp(intensity, 0, _ClampIntensityMax);
// Calculate the Ambient Lighting, and use its Luminosity as the base brightness
float4 ambientLight = float4(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w, 1);
float ambientLuminosity = saturate(dot(ambientLight.rgb, float3(0.2126, 0.7152, 0.0722))) * _AmbientMultLuminosity;
// Calculate the Grayscale color (Luminosity method) and interpolate between that and the full color based on the effective light Intensity
float gsColor = dot(sampledColor.rgb, half3(0.299, 0.587, 0.114)) * ambientLuminosity;
float r = lerp(gsColor, sampledColor.r * ambientLuminosity, intensity);
float g = lerp(gsColor, sampledColor.g * ambientLuminosity, intensity);
float b = lerp(gsColor, sampledColor.b * ambientLuminosity, intensity);
// Multiplicative Sun looks better IMO, but depends on game style, lighting, etc
if (_BaseIsMultiplicative >= 1)
{
if (_SunIsMultiplicative >= 1)
{
if (_AmbientIsMultiplicative >= 1)
{
// Base Color Multiplicative, Ambient Multiplicative, Sun Multiplicative
return (float4(r, g, b, 1) * _BaseColor * float4(mainLightDiffuse, 1) * _SunMultColor * ambientLight * _AmbientMultColor) + (float4(lightDiffuse, 1) * _LightMultColor);
}
// Base Color Multiplicative, Ambient Additive, Sun Multiplicative
return (float4(r, g, b, 1) * _BaseColor * float4(mainLightDiffuse, 1) * _SunMultColor) + (float4(lightDiffuse, 1) * _LightMultColor) + (ambientLight * _AmbientMultColor);
}
// Base Color Multiplicative, Ambient Additive, Sun Additive
return (float4(r, g, b, 1) * _BaseColor) + (float4(mainLightDiffuse, 1) * _SunMultColor) + (float4(lightDiffuse, 1) * _LightMultColor);
}
if (_SunIsMultiplicative >= 1)
{
if (_AmbientIsMultiplicative >= 1)
{
// Base Color Additive, Ambient Multiplicative, Sun Multiplicative
return (float4(r, g, b, 1) * float4(mainLightDiffuse, 1) * _SunMultColor * ambientLight * _AmbientMultColor) + (float4(lightDiffuse, 1) * _LightMultColor) + _BaseColor;
}
// Base Color Additive, Ambient Additive, Sun Multiplicative
return (float4(r, g, b, 1) * float4(mainLightDiffuse, 1) * _SunMultColor) + (float4(lightDiffuse, 1) * _LightMultColor) + (ambientLight * _AmbientMultColor) + _BaseColor;
}
// Base Color Additive, Ambient Additive, Sun Additive
return (float4(r, g, b, 1)) + (float4(mainLightDiffuse, 1) * _SunMultColor) + (float4(lightDiffuse, 1) * _LightMultColor) + _BaseColor;
}
ENDHLSL
}
}
FallBack "Lit"
CustomEditor "ColorByLightInspector"
}
using UnityEditor;
public class ColorByLightInspector : ShaderGUI
{
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
// Iterate over all properties
foreach (var property in properties)
{
switch (property.name)
{
case "_BaseIsMultiplicative":
{
// Display as a toggle
EditorGUI.BeginChangeCheck();
var toggleValue = EditorGUILayout.Toggle("Base Color Is Multiplicative", property.floatValue > 0.5f);
if (EditorGUI.EndChangeCheck())
{
property.floatValue = toggleValue ? 1.0f : 0.0f; // Set the property value based on the toggle
}
break;
}
case "_AmbientIsMultiplicative":
{
// Display as a toggle
EditorGUI.BeginChangeCheck();
var toggleValue = EditorGUILayout.Toggle("Ambient Is Multiplicative", property.floatValue > 0.5f);
if (EditorGUI.EndChangeCheck())
{
property.floatValue = toggleValue ? 1.0f : 0.0f; // Set the property value based on the toggle
}
break;
}
case "_SunIsMultiplicative":
{
// Display as a toggle
EditorGUI.BeginChangeCheck();
var toggleValue = EditorGUILayout.Toggle("Sun Is Multiplicative", property.floatValue > 0.5f);
if (EditorGUI.EndChangeCheck())
{
property.floatValue = toggleValue ? 1.0f : 0.0f; // Set the property value based on the toggle
}
break;
}
default:
// Render other properties normally
materialEditor.ShaderProperty(property, property.displayName);
break;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment