- Home /
Shader mesh not being effected by directional lights?
I've written a simple shader which takes two heightmaps and distorts a flat plane mesh accordingly. You can find this below:
Shader "Extrusion" {
Properties {
_WaveTex ("Texture", 2D) = "white" {}
_HeightTex ("Texture", 2D) = "white" {}
_Amount ("Height Extrusion Amount", Range(-1,1)) = 0.5
_WaveAmount ("Wave Extrusion Amount", Range(-1,1)) = 0.5
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:vert nolightmap
struct Input {
float2 uv_HeightTex;
};
sampler2D _WaveTex;
sampler2D _HeightTex;
sampler2D _OutputTex;
float _Amount;
float _WaveAmount;
void vert (inout appdata_full v) {
float4 waveTex = tex2Dlod (_WaveTex, float4(v.texcoord.xy,0,0));
float4 heightTex = tex2Dlod (_HeightTex, float4(v.texcoord.xy,0,0));
v.vertex.y += ((waveTex.b * _WaveAmount) + (heightTex.b * _Amount)) / 2.0;
}
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = 1.0;
}
ENDCG
}
Fallback "Diffuse"
}
The weird thing is that it doesn't seem to interact correctly with directional lights. The entire distorted plane is a uniform single colour - even in areas where you'd expect the light to be much darker such as cracks and crevices. This isn't the case when a point light is placed near to the plane, then it is shaded as you'd expect.
Erroneous uniform colour (directional light):
Interestingly, the plane is definitely receiving the directional light because if I rotate it around then the lighting changes - it's just always a completely uniform colour!
Any help would be greatly appreciated - I'm really tearing my hair out over it!
Answer by Eno-Khaon · Mar 16, 2016 at 08:26 AM
You're modifying the vertex positions on the mesh, but you aren't making the same adjustments for the normals.
If you want to generate appropriate lighting in the vertex shader to work with the vertex positions, you'll need some more texture samples.
//
// Y
// |
// O---X
//
Consider the "O" to be the pixel you're currently sampling on your texture. The "X", then, is the neighboring pixel at float4(v.texcoord.x + _WaveHeight_TexelSize.x, v.texcoord.y, 0, 0)
. The "Y" is the same, adjusted accordingly. http://forum.unity3d.com/threads/_maintex_texelsize-whats-the-meaning.110278/
Once you've established your variations of waveTex, waveTexPlusX and waveTexPlusY (and heightTex, by association), you take the cross product of them to get a new normal.
// Names shortened for simplicity (waveTex -> wt)
float3 newNormal = normalize(cross(wtpY - wt, wtpX - wt));
Hope this gets you started in the right direction!
Thanks for the reply! $$anonymous$$uch appreciated, great explanation too, though I can't quite get it working. So you're saying my code block would now be (ignoring the waves for now):
float4 heightTexPlusX = tex2Dlod( _HeightTex, float4(v.texcoord.x + _HeightTex_TexelSize.x, v.texcoord.y, 0, 0) );
float4 heightTexPlusY = tex2Dlod( _HeightTex, float4(v.texcoord.x, v.texcoord.y + _HeightTex_TexelSize.y, 0, 0) );
float3 hNormal = normalize(cross( heightTexPlusY-heightTex, heightTexPlusX-heightTex));
v.normal = hNormal;
Because the resultant shading it generates is a little funky strangely enough!
Well, admittedly, my example would be a little bit off. If you intend to provide further accuracy to the normals, you'll want a texture sample from every side rather than just from two, so you'd wind up with 5 texture samples per pixel (center one for its own color, if applicable, and then cross((y+1 - y-1), (x+1 - x-1))
for the normals).
The more accuracy you want, the more expensive it becomes, since 3/6 texture lookups is plenty less expensive than 5/10 (using one or two interpolated normals from them).
I think - aside from the inaccuracy - there's a problem with the logic (perhaps my misunderstanding?). The shading that it generates is very wrong - so with the Unity "default-particle" used as the input for example it generates the following image (A single directional light is placed directly above):
To me it looks like half of the normals face "up" and half of them face "down"? Very peculiar because I'm pretty sure I understand the logic you proposed! Is there anything obvious I've done wrong per chance? Thanks again for the support by the way!
Your answer
Follow this Question
Related Questions
Best Way to Implement an Exaggerated Horizon Curve to 3D Endless Runner? 0 Answers
InnerGlow Shader for Polygons 0 Answers
Simulating horizon curvature 1 Answer
How to determine shader center? 0 Answers