Dear Hivemind!
I just took my first steps into the wonderful world of shaders and immediately stepped into the bear trap of confusion. Anyway I was creating a shader that could blend between two textures based on the light information.
To be more precise:
-
if an object is in the shadows it should show Texture A
-
if an object is fully lit it should show Texture B
-
if an object is in between it should blend it with an amount of 50%
I approached this shader is by using a grabpass to write the lighting information to a texture and then using that texture to blend between two textures. This works without a hitch with a directional light and it also ALMOST works with a point light except for this issue:
- When you move the camera the texture flickers between the two textures. As you can see it does not appear to happen randomly since it happens at some fixed points in space.
- It does not happen when I only have one object in the space.
- The framedebugger shows that the render order of the object changes.
- The flickering is caused by the grab pass.
Here is my shadercode:
Shader "Custom/LightBlend"
{
Properties
{
_LightTex("Light Texture", 2D) = "white" {}
_LightColor("Light Tint", Color) = (1,1,1,1)
_ShadowTex("Shadow Texture", 2D) = "white" {}
_ShadowColor("Shadow Tint", Color) = (1,1,1,1)
_BlendStrength("Blend Strength", Range(1,8))= 1
}
// Calculate lighting in this pass
SubShader{
Tags{ "RenderType" = "Opaque""Queue" = "Background"}
CGPROGRAM
#pragma surface surf LightPass fullforwardshadows
struct Input
{
float2 uv_LightTex;
};
float _BlendStrength;
float4 LightingLightPass(SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot(s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * (NdotL * atten * _BlendStrength);
return c;
}
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = float4(1,1,1,1);
}
ENDCG
//Calculate blending in this pass
GrabPass{ "_LightingGrab" }
Tags{"RenderType" = "Opaque" "Queue" = "Background" }
Lighting Off
CGPROGRAM
#pragma surface surf Unlit vertex:vert
#pragma debug
sampler2D _LightingGrab;
sampler2D _LightTex;
sampler2D _ShadowTex;
half4 _LightColor;
half4 _ShadowColor;
struct Input {
float2 uv_LightTex;
float2 uv_ShadowTex;
float4 grabUV;
};
void vert(inout appdata_full v, out Input o) {
// Calculate grab uv's
UNITY_INITIALIZE_OUTPUT(Input, o);
float4 hpos = UnityObjectToClipPos(v.vertex);
o.grabUV = ComputeGrabScreenPos(hpos);
}
half4 LightingUnlit(SurfaceOutput s, half3 lightDir, half atten) {
half4 c;
c.rgb = s.Albedo;
//c.a = s.Alpha;
return c;
}
void surf(Input IN, inout SurfaceOutput o) {
half4 _GrabTex = tex2Dproj(_LightingGrab, UNITY_PROJ_COORD(IN.grabUV));
half4 lightTex = tex2D(_LightTex, IN.uv_LightTex)*_LightColor;
half4 shadowTex = tex2D(_ShadowTex, IN.uv_ShadowTex) * _ShadowColor;
o.Albedo = lerp(shadowTex, lightTex, _GrabTex);
}
ENDCG
}
Fallback "Diffuse"
}
Now I’m not sure if this is a bug or that I’m doing something wrong or a bit of both. But if anyone could point me in the right direction it would be much appreciated even if someone has a better way to go about this!
THANKS!
Daniel
PS it’s a shader I’m using for my VR projects which is why I use forward rendering.