Here is a custom shader that I aggressively simplified to show my point. Fog isn’t working when using the finalColor function. What I want to do is apply a simple color remap after the fog, but it isn’t working. I get the error : “invalid subscript ‘fogCoord’”. I have tried additional things like adding in a vertex shader to try and manually do the fog calcuations, but I get other errors.
Shader "Custom/TestFog"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
[NoScaleOffset] _MainTex("Albedo", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows finalcolor:finalColor
// make fog work
#pragma multi_compile_fog
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutputStandard o)
{
o.Albedo = float3(1, 0, 0);
}
half4 toGrayscale(half4 c) {
c.rgb = (c.r + c.g + c.b) / 3.0f;
return c;
}
void finalColor(Input IN, SurfaceOutputStandard o, inout fixed4 color)
{
UNITY_APPLY_FOG(IN.fogCoord, col);
color = toGrayscale(color);
}
ENDCG
}
}
My guess as to the reason why using finalcolor disables fog is that it was likely originally conceived primarily as a way to do custom fog, so it probably made sense to disable “real” fog when it was in use. Unfortunately, finalcolor has plenty of other uses, but that original assumption remains. So your idea of doing fog again makes sense and is one of the ways to solve it.
Now to the error you’re getting with the code above. You’re trying to access IN.fogCoord. The IN there is the Input struct you defined above, which has no fogCoord property, which is why you get that error. If you’re going to put the fogCoord in the Input struct, you will have to calculate the fogCoord yourself in a vertex function.
Unity’s documentation on Surface Shaders has an example of how to do custom fog here:
Search for Linear Fog on that page. Note the Custom Fog with Final Color Modifier example just above that is doing “fog” by screen distance to the middle of the screen which isn’t all that useful. And the linear fog example won’t match Unity’s built in fog. Luckily you can still reproduce the original fog like this:
#pragma surface surf Standard fullforwardshadows vertex:vert finalcolor:finalColor
// you were right that you need to add this
// normally you wouldn't as Surface Shaders add it automatically,
// but the finalcolor stops that from happening as part of it disabling fog
#pragma multi_compile_fog
struct Input {
float2 uv_MainTex;
float fogCoord; // must be exactly this name as that's what the UNITY_TRANSFER_FOG macro is expecting
};
void vert (inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input,o);
// need to get the clip pos and call the UNITY_TRANSFER_FOG macro to setup the fogCoord
float4 clipPos = UnityObjectToClipPos(v.vertex);
UNITY_TRANSFER_FOG(o, clipPos);
}
void finalColor(Input IN, SurfaceOutputStandard o, inout fixed4 color)
{
// and now this "just works"
UNITY_APPLY_FOG(IN.fogCoord, col);
color = toGrayscale(color);
}