Hey everyone!
I’m going to preface this with the fact that I have scoured the world wide web in search of answers on this one, and I’ve actually found some. But the issue is I either can’t seem to get them to work correctly, or I don’t fully understand them. I’m new to graphics relatively, I have a background in CS, and I’ve been learning shaders and CG for a couple months now. I’m also not a bad modeler and I’m super familiar with unity on the editor and C# side.
So anyway, I just cannot get this effect to work. First of all, a picture of the witness:
So these look super cool, I’ve seen this look in a few other games, etc. They give this feel of almost an impressionist painting - it’s awesome. So now into what I have heard about how to do this:
- You gotta correct your normals with something like normal theif in 3dsmax or normal edit in blender
- Write a shader that essentially drops the alpha in relation to the view direction (normal dot view dir) to fade out quads with their edges facing the camera
- Add to that shader AlphaToMask with 4x MSAA
So here’s what I’ve got:
- Corrected normals with standard surface shader (This looks kinda good but trust me, this is a perfect angle, the whole seeing the quad edges is a huge issue here, plus some other thing I’m not stoked on)
So first off, you can still totally see the quad edges, each seems to basically have their shadows, making it rather obvious we have a bunch of quads on a stick. Right off the bat - should the normal transfer (from an elliptic uv sphere) be fixing that? did I do that part wrong somehow? This is clearly way better than the quads without doing the normal correction I did. It’s like if we could just blend/smooth this all out somehow it would work pretty well… But still In the witness and other games like it, you seriously can barely tell they are using quads with leaf textures - how do they get that? Possibly the AlphaToMask thing? Let’s continue…
Okay lets’s try that shader idea…
Shader "Nature/Witness/leaves"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.5
_EdgeTransparency ("Edge Transparency Factor", Range(0,1)) = 3
}
SubShader
{
Tags
{
"Queue"="AlphaTest"
"IgnoreProjector"="True"
"RenderType"="TransparentCutout"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
LOD 200
Cull Off
Lighting On
AlphaToMask On
CGPROGRAM
#pragma surface surf Lambert addshadow alphatest:_Cutoff
sampler2D _MainTex;
fixed4 _Color;
float _EdgeTransparency;
struct Input
{
float2 uv_MainTex;
float3 viewDir;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
// normal shader
o.Albedo = c.rgb;
o.Alpha = c.a;
o.Alpha *= 1.0 - (dot (normalize(IN.viewDir), o.Normal)*_EdgeTransparency);
// this is what I used in the test video with the white/black showing normal dot view
//o.Albedo = 1.0 - (dot (normalize(IN.viewDir), o.Normal)*_EdgeTransparency);;
//o.Alpha = 1;
}
ENDCG
}
Fallback "Legacy Shaders/Transparent/Cutout/VertexLit"
Dependency "OptimizedShader" = "Hidden/Nature/Tree Creator Leaves Fast Optimized"
}
So here’s my shader - pretty straightforward, using a surface shader, gunna drop the alpha based on the normal-dot-view like was proposed across the internet I think first appearing on the witness dev blog.
But here’s the issue. I corrected all the normals. So it’s not going to fade out the weird edges of the quads anymore, it’s just gunna fade out whatever is right in front of me. With uncorrected normals, this technique actually works BETTER. Here’s a test I did to show my math is working, this is just passing that dot calculation line straight to albedo:
So this is basically what I just said would happen - it’s just fading out based on the corrected normals, which is not really the reason we were doing this whole fade out edges quads. Basically this is just ends up cutting out a piece of the tree in front of the cam it looks exactly like we have the camera’s clipping distance set super high. AlphaToMask is in there, from what I can tell that was basically inconsequential.
So from what I can tell, the standard shader is working the best - is there something I’m not getting about this technique? How do you get that billboard-esque effect without actually billboarding and having all the terrible artifacts that would come with it? It looks so simple, hence why I thought I might try it, but it’s turning out to be quite a mystery…
Any help would be greatly appreciated! Thanks in advance!