This problem will be best described in a video so I’m posting it below.
Basically I have a quad renderer problem, in where a 2.5D character is drawn on screen as a custom material on a quad that’s generated at scene start.
Now, the problem is that this quad only has one side, so when the lighting is right it looks very beautiful because the sun is pointing right at it, but the trouble arises when you rotate the sun around to it’s back. From it’s back it obviously won’t have shadows casted on it’s textures pixels because the quad isn’t double sided.
The idea I had is that it would have a mirrored backface created and when the light is hitting it, or shadows are being drawn, it would mirror that to the front face.
I’m not looking for someone to do the work for me, just looking to see if anyone knows generally what a solution might be.
Here’s a video showing the problem:
I figured it out!
Flipping the normals using this shader code:
Shader "Astrah_Graphics/OObject" {
Properties {
_Brightness ("Brightness", Float) = 1
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
_Cutoff("Alpha cutoff", Range(0,1)) = 0.5
_FlipNormals("Flip Normals", Float) = 1
}
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
LOD 200
CGPROGRAM
#pragma surface surf Lambert alphatest:_Cutoff vertex:vert
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _Color;
float _Brightness;
struct Input {
float2 uv_MainTex;
};
float _FlipNormals;
void vert(inout appdata_full v) {
v.normal.xyz = v.normal * _FlipNormals;
}
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
c.r = c.r * _Brightness;
c.g = c.g * _Brightness;
c.b = c.b * _Brightness;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
Fallback "Legacy Shaders/Transparent/Cutout/VertexLit"
}
With this part in particular:
void vert(inout appdata_full v) {
v.normal.xyz = v.normal * _FlipNormals;
}
I can flip the normals from an external script like so. In my program ‘oGraphics’ refers to the game object that always faces towards the camera:
private void ProcessBackfaceShadowsFromMainLight() {
//This is all global rotation.eulerAngles not just .eulerAngles which is local...
float mainLight_y = manager.s_Scene.sceneMainLight.transform.rotation.eulerAngles.y;
float oGraphics_y = this.gameObject.transform.rotation.eulerAngles.y;
float remainder = mainLight_y - oGraphics_y;
if (remainder > -90 && remainder < 90)
{
quadRenderer.gO.GetComponent<Renderer>().sharedMaterial.SetFloat("_FlipNormals", -1);
} else
{
quadRenderer.gO.GetComponent<Renderer>().sharedMaterial.SetFloat("_FlipNormals", 1);
}
}
It’s not perfect, of course from the side the light won’t hit the quad, and my only solution to that is to create yet another light that hits the quads in the scene once it’s at a particular angle…well, too complex for me, so 50% of the time it’s correct. As long as it looks okay: