- Home /
Shader float value weirdness
Shader "Shader Tuts/Lambert" {
Properties {
_Color ("Color", Color) = (1.0,1.0,1.0,1.0)
_MainTex ("Main Tex", 2D) = "white" {}
_BumpMap ("Bump Map", 2D) = "bump" {}
_BumpDepth ("Bump Depth", Range(-2.0, 2.0)) = 0.0
_SpecColor ("Specular Color", Color) = (1.0, 1.0, 1.0, 1.0)
_Shininess ("Shininess", float) = 0.0
}
SubShader {
Pass {
Tags {
"LightMode" = "ForwardBase"
}
CGPROGRAM
// pragmas
#pragma vertex vert
#pragma fragment frag
// user defined variables
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform sampler2D _BumpMap;
uniform float4 _BumpMap_ST;
uniform float4 _Color;
uniform float4 _SpecColor;
uniform float _Shininess;
uniform float _BumpDepth;
// inbuilt variables
uniform float4 _LightColor0;
// base input structs
struct vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 tangent : TANGENT;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float4 tex : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float3 normalWorld : TEXCOORD2;
float3 tangentWorld : TEXCOORD3;
float3 binormalWorld : TEXCOORD4;
};
// vertex program
vertexOutput vert(vertexInput v) {
vertexOutput o;
o.posWorld = mul(_Object2World, v.vertex);
// convert normal from object space to world space and normalize
o.normalWorld = normalize(mul(float4(v.normal, 0.0f), _World2Object));
o.tangentWorld = normalize(mul(_Object2World, v.tangent));
o.binormalWorld = normalize(cross(o.normalWorld, o.tangentWorld) * v.tangent.w);
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.tex = v.texcoord;
return o;
}
float4 frag(vertexOutput i) : COLOR {
// direction calculations
float3 lightDir = normalize(_WorldSpaceLightPos0).xyz;
float3 viewDir = normalize(_WorldSpaceCameraPos - i.posWorld);
float atten = 1.0f;
// texture calculations
float4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);
float4 encodedNormal = tex2D(_BumpMap, i.tex.xy * _BumpMap_ST.xy + _BumpMap_ST.zw);
// unpack normals, Unity has inbuild function but we will create our own since its more efficient
float3 localCoords = (2.0 * encodedNormal.ag - float2(1.0,1.0), 0.0);
localCoords.z = 1.0 - 0.5 * dot(localCoords, localCoords);
// normal transpose matrix
float3x3 local2WorldTranspose = float3x3(i.tangentWorld,
i.binormalWorld,
i.normalWorld);
float3 normalDir = normalize(mul(localCoords, local2WorldTranspose));
float3 reflectedDir = reflect(-lightDir, normalDir);
// light calculations
float3 diffuseReflection = atten * _LightColor0.xyz * max(0.0, dot(normalDir, lightDir));
float3 specularReflection = diffuseReflection * _SpecColor.rgb * pow(max(0.0, dot(reflectedDir, viewDir)), _Shininess);
float3 finalLight = diffuseReflection + specularReflection + UNITY_LIGHTMODEL_AMBIENT;
return float4(tex.xyz * finalLight * _Color.rgb , 1.0);
}
// fragment program
ENDCG
}
}
// Fallback "Diffuse"
}
In the above shader, if I set the value of _Shininess to 0 from the editor I get this result
Instead, if I replace the value of _Shininess to 0 manually in the shader at this line:
float3 specularReflection = diffuseReflection * _SpecColor.rgb * pow(max(0.0, dot(reflectedDir, viewDir)), 0.0);
then I get this result:
What exactly is going on here!? Why does it behave differently when the value is set in the editor and when its hardcoded! Any help would be appreciated. Thank you.
Answer by Teravisor · Jan 25, 2016 at 12:08 PM
It's result of pow(x,0) always being 1 and due to how pow(x,y)
is compiled. If y is not known at compile time, it is compiled as exp(y*log(x))
otherwise it's compiled as several multiplications. So if you exchange your pow(max(0.0,dot(reflectedDir,viewDir)), 0)
to exp(0*log(max(0.0,dot(reflectedDir,viewDir))))
you will get same effect as when you use pow(x,y) with y not being constant. It gets black when that max(...) statement returns 0 and log(0) is defined as -INF if I remember right (shader default, not mathematical).
Thanks for sharing this knowledge. I had no idea about this.