Resolved: The answer is “no”. Be sure to normalize s.Normal in the lighting function. Because the surface shader path doesn’t do it for you.
I think…
The surface shaders do send an interpolated normal, but those values are not normalized inside of the fragment shader. So the end effect is that of being vertex lit.
Try having this at the top of your surface shader’s lighting function;
lightDir = normalize(lightDir);
viewDir = normalize(viewDir);
Thanks, but didn’t change anything for me. I suppose digging through compiled shader code would let me see if my suspicions are correct. Assuming of course that it’s not an error on my end! Giving out the code for the built-in shaders would be a nice carrot for developers trying to debug shaders…
The code is available, but it’s mostly all plugging stuff into the surface shader system.
You can put #pragma debug into a surface shader’s CGPROGRAM block and the compiled shader is easier to read.
Oh, and I forgot to add it above, but try those two lines I posted above and add this extra line;
lightDir = normalize(lightDir);
viewDir = normalize(viewDir);
s.Normal = normalize(s.Normal);
I thought I had tried all combos of normalizing before, but I guess not. It’s the normal that’s not coming in normalized. (View and Light don’t need it).
That’s what I get for basing my code off of the examples and not paying attention to the Simple Specular being obviously vertex lit: Unity - Manual: Surface Shader lighting examples
Thanks for your help
Well it is coming in normalized per-vertex. But as it interpolates between the vertices, it shortens a little. So you have to normalize it in the fragment shader in order for it to regain it’s full length at the fragment level, rather than just the vertex level.
The same thing does happen for the light and view directions - it’s just not as obvious.
I understand all this (thanks for the effort); I’ve written a lot of vert/frag shaders in a variety of languages, and the first thing in the frag shader is to normalize everything that’s a direction. I would have assumed that the surface shaders would take care of this for you. After all, the surface shader is playing a large part of the frag shader role before it executes your lighting function. Things that don’t have meaning without being normalized (normals, tangents) should be normalized before the lighting function. If they’re not doing it for you, it needs to be documented.