[Unity][Shader] Stylized Fog
- Get link
- X
- Other Apps
I wrote a simple shader for Unity to make a stylized fog like Fire Watch's fog. The idea is to get a pixel on the texture depending on the pixel depth, if the fog is near, a pixel on the left on the texture uv will be picked, if the fog is far, a pixel on the right on the texture uv will be picked.
Features
- Choose between a linear fog and an exponential fog
- Choose between a simple color or a texture
Screenshots
Video
Source Code
Image Effect Version (Unity 2017 and older if not using Stack)
Shader "Hidden/Shader_StylizedFog"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_FogColor("Fog Color", Color) = (1, 1, 1, 1)
_UseStylizedFogTexture("Use Stylized Fog Texture", Int) = 0
_StylizedFogTexture("Stylized Fog Texture", 2D) = "white" {}
_FogMinDistance("Fog Min Distance", Float) = 0
_FogMaxDistance("Fog Max Distance", Float) = 100
_IsExponential("Exponential Fog", Int) = 0
_ExponentialDensity("Exponential Fog Density", Range(0, 10)) = 1
_FogIntensity("Fog Intensity", Range(0, 1)) = 1
_FogOpacityMax("Fog Opacity Max", Range(0, 1)) = 1
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex, _CameraDepthTexture, _StylizedFogTexture;
fixed4 _FogColor;
float _FogMinDistance, _FogMaxDistance, _ExponentialDensity, _FogIntensity, _FogOpacityMax;
int _IsExponential, _UseStylizedFogTexture;
fixed4 frag (v2f i) : SV_Target
{
// Color of pixel to render
fixed4 baseColor = tex2D(_MainTex, i.uv);
// Get pixel depth and make linear fog calculations from it
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
depth = Linear01Depth(depth);
depth = clamp(depth * (_ProjectionParams.z / _FogMaxDistance), 0, 1);
// Get fog color from stylized texture based on depth for UV
if (_UseStylizedFogTexture)
_FogColor = tex2D(_StylizedFogTexture, float2(min(0.9, depth), 0));
// Exponential fog
if (_IsExponential)
depth = 1 / exp((1 - depth) * _ExponentialDensity);
return lerp(baseColor, _FogColor, min(depth * _FogIntensity, _FogOpacityMax) * _FogColor.a);
}
ENDCG
}
}
}
using UnityEngine;
public class ImageEffect_StylizedFog : MonoBehaviour
{
#region MonoBehaviour Methods
/// <summary>
/// Use this for initialization
/// </summary>
private void Start()
{
// Create material from linked shader
if (m_Shader != null)
m_Material = new Material(m_Shader);
// Update material parameters
UpdateMaterialParameters();
}
/// <summary>
/// Called when image is renderer for graphics
/// </summary>
/// <param name="_Source" />Source image
/// <param name="_Destination" />Destination Image
private void OnRenderImage(RenderTexture _Source, RenderTexture _Destination)
{
// Set the image to draw
Graphics.Blit(_Source, _Destination, m_Material);
}
/// <summary>
/// Called when a variable change in editor
/// </summary>
private void OnValidate()
{
UpdateMaterialParameters();
}
#endregion
#region Private Methods
/// <summary>
/// Update all material parameters
/// </summary>
private void UpdateMaterialParameters()
{
// Update material parameters
if (m_Material != null)
{
m_Material.SetColor("_FogColor", m_FogColor);
m_Material.SetFloat("_FogMaxDistance", m_FogMaxDistance);
m_Material.SetInt("_IsExponential", m_IsExponentialFog ? 1 : 0);
m_Material.SetFloat("_ExponentialDensity", m_ExponentialFogDensity);
m_Material.SetFloat("_FogIntensity", m_FogIntensity);
m_Material.SetFloat("_FogOpacityMax", m_FogOpacityMax);
m_Material.SetTexture("_StylizedFogTexture", m_StylizedFogTexture);
m_Material.SetInt("_UseStylizedFogTexture", m_StylizedFogTexture != null ? 1 : 0);
}
}
#endregion
#region Getters & Setters
// Accessors for colorization ratio
public Color FogColor
{
get { return m_FogColor; }
set
{
m_FogColor = value;
// Update material parameters
UpdateMaterialParameters();
}
}
#endregion
#region Attributes
// Shader to execute for post process effect
[SerializeField]
[Tooltip("Shader to execute for post process effect")]
private Shader m_Shader = null;
// Fog intensity (0 = no fog, 1 = fog opaque)
[SerializeField]
[Tooltip("Fog intensity (0 = no fog, 1 = fog opaque)")]
[Range(0, 1)]
private float m_FogIntensity = 1;
// Opacity maximum for the fog (clamp opacity)
[SerializeField]
[Tooltip("Opacity maximum for the fog (clamp opacity instead of multiplying it)")]
[Range(0, 1)]
private float m_FogOpacityMax = 1;
// Fog color
[SerializeField]
[Tooltip("Fog color")]
private Color m_FogColor = Color.white;
// Stylized fog texture. Color will be picked on UV using fog distance ratio (near fog is 0 on uv.x and far fog is 1 on uv.x)
[SerializeField]
[Tooltip("Stylized fog texture. Color will be picked on UV using fog distance ratio (near fog is 0 on uv.x and far fog is 1 on uv.x)")]
private Texture2D m_StylizedFogTexture = null;
// Fog max distance
[SerializeField]
[Tooltip("Fog max distance")]
private float m_FogMaxDistance = 100;
// Is fog exponential or linear
[SerializeField]
[Tooltip("Is fog exponential or linear")]
private bool m_IsExponentialFog = false;
// Exponential fog density
[SerializeField]
[Tooltip("Exponential fog density (if fog exponential)")]
[Range(0, 10)]
private float m_ExponentialFogDensity = 1;
// Material used to execute post process shader
private Material m_Material = null;
#endregion
}
Stack Version (Unity 2018)
Shader "Hidden/Stylized Fog"
{
HLSLINCLUDE
#include "PostProcessing/Shaders/StdLib.hlsl"
TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture);
float4 FogColor;
int UseStylizedFogTexture;
TEXTURE2D_SAMPLER2D(StylizedFogTexture, sampler_StylizedFogTexture);
float FogMinDistance;
float FogMaxDistance;
int IsExponential;
float ExponentialDensity;
float FogIntensity;
float FogOpacityMax;
float4 Frag(VaryingsDefault i) : SV_Target
{
// Color of pixel to render
float4 baseColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
// Get pixel depth and make linear fog calculations from it
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoord);
depth = Linear01Depth(depth);
depth = clamp(depth * (_ProjectionParams.z / FogMaxDistance), 0, 1);
// Get fog color from stylized texture based on depth for UV
if (UseStylizedFogTexture)
FogColor = SAMPLE_TEXTURE2D(StylizedFogTexture, sampler_StylizedFogTexture, float2(min(0.9, depth), 0));
// Exponential fog
if (IsExponential)
depth = 1 / exp((1 - depth) * ExponentialDensity);
return lerp(baseColor, FogColor, min(depth * FogIntensity, FogOpacityMax) * FogColor.a);
}
ENDHLSL
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex VertDefault
#pragma fragment Frag
ENDHLSL
}
}
}
{
HLSLINCLUDE
#include "PostProcessing/Shaders/StdLib.hlsl"
TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture);
float4 FogColor;
int UseStylizedFogTexture;
TEXTURE2D_SAMPLER2D(StylizedFogTexture, sampler_StylizedFogTexture);
float FogMinDistance;
float FogMaxDistance;
int IsExponential;
float ExponentialDensity;
float FogIntensity;
float FogOpacityMax;
float4 Frag(VaryingsDefault i) : SV_Target
{
// Color of pixel to render
float4 baseColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
// Get pixel depth and make linear fog calculations from it
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoord);
depth = Linear01Depth(depth);
depth = clamp(depth * (_ProjectionParams.z / FogMaxDistance), 0, 1);
// Get fog color from stylized texture based on depth for UV
if (UseStylizedFogTexture)
FogColor = SAMPLE_TEXTURE2D(StylizedFogTexture, sampler_StylizedFogTexture, float2(min(0.9, depth), 0));
// Exponential fog
if (IsExponential)
depth = 1 / exp((1 - depth) * ExponentialDensity);
return lerp(baseColor, FogColor, min(depth * FogIntensity, FogOpacityMax) * FogColor.a);
}
ENDHLSL
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex VertDefault
#pragma fragment Frag
ENDHLSL
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;
[System.Serializable]
[PostProcess(typeof(StylizedFogRenderer), PostProcessEvent.AfterStack, "Custom/Stylized Fog")]
public sealed class PostProcess_StylizedFog : PostProcessEffectSettings
{
#region Shader Parameters
public ColorParameter FogColor = new ColorParameter { value = new Color(1, 1, 1, 1) };
[Range(0, 1)]
public IntParameter UseStylizedFogTexture = new IntParameter { value = 0 };
public TextureParameter StylizedFogTexture = new TextureParameter { };
public FloatParameter FogMinDistance = new FloatParameter { value = 0 };
public FloatParameter FogMaxDistance = new FloatParameter { value = 100 };
[Range(0, 1)]
public IntParameter IsExponential = new IntParameter { value = 1 };
[Range(0f, 10f)]
public FloatParameter ExponentialDensity = new FloatParameter { value = 1f };
[Range(0f, 1f)]
public FloatParameter FogIntensity = new FloatParameter { value = 1 };
[Range(0f, 1f)]
public FloatParameter FogOpacityMax = new FloatParameter { value = 1 };
#endregion
public override bool IsEnabledAndSupported(PostProcessRenderContext context)
{
return enabled.value;
}
}
public sealed class StylizedFogRenderer : PostProcessEffectRenderer<postprocess_stylizedfog>
{
public override void Render(PostProcessRenderContext context)
{
var sheet = context.propertySheets.Get(Shader.Find("Hidden/Stylized Fog"));
sheet.properties.SetColor("FogColor", settings.FogColor);
sheet.properties.SetInt("UseStylizedFogTexture", settings.UseStylizedFogTexture);
if (settings.StylizedFogTexture != null)
sheet.properties.SetTexture("StylizedFogTexture", settings.StylizedFogTexture);
sheet.properties.SetFloat("FogMinDistance", settings.FogMinDistance);
sheet.properties.SetFloat("FogMaxDistance", settings.FogMaxDistance);
sheet.properties.SetInt("IsExponential", settings.IsExponential);
sheet.properties.SetFloat("ExponentialDensity", settings.ExponentialDensity);
sheet.properties.SetFloat("FogIntensity", settings.FogIntensity);
sheet.properties.SetFloat("FogOpacityMax", settings.FogOpacityMax);
context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
}
}
On your post process volume, click on add effect and you should see the shader in the "custom" category. Edit it as any other post process effect.
Comments
Post a Comment