when the light is set to “spot or point light/important (pixel lighting)” the final color is (0.6,0.6,0.6) if intensity>0 (no matter how small). “spot or point light/not important (vertex lighting)” and “directional light” give the correct color (0.3,0.3,0.3)
source code:
PS. I’m also interested in the “execution order of surface shader functions”. e.g. where are these functions plugged after being translated into vertex and fragment shader? vertex:VertexFunction, finalcolor:ColorFunction, lightModel
It’s because Unity expects you to multiply something with the final color, not set its value directly. You get double the result because there is a pass done for every light and the results are then summed together.
If you don’t need to handle lighting, you shouldn’t use surface shaders at all. If you need to do something more complex, then tell what exactly, so I can help you more.
Add #pragma debug inside your shader and then open the compiled result. You should see when and how your functions are called.
I’m writing a set of shaders that part of the object is the same as the builtin shaders Diffuse, Specular, Bumped Diffuse, Bumped Specular, etc. and the rest part takes color from a texture (imagine a plane that half is lighted as usual and the other half takes color from a texture).
Since it interacts with lighting, I believe surface shader would be simpler, I’m expecting to take the exact color of the texture and output it. Any simple solution to this?
So output of finalcolor will also affected by lighting?
I’m still not sure what you want to do though… If you want to overwrite the computed color, the lighting that was done to it will get wasted and you’ll go better by not using a surface shader. If you want to add a texture unaffected by lighting to the final result, use o.Emission.
If, for some reason, none of these fit you and you don’t want the result of the finalcolor to be accumulated, you could hack it like this:
void fctest (Input IN, SurfaceOutput o, inout half4 color)
{
#ifdef UNITY_PASS_FORWARDBASE
color = 0.3;
#endif
}
I’m not sure if this will work… What it should do though, is that it would set the color to 0.3’s only in the first pass, which unity marks as UNITY_PASS_FORWARDBASE. But again, if you just overwrite the color like this, it’s a waste of the lighting that was done before.
As said before, suppose there is a plane, the left half is lit normally with a Diffuse material, and the right half is taken from a texture (a background image), because i know it is occluded.
Originally, I’m trying to modifying the color output in a custom lighting model, But I found it is hardly achievable over there, because the output of custom lighting model is affected by to many things later on, e.g. ambient lighting, which need to be turned on. Is it possible to specify exact some color in custom lighting model the same as appeared on the screen?
Then I decide to use an ‘over-draw’ approach with a finalcolor function, but realize its color will also be affected by point and spot light with pixel lighting.
Wait… background image? From GrabPass? Why not just clip() the pixels then?
Anyways, for setting a color that is not affected by lighting, DONT use surface shader… make your own vertex and fragment shaders. The overdrawing would work that way. But assuming you have some kind of condition for separating the halves, the easiest, and probably faster, way is to use what I suggested:
if (condition) {
#ifdef UNITY_PASS_FORWARDBASE
// Will be done only in first pass, so it shouldn't accumulate
color = yourTexColor;
#else
// Making sure no other magic happens there
color = 0;
#endif
}
Problem solved! clip() works like a charm! but the nvidia cg tutorial never mentioned there is a clip function, seems I should refer HLSL for shader programming.
Currently i’m not using GrabPass but I think the situation is the same. The background image is pre-rendered in an external ray-tracer, and an additional camera is set up looking at this image plane. And this texture also is passed to the shader as a texture, and I wished to redraw part of the texture as a cheap replacement to clip().