Problem:
I wrote a custom shader for making animated sprites from a sprite sheet (not going into why I’m doing that rather than use Unity’s animation player for this project”).
It works well, but the shadows casted are of the complete sprite sheet, not the current cell displayed in the surf method. So for example, if there is a sprite sheet with 4 frames. Instead of the shadow being cast by the current frame, you’ll see 4 individual shadows for each frame of the sheet.
Image Example
I can change the “Tile” and “Offset” values in the material properties to correct the shadows.
But that would require logic on the cpu side to update them and would need to be synched with the shader.
Question:
Is there a way to keep this purely in the shader and have correct shadows?
Here’s the attached shader:
Shader "Custom/Pixel_Sprite_Diffuse"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_Cutoff("Cutoff", Range(0, 1)) = 0.5
[ToggleOff] _SpecularHighlights ("Specular Highlights", Float) = 1.000000
[ToggleOff] _GlossyReflections ("Glossy Reflections", Float) = 1.000000
cell_x_count("Cell Count X", float) = 1
cell_y_count("Cell Count Y", float) = 1
frame_count("Frame Count", float) = 1
speed("Speed", float) = 1
}
SubShader
{
Tags{ "RenderType" = "TransparentCutout" "Queue" = "Transparent"}
ZWrite Off
//Tags{ "RenderType" = "Transparent" "Queue" = "TransparentCutout"}
//ZWrite Off Blend SrcAlpha OneMinusSrcAlpha
LOD 300
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard alphatest:_Cutoff
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
float _SpecularHighlights;
float _GlossyReflections;
fixed4 _Color;
float frame_count;
float cell_x_count;
float cell_y_count;
float speed;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o)
{
int currentIndex = (int)
(((float)_Time * speed * 20) % frame_count);
float2 cellSize
= float2(
1.0 / cell_x_count,
1.0 / cell_y_count
);
const float2 offset = float2
(
((float)currentIndex % cell_x_count) / cell_x_count,
1 - (1 * floor(2.0 * (float)currentIndex * cellSize.x * cellSize.y))
);
const float2 cellCoord =
float2(
IN.uv_MainTex.x * cellSize.x,
-(1 - IN.uv_MainTex.y) * cellSize.y
);
const float2 samplePoint = offset + cellCoord;
float4 color = tex2D(_MainTex, samplePoint);
if( color.a < .01)
{
discard;
}
o.Albedo = color.rgb;
o.Alpha = color.a;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
}
ENDCG
}
FallBack "Standard"
}
I’ve previously made a script solution to update the “tile” and “offset” on the materials to create he illusion of animation which largely worked, but is less simple to setup than a simple shader.
Marco Flores is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.