So I’m using the global fog shader & Script for image effects. Now what I’m trying to do, is instead of using 1 fog color for the shader, sample the skybox. I want to give the effect of everything simply fading into the sky, rather than having that look of a mountain in the distance being a solid color…
I need some help to put me in the right direction? One of my ideas was to have the shader place the skybox image across it in a way where… Well the unity 4 docs (not the 5) had a page where it shows an image being overlayed on the soldier, but depending on where the camera was… as in… imagine drawing a 2D image on a screen, and masking it just to the character. Perhaps I could do that, and use a seperate camera that only sees the skybox, and sample the render texture? I’m really not sure how to go about doing this.
Help is appreciated :).
Shader "Hidden/GlobalFog" {
Properties {
_MainTex ("Base (RGB)", 2D) = "black" {}
}
CGINCLUDE
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform sampler2D_float _CameraDepthTexture;
// x = fog height
// y = FdotC (CameraY-FogHeight)
// z = k (FdotC > 0.0)
// w = a/2
uniform float4 _HeightParams;
// x = start distance
uniform float4 _DistanceParams;
int4 _SceneFogMode; // x = fog mode, y = use radial flag
float4 _SceneFogParams;
#ifndef UNITY_APPLY_FOG
half4 unity_FogColor;
half4 unity_FogDensity;
#endif
uniform float4 _MainTex_TexelSize;
// for fast world space reconstruction
uniform float4x4 _FrustumCornersWS;
uniform float4 _CameraWS;
struct v2f {
float4 pos : SV_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;
}
// Applies one of standard fog formulas, given fog coordinate (i.e. distance)
half ComputeFogFactor (float coord)
{
float fogFac = 0.0;
if (_SceneFogMode.x == 1) // linear
{
// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
fogFac = coord * _SceneFogParams.z + _SceneFogParams.w;
}
if (_SceneFogMode.x == 2) // exp
{
// factor = exp(-density*z)
fogFac = _SceneFogParams.y * coord; fogFac = exp2(-fogFac);
}
if (_SceneFogMode.x == 3) // exp2
{
// factor = exp(-(density*z)^2)
fogFac = _SceneFogParams.x * coord; fogFac = exp2(-fogFac*fogFac);
}
return saturate(fogFac);
}
// Distance-based fog
float ComputeDistance (float3 camDir, float zdepth)
{
float dist;
if (_SceneFogMode.y == 1)
dist = length(camDir);
else
dist = zdepth * _ProjectionParams.z;
// Built-in fog starts at near plane, so match that by
// subtracting the near value. Not a perfect approximation
// if near plane is very large, but good enough.
dist -= _ProjectionParams.y;
return dist;
}
// Linear half-space fog, from https://www.terathon.com/lengyel/Lengyel-UnifiedFog.pdf
float ComputeHalfSpace (float3 wsDir)
{
float3 wpos = _CameraWS + wsDir;
float FH = _HeightParams.x;
float3 C = _CameraWS;
float3 V = wsDir;
float3 P = wpos;
float3 aV = _HeightParams.w * V;
float FdotC = _HeightParams.y;
float k = _HeightParams.z;
float FdotP = P.y-FH;
float FdotV = wsDir.y;
float c1 = k * (FdotP + FdotC);
float c2 = (1-2*k) * FdotP;
float g = min(c2, 0.0);
g = -length(aV) * (c1 - g * g / abs(FdotV+1.0e-5f));
return g;
}
half4 ComputeFog (v2f i, bool distance, bool height) : SV_Target
{
half4 sceneColor = tex2D(_MainTex, i.uv);
// Reconstruct world space position & direction
// towards this screen pixel.
float rawDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv_depth);
float dpth = Linear01Depth(rawDepth);
float4 wsDir = dpth * i.interpolatedRay;
float4 wsPos = _CameraWS + wsDir;
// Compute fog distance
float g = _DistanceParams.x;
if (distance)
g += ComputeDistance (wsDir, dpth);
if (height)
g += ComputeHalfSpace (wsDir);
// Compute fog amount
half fogFac = ComputeFogFactor (max(0.0,g));
// Do not fog skybox
if (rawDepth >= 0.999999)
fogFac = 1.0;
//return fogFac; // for debugging
// Lerp between fog color & original scene color
// by fog amount
return lerp (unity_FogColor, sceneColor, fogFac);
}
ENDCG
SubShader
{
ZTest Always Cull Off ZWrite Off Fog { Mode Off }
// 0: distance + height
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
half4 frag (v2f i) : SV_Target { return ComputeFog (i, true, true); }
ENDCG
}
// 1: distance
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
half4 frag (v2f i) : SV_Target { return ComputeFog (i, true, false); }
ENDCG
}
// 2: height
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
half4 frag (v2f i) : SV_Target { return ComputeFog (i, false, true); }
ENDCG
}
}
Fallback off
}
using System;
using UnityEngine;
namespace UnitySampleAssets.ImageEffects
{
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
[AddComponentMenu ("Image Effects/Rendering/Global Fog")]
class GlobalFog : PostEffectsBase
{
[Tooltip("Apply distance-based fog?")]
public bool distanceFog = true;
[Tooltip("Distance fog is based on radial distance from camera when checked")]
public bool useRadialDistance = false;
[Tooltip("Apply height-based fog?")]
public bool heightFog = true;
[Tooltip("Fog top Y coordinate")]
public float height = 1.0f;
[Range(0.001f,10.0f)]
public float heightDensity = 2.0f;
[Tooltip("Push fog away from the camera by this amount")]
public float startDistance = 0.0f;
public Shader fogShader = null;
private Material fogMaterial = null;
public override bool CheckResources ()
{
CheckSupport (true);
fogMaterial = CheckShaderAndCreateMaterial (fogShader, fogMaterial);
if (!isSupported)
ReportAutoDisable ();
return isSupported;
}
[ImageEffectOpaque]
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
if (CheckResources()==false || (!distanceFog && !heightFog))
{
Graphics.Blit (source, destination);
return;
}
Camera cam = GetComponent<Camera>();
Transform camtr = cam.transform;
float camNear = cam.nearClipPlane;
float camFar = cam.farClipPlane;
float camFov = cam.fieldOfView;
float camAspect = cam.aspect;
Matrix4x4 frustumCorners = Matrix4x4.identity;
float fovWHalf = camFov * 0.5f;
Vector3 toRight = camtr.right * camNear * Mathf.Tan (fovWHalf * Mathf.Deg2Rad) * camAspect;
Vector3 toTop = camtr.up * camNear * Mathf.Tan (fovWHalf * Mathf.Deg2Rad);
Vector3 topLeft = (camtr.forward * camNear - toRight + toTop);
float camScale = topLeft.magnitude * camFar/camNear;
topLeft.Normalize();
topLeft *= camScale;
Vector3 topRight = (camtr.forward * camNear + toRight + toTop);
topRight.Normalize();
topRight *= camScale;
Vector3 bottomRight = (camtr.forward * camNear + toRight - toTop);
bottomRight.Normalize();
bottomRight *= camScale;
Vector3 bottomLeft = (camtr.forward * camNear - toRight - toTop);
bottomLeft.Normalize();
bottomLeft *= camScale;
frustumCorners.SetRow (0, topLeft);
frustumCorners.SetRow (1, topRight);
frustumCorners.SetRow (2, bottomRight);
frustumCorners.SetRow (3, bottomLeft);
var camPos= camtr.position;
float FdotC = camPos.y-height;
float paramK = (FdotC <= 0.0f ? 1.0f : 0.0f);
fogMaterial.SetMatrix ("_FrustumCornersWS", frustumCorners);
fogMaterial.SetVector ("_CameraWS", camPos);
fogMaterial.SetVector ("_HeightParams", new Vector4 (height, FdotC, paramK, heightDensity*0.5f));
fogMaterial.SetVector ("_DistanceParams", new Vector4 (-Mathf.Max(startDistance,0.0f), 0, 0, 0));
var sceneMode= RenderSettings.fogMode;
var sceneDensity= RenderSettings.fogDensity;
var sceneStart= RenderSettings.fogStartDistance;
var sceneEnd= RenderSettings.fogEndDistance;
Vector4 sceneParams;
bool linear = (sceneMode == FogMode.Linear);
float diff = linear ? sceneEnd - sceneStart : 0.0f;
float invDiff = Mathf.Abs(diff) > 0.0001f ? 1.0f / diff : 0.0f;
sceneParams.x = sceneDensity * 1.2011224087f; // density / sqrt(ln(2)), used by Exp2 fog mode
sceneParams.y = sceneDensity * 1.4426950408f; // density / ln(2), used by Exp fog mode
sceneParams.z = linear ? -invDiff : 0.0f;
sceneParams.w = linear ? sceneEnd * invDiff : 0.0f;
fogMaterial.SetVector ("_SceneFogParams", sceneParams);
fogMaterial.SetVector ("_SceneFogMode", new Vector4((int)sceneMode, useRadialDistance ? 1 : 0, 0, 0));
int pass = 0;
if (distanceFog && heightFog)
pass = 0; // distance + height
else if (distanceFog)
pass = 1; // distance only
else
pass = 2; // height only
CustomGraphicsBlit (source, destination, fogMaterial, pass);
}
static void CustomGraphicsBlit (RenderTexture source, RenderTexture dest, Material fxMaterial, int passNr)
{
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.0f); // TL
GL.End ();
GL.PopMatrix ();
}
}
}