Hello everyone !
I had to play with post-process effects with Unity3D, and I finally ended with looking at the “Global Fog” Shader script.
But there are things I’m a bit confused with, mostly mathematics.
Everything I said from this point is what I think have understood from the code, so feel free to correct me if I’m wrong ![]()
Here, in the OnRenderImage function, a 4x4 Matrix is created, where each rows contains the direction of each “edge” of the far plane.
function OnRenderImage (source : RenderTexture, destination : RenderTexture) {
if(CheckResources()==false) {
Graphics.Blit (source, destination);
return;
}
CAMERA_NEAR = camera.nearClipPlane;
CAMERA_FAR = camera.farClipPlane;
CAMERA_FOV = camera.fieldOfView;
CAMERA_ASPECT_RATIO = camera.aspect;
var frustumCorners : Matrix4x4 = Matrix4x4.identity;
var vec : Vector4;
var corner : Vector3;
var fovWHalf : float = CAMERA_FOV * 0.5f;
var toRight : Vector3 = camera.transform.right * CAMERA_NEAR * Mathf.Tan (fovWHalf * Mathf.Deg2Rad) * CAMERA_ASPECT_RATIO;
var toTop : Vector3 = camera.transform.up * CAMERA_NEAR * Mathf.Tan (fovWHalf * Mathf.Deg2Rad);
var topLeft : Vector3 = (camera.transform.forward * CAMERA_NEAR - toRight + toTop);
var CAMERA_SCALE : float = topLeft.magnitude * CAMERA_FAR/CAMERA_NEAR;
topLeft.Normalize();
topLeft *= CAMERA_SCALE;
var topRight : Vector3 = (camera.transform.forward * CAMERA_NEAR + toRight + toTop);
topRight.Normalize();
topRight *= CAMERA_SCALE;
var bottomRight : Vector3 = (camera.transform.forward * CAMERA_NEAR + toRight - toTop);
bottomRight.Normalize();
bottomRight *= CAMERA_SCALE;
var bottomLeft : Vector3 = (camera.transform.forward * CAMERA_NEAR - toRight - toTop);
bottomLeft.Normalize();
bottomLeft *= CAMERA_SCALE;
frustumCorners.SetRow (0, topLeft);
frustumCorners.SetRow (1, topRight);
frustumCorners.SetRow (2, bottomRight);
frustumCorners.SetRow (3, bottomLeft);
fogMaterial.SetMatrix ("_FrustumCornersWS", frustumCorners);
fogMaterial.SetVector ("_CameraWS", camera.transform.position);
fogMaterial.SetVector ("_StartDistance", Vector4 (1.0f / startDistance, (CAMERA_SCALE-startDistance)));
fogMaterial.SetVector ("_Y", Vector4 (height, 1.0f / heightScale));
fogMaterial.SetFloat ("_GlobalDensity", globalDensity * 0.01f);
fogMaterial.SetColor ("_FogColor", globalFogColor);
CustomGraphicsBlit (source, destination, fogMaterial, fogMode);
}
Ok, so no we blit your source on a quad. The MultiTexCoord2 isn’t a problem, but I don’t really understand the point of making the quad starting in Z=3, and then each vertex make if closer from the Z=0. I Believe this is related to the vertex part of the shader ?
static function CustomGraphicsBlit (source : RenderTexture, dest : RenderTexture, fxMaterial : Material, passNr : int) {
RenderTexture.active = dest;
fxMaterial.SetTexture ("_MainTex", source);
GL.PushMatrix ();
GL.LoadOrtho ();
fxMaterial.SetPass (passNr);
GL.Begin (GL.QUADS);
GL.MultiTexCoord2 (0, 0.0f, 0.0f);
GL.Vertex3 (0.0f, 0.0f, 3.0f); // BL
GL.MultiTexCoord2 (0, 1.0f, 0.0f);
GL.Vertex3 (1.0f, 0.0f, 2.0f); // BR
GL.MultiTexCoord2 (0, 1.0f, 1.0f);
GL.Vertex3 (1.0f, 1.0f, 1.0f); // TR
GL.MultiTexCoord2 (0, 0.0f, 1.0f);
GL.Vertex3 (0.0f, 1.0f, 0.0); // TL
GL.End ();
GL.PopMatrix ();
}
And now the shader: There’s no problem with the fragment, it’s mostly the vertex: there’s interpolation, And it’s that point I don’t understand:
uniform float4x4 _FrustumCornersWS;
uniform float4 _CameraWS;
struct v2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float2 uv_depth : TEXCOORD1;
float4 interpolatedRay : TEXCOORD2;
};
v2f vert( appdata_img v )
{
v2f o;
half index = v.vertex.z;
v.vertex.z = 0.1;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
o.uv_depth = v.texcoord.xy;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv.y = 1-o.uv.y;
#endif
o.interpolatedRay = _FrustumCornersWS[(int)index];
o.interpolatedRay.w = index;
return o;
}
...
half4 fragAbsoluteYAndDistance (v2f i) : COLOR
{
float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv_depth)));
float4 wsDir = dpth * i.interpolatedRay;
float4 wsPos = _CameraWS + wsDir;
return lerp(...);
}
If someone could explain me how this interpolation works ? And what is the meaning of interpolatedRay ?
o.interpolatedRay = _FrustumCornersWS[(int)index];
o.interpolatedRay.w = index;
Many thanks for those who’ll help understanding this ![]()
Edit: Yeah, I took me nearly one year to decide myself to ask “how it works”: http://forum.unity3d.com/threads/169841-Weird-world-coordinate-for-post-process-pixel