- Home /
How can I get correct lighting on a low poly water shader?
I have been working on this low poly water shader and I got each vertex to move up and down like I want to, I also got the shader to be transparent but I am having problems with lighting. If the metallic is set to 1, it is a solid color and I cant tell that the vertices are even moving in the center. The light hits the plane as if it was completely flat and leaves an object that was in the center a shadow of a flat line and not the way it is supposed to be. I am very new to shader writing so please correct me on anything else I did wrong. Here is my code:
Shader "Custom/LowPolyWater" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
_Glossiness("Smoothness", Range(0,1)) = 0
_Metallic("Metallic", Range(0,1)) = 0
_Speed("Speed", Range(0, 5)) = 1
_Scale("Scale", Range(0, 3)) = 0.3
_Amount("Amount", Range(0, 0.5)) = 0.1
}
SubShader {
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows alpha
#pragma vertex vert
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
half _Glossiness;
half _Metallic;
fixed4 _Color;
half _Speed;
half _Scale;
fixed _Amount;
struct Input {
float2 uv_MainTex;
};
void vert(inout appdata_full v, out Input o) {
//Idk why i usually need this but just in case
UNITY_INITIALIZE_OUTPUT(Input, o);
//I basically plugged functions and numbers in until something worked... my favorite meathod
v.vertex.y = (sin((_Time.w * _Speed) + v.vertex.x / _Amount) + sin((_Time.w * _Speed) + v.vertex.z / _Amount)) * _Scale;
}
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = _Color.a;
}
ENDCG
}
FallBack "Diffuse"
}
Answer by Namey5 · Jan 02, 2017 at 12:09 AM
This is because in a vertex shader there is no way to re-calculate normals after adjustment, meaning all the lighting, reflections, etc. still think that the plane is flat. There used to be some tricks around this, but they don't really work anymore. The only way to fix the normals would be to either calculate the displacement in a hull/domain shader (although these are essentially completely undocumented, and only work on DX10/11), or to calculate the displacement in a script (works a lot better, is the easiest, but has a higher performance impact). Either way would you to recalculate the normals, however.
As for the shader, you've got it pretty much right. The only thing I would comment on (which you pointed out) is the first line in the vertex function;
UNITY_INITIALIZE_OUTPUT(Input, o);
This is only necessary if you are passing any information to the surface function, which in this case you aren't so it isn't necessary. It is good knowledge to have though, because without it you can have unexplained problems when outputting vertex information.