I’m on Unity. I’m not very experienced with shaders nor shader graphs, but I managed to get this one to work on URP. Currently I’m changing the light intensity or brightness "manually" with the _LightIntensity
variable. But this shader applied to a material in a sprite renderer is not being affected by URP 2D lights, like global, shape light, unless they are volumetric. When I place one of those 2D URP lights on top of the sprite in the scene, lights wont make brighter parts of the sprite. Any way I can add to the code to make it affected by 2D lights?
Shader "Custom/URPTilemapLitHSV" { Properties { _MainTex ("Map", 2D) = "white" {} _Tileset("Tileset", 2D) = "white" {} _Size("Map & Tileset Size", Vector) = (16, 16, 20, 13) _LightIntensity("Light Intensity", Range(0, 5)) = 1 _HueShift("Hue Shift", Range(-180, 180)) = 0 _Saturation("Saturation", Range(0, 2)) = 1 _Brightness("Brightness", Range(0, 2)) = 1 } SubShader { Tags { "RenderPipeline" = "UniversalPipeline" "Queue" = "Transparent" } LOD 200 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 3.0 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" sampler2D _MainTex; sampler2D _Tileset; sampler2D _LightTex; float4 _Size; float _HueShift; float _Saturation; float _Brightness; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.uv = v.uv; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); return o; } float3 RGBtoHSV(float3 color) { float3 hsv; float minVal = min(min(color.r, color.g), color.b); float maxVal = max(max(color.r, color.g), color.b); hsv.z = maxVal; float delta = maxVal - minVal; if (maxVal > 0.0) { hsv.y = delta / maxVal; if (color.r >= maxVal) hsv.x = (color.g - color.b) / delta; else if (color.g >= maxVal) hsv.x = 2.0 + (color.b - color.r) / delta; else hsv.x = 4.0 + (color.r - color.g) / delta; hsv.x *= 60.0; if (hsv.x < 0.0) hsv.x += 360.0; } else { hsv.y = 0.0; hsv.x = 0.0; } return hsv; } float3 HSVtoRGB(float3 hsv) { float3 rgb; if (hsv.y == 0.0) { rgb = float3(hsv.z, hsv.z, hsv.z); } else { float hue = hsv.x / 60.0; int i = floor(hue); float f = hue - i; float p = hsv.z * (1.0 - hsv.y); float q = hsv.z * (1.0 - hsv.y * f); float t = hsv.z * (1.0 - hsv.y * (1.0 - f)); if (i == 0) rgb = float3(hsv.z, t, p); else if (i == 1) rgb = float3(q, hsv.z, p); else if (i == 2) rgb = float3(p, hsv.z, t); else if (i == 3) rgb = float3(p, q, hsv.z); else if (i == 4) rgb = float3(t, p, hsv.z); else rgb = float3(hsv.z, p, q); } return rgb; } float4 frag(v2f IN) : SV_Target { float2 mapLocation = IN.uv * _Size.xy; float2 inTileUV = frac(mapLocation); mapLocation = (mapLocation - inTileUV) / _Size.xy; inTileUV = inTileUV * 1275.0f / 1280.0f + 1.0f / 1280.0f; float4 grad = float4(ddx(IN.uv), ddy(IN.uv)); float4 tileIndex = tex2D(_MainTex, mapLocation); tileIndex = (tileIndex * 255.0f + inTileUV.xyxy) / _Size.zwzw; float4 over = tex2Dgrad(_Tileset, tileIndex.zw, grad.xy, grad.zw); float3 colorRGB = over.rgb; // Apply hue shift float3 colorHSV = RGBtoHSV(colorRGB); colorHSV.x += _HueShift; colorHSV.x = frac(colorHSV.x / 360.0) * 360.0; colorRGB = HSVtoRGB(colorHSV); // Apply saturation and brightness colorRGB = saturate(colorRGB * _Saturation) * _Brightness; float4 finalColor = float4(colorRGB, over.a); // Multiply by light intensity finalColor.rgb *= _LightIntensity; if (finalColor.a < 0.5) discard; return finalColor; } ENDHLSL } } FallBack "Diffuse" }
I looked into the URP sprite lit shader and it seems a very complex code can’t seem to get any ideas from it. It seems to differentiate the type of light that is applied be URP global, shape etc…
This is the Unity sprite lit Shader
Shader "Universal Render Pipeline/2D/Sprite-Lit-Default" { Properties { _MainTex("Diffuse", 2D) = "white" {} _MaskTex("Mask", 2D) = "white" {} _NormalMap("Normal Map", 2D) = "bump" {} // Legacy properties. They're here so that materials using this shader can gracefully fallback to the legacy sprite shader. [HideInInspector] _Color("Tint", Color) = (1,1,1,1) [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1) [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1) [HideInInspector] _AlphaTex("External Alpha", 2D) = "white" {} [HideInInspector] _EnableExternalAlpha("Enable External Alpha", Float) = 0 } SubShader { Tags {"Queue" = "Transparent" "RenderType" = "Transparent" "RenderPipeline" = "UniversalPipeline" } Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha Cull Off ZWrite Off Pass { Tags { "LightMode" = "Universal2D" } HLSLPROGRAM #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #pragma vertex CombinedShapeLightVertex #pragma fragment CombinedShapeLightFragment #pragma multi_compile USE_SHAPE_LIGHT_TYPE_0 __ #pragma multi_compile USE_SHAPE_LIGHT_TYPE_1 __ #pragma multi_compile USE_SHAPE_LIGHT_TYPE_2 __ #pragma multi_compile USE_SHAPE_LIGHT_TYPE_3 __ #pragma multi_compile _ DEBUG_DISPLAY struct Attributes { float3 positionOS : POSITION; float4 color : COLOR; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; half4 color : COLOR; float2 uv : TEXCOORD0; half2 lightingUV : TEXCOORD1; #if defined(DEBUG_DISPLAY) float3 positionWS : TEXCOORD2; #endif UNITY_VERTEX_OUTPUT_STEREO }; #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl" TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_MaskTex); SAMPLER(sampler_MaskTex); half4 _MainTex_ST; float4 _Color; half4 _RendererColor; #if USE_SHAPE_LIGHT_TYPE_0 SHAPE_LIGHT(0) #endif #if USE_SHAPE_LIGHT_TYPE_1 SHAPE_LIGHT(1) #endif #if USE_SHAPE_LIGHT_TYPE_2 SHAPE_LIGHT(2) #endif #if USE_SHAPE_LIGHT_TYPE_3 SHAPE_LIGHT(3) #endif Varyings CombinedShapeLightVertex(Attributes v) { Varyings o = (Varyings)0; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.positionCS = TransformObjectToHClip(v.positionOS); #if defined(DEBUG_DISPLAY) o.positionWS = TransformObjectToWorld(v.positionOS); #endif o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.lightingUV = half2(ComputeScreenPos(o.positionCS / o.positionCS.w).xy); o.color = v.color * _Color * _RendererColor; return o; } #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/CombinedShapeLightShared.hlsl" half4 CombinedShapeLightFragment(Varyings i) : SV_Target { const half4 main = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv); const half4 mask = SAMPLE_TEXTURE2D(_MaskTex, sampler_MaskTex, i.uv); SurfaceData2D surfaceData; InputData2D inputData; InitializeSurfaceData(main.rgb, main.a, mask, surfaceData); InitializeInputData(i.uv, i.lightingUV, inputData); return CombinedShapeLightShared(surfaceData, inputData); } ENDHLSL } Pass { Tags { "LightMode" = "NormalsRendering"} HLSLPROGRAM #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #pragma vertex NormalsRenderingVertex #pragma fragment NormalsRenderingFragment struct Attributes { float3 positionOS : POSITION; float4 color : COLOR; float2 uv : TEXCOORD0; float4 tangent : TANGENT; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; half4 color : COLOR; float2 uv : TEXCOORD0; half3 normalWS : TEXCOORD1; half3 tangentWS : TEXCOORD2; half3 bitangentWS : TEXCOORD3; UNITY_VERTEX_OUTPUT_STEREO }; TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); half4 _NormalMap_ST; // Is this the right way to do this? Varyings NormalsRenderingVertex(Attributes attributes) { Varyings o = (Varyings)0; UNITY_SETUP_INSTANCE_ID(attributes); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.positionCS = TransformObjectToHClip(attributes.positionOS); o.uv = TRANSFORM_TEX(attributes.uv, _NormalMap); o.color = attributes.color; o.normalWS = -GetViewForwardDir(); o.tangentWS = TransformObjectToWorldDir(attributes.tangent.xyz); o.bitangentWS = cross(o.normalWS, o.tangentWS) * attributes.tangent.w; return o; } #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/NormalsRenderingShared.hlsl" half4 NormalsRenderingFragment(Varyings i) : SV_Target { const half4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv); const half3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, i.uv)); return NormalsRenderingShared(mainTex, normalTS, i.tangentWS.xyz, i.bitangentWS.xyz, i.normalWS.xyz); } ENDHLSL } Pass { Tags { "LightMode" = "UniversalForward" "Queue"="Transparent" "RenderType"="Transparent"} HLSLPROGRAM #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #pragma vertex UnlitVertex #pragma fragment UnlitFragment struct Attributes { float3 positionOS : POSITION; float4 color : COLOR; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float4 color : COLOR; float2 uv : TEXCOORD0; #if defined(DEBUG_DISPLAY) float3 positionWS : TEXCOORD2; #endif UNITY_VERTEX_OUTPUT_STEREO }; TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); float4 _MainTex_ST; float4 _Color; half4 _RendererColor; Varyings UnlitVertex(Attributes attributes) { Varyings o = (Varyings)0; UNITY_SETUP_INSTANCE_ID(attributes); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.positionCS = TransformObjectToHClip(attributes.positionOS); #if defined(DEBUG_DISPLAY) o.positionWS = TransformObjectToWorld(v.positionOS); #endif o.uv = TRANSFORM_TEX(attributes.uv, _MainTex); o.color = attributes.color * _Color * _RendererColor; return o; } float4 UnlitFragment(Varyings i) : SV_Target { float4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv); #if defined(DEBUG_DISPLAY) SurfaceData2D surfaceData; InputData2D inputData; half4 debugColor = 0; InitializeSurfaceData(mainTex.rgb, mainTex.a, surfaceData); InitializeInputData(i.uv, inputData); SETUP_DEBUG_DATA_2D(inputData, i.positionWS); if(CanDebugOverrideOutputColor(surfaceData, inputData, debugColor)) { return debugColor; } #endif return mainTex; } ENDHLSL } } Fallback "Sprites/Default" }