I’m trying to add fog to water reflections. To do so I want to calculate world position of reflected objects and then distance to the main camera to calculate fog factor in water shader.
- Reflections camera renders to depth texture.
m_ReflectionTexture = new RenderTexture(textureSize, textureSize, 0);
ReflectionTextureDepth = new RenderTexture(textureSize, textureSize, 24, RenderTextureFormat.Depth);
reflectionCamera.SetTargetBuffers(reflectionTex.colorBuffer, ReflectionTextureDepth.depthBuffer);
- Then send it to my shader. With reflection camera position to reconstract world position.
GetComponent<Renderer>().sharedMaterial.SetTexture("_ReflectionTex", reflectionTexture);
GetComponent<Renderer>().sharedMaterial.SetTexture("_ReflectionTexDepth", ReflectionTextureDepth);
GetComponent<Renderer>().sharedMaterial.SetVector("_ReflectionCameraPosition", reflectionCamera.transform.position);
- Sample depth, I think problem there because fog show on reflected geometry only if I set fog end close to 2 or smaller.
float rawZ = SAMPLE_DEPTH_TEXTURE_PROJ(_ReflectionTexDepth, UNITY_PROJ_COORD(i.ref));
float sceneZ = LinearEyeDepth(rawZ) ;
- Calculate world positions of reflected objects and distance from main camera. Am I correct that directionFromReflectionCamera is correct direction to the mountain?
float3 directionFromReflectionCamera = normalize(i.wpos - _ReflectionCameraPosition.xyz);
float3 reflectedWpos = (sceneZ * directionFromReflectionCamera) + _ReflectionCameraPosition.xyz;
float reflectedSceneDistance = length(reflectedWpos - _WorldSpaceCameraPos);
- Calculate fog factor and return resulting color.
//linear fog unity formula
float unityFogFactorReflection = (reflectedSceneDistance)* unity_FogParams.z + unity_FogParams.w;
loat3 reflectionColorWithFog = lerp(unity_FogColor.rgb, refl.rgb,saturate(unityFogFactorReflection));
return half4(reflectionColorWithFog.rgb, 1);
Fog start = 0, end = 1
Fog start = 0.35, end 0.5
We see that the fog shows on the top of the mountain cause the top is farther than the bottom.
Full shader code
Shader "FX/Water" {
Properties{
}
Subshader{
Tags { "WaterMode" = "Refractive" "RenderType" = "Opaque" }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
sampler2D _ReflectionTex;
sampler2D _ReflectionTexDepth;
float4 _ReflectionCameraPosition;
struct appdata {
float4 vertex : POSITION;
};
struct v2f {
float4 pos : SV_POSITION;
float4 ref : TEXCOORD0;
float3 wpos : TEXCOORD1;
};
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.ref = ComputeNonStereoScreenPos(o.pos);
o.wpos = mul((float4x4)unity_ObjectToWorld, v.vertex);
return o;
}
half4 frag(v2f i) : SV_Target
{
half4 refl = tex2Dproj(_ReflectionTex, UNITY_PROJ_COORD(i.ref));
float rawZ = SAMPLE_DEPTH_TEXTURE_PROJ(_ReflectionTexDepth, UNITY_PROJ_COORD(i.ref));
float sceneZ = LinearEyeDepth(rawZ) ; //return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w); where _ZBufferParams.z is (x/far) and _ZBufferParams.w is (y/far) they are same in reflectionCamera and mainCamera
float3 directionFromReflectionCamera = normalize(i.wpos - _ReflectionCameraPosition.xyz);
float3 reflectedWpos = (sceneZ * directionFromReflectionCamera) + _ReflectionCameraPosition.xyz;
float reflectedSceneDistance = length(reflectedWpos - _WorldSpaceCameraPos);
float unityFogFactorReflection = (reflectedSceneDistance)* unity_FogParams.z + unity_FogParams.w; //linear fog unity formula where z = –1/(end-start) w = end/(end-start)
float3 reflectionColorWithFog = lerp(unity_FogColor.rgb, refl.rgb,saturate(unityFogFactorReflection));
//return half4(refl.rgb,1);//shows reflection texture
//return half4(sceneZ.xxx, 1); //shows depth texture
return half4(reflectionColorWithFog.rgb, 1);
}
ENDCG
}
}
}
And on next stage, I want to consider distance to water and show fog on the water.(current unity default behavior) So if I calculate distance to current water fragment.
float reflectionSceneDistance = length(i.wpos - _WorldSpaceCameraPos);
float unityFogFactorReflection = ( reflectionSceneDistance)* unity_FogParams.z + unity_FogParams.w;
But if I want to consider fog on reflected mountain.
float reflectedSceneDistance = length(reflectedWpos - _WorldSpaceCameraPos);
float reflectionSceneDistance = length(i.wpos - _WorldSpaceCameraPos);
float unityFogFactorReflection = ( reflectionSceneDistance - reflectedSceneDistance)* unity_FogParams.z + unity_FogParams.w;
Now it looks like this.
3277167–253405–StandartWaterFog.zip (248 KB)