"Fog" is a very important effect in expressing the atmosphere, spaciousness, and fantastic atmosphere of the game. However, when building a foggy forest or a dimly lit cave using the Universal Render Pipeline (URP), have you ever encountered a rendering problem where smoke or flame particles (semi-transparent objects) placed deep in the fog appear to stand out in sharp, dark colors without being affected by the fog at all? This occurs due to a simple oversight in the graphics settings or insufficient description of the homemade shader. In this article, we will thoroughly explain the internal mechanism that causes this fog and translucent drawing bug, an example that is easy to understand even for beginners, and a complete solution with specific steps and code.
1. Understanding with an analogy: ``flame drawn on an acrylic board'' and ``a white paper curtain''
In order to visually understand this ``contradiction between fog and translucent particles,'' let's consider the overlapping of a picture drawn on a transparent acrylic board and a ``translucent white curtain'' as an analogy.
Suppose you have drawn multiple layers of white curtains (fog) at the back of the room (distant view) so that the scenery in the back does not appear hazy and hazy. Directly behind the curtain (behind the fog) is a red-hot flame (particles). If the view is physically correct, the light from the flame will pass through many white curtains, so it should appear as a ``slightly white, blurred, pink light'' from the front.
However, if there is a bug in the drawing process, the production staff (rendering engine) will process this by saying, ``The flames are semi-transparent and are drawn on an acrylic board, so after you finish calculating the curtains, put them on top of each other.'' As a result, an acrylic plate with a clear bright red flame is firmly attached to the front of the white curtain (the very front). The mountains and houses in the background are hidden in white by the curtains, but the flames, which are supposed to be deep inside, pierce through the curtains and come to the foreground in vivid colors. This is the true nature of the bug that breaks fog and translucent blending.
2. Root cause: Missing rendering passes and fog blending
Technically speaking, in Unity's Universal Render Pipeline (URP), fog is computed inside the shader in the Vertex Shader and Fragment Shader. Normally, when a 3D object is drawn, the fog attenuation rate ($0$~$1$) is calculated based on the distance (depth) from the camera, and the object's original color and the fog color (white, gray, etc.) are blended by linear interpolation.
However, objects drawn in the Transparent queue (such as materials for particle systems) are written to the backbuffer after all opaque objects have finished drawing. If the shader used at this time does not have a process to calculate fog (HLSL code or node structure) or is disabled, the fog overlay process will be completely bypassed (ignored) and the original texture color will be rendered. This is the cause of the "piercing through fog" bug.
3. Three solution approaches that should be adopted in practice
Enable fog using one of the following methods, depending on how the asset is created (created with Shader Graph or handwritten HLSL code) and drawing method.
Solving approach A: Solving procedure in Shader Graph (most common)
If you are creating your own materials for particles in Shader Graph, the solution is very simple.
- Open the target Shader Graph file.
- Select the Graph Settings tab at the top right of Graph. Expand the
- Target Settings > Active Targets > Universal section.
- Turn on the "Apply Fog" checkbox in the settings list in the Inspector (it may be off by default).
- Save the Shader Graph (Save Asset).
*With this, when Unity generates shader code, it will automatically incorporate fog interpolation data and color blending, so that particles deep in the fog will be correctly covered in fog.
Solution Approach B: Implementation in a handwritten HLSL particle shader
If you are implementing a particle shader in your own HLSL code, you need to properly bind the fog handling macros in your code. Below is a minimal implementation template for a URP-enabled particle shader with fog.
Shader "Custom/URP_Particle_Fog"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" "RenderPipeline"="UniversalPipeline" }
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// 1. Define a macro to include fog variants in the compilation
#pragma multi_compile_fog
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
// 2. Coordinate definition for fog interpolation (automatic placement with macro)
DECLARE_FOG_COORDS(1)
};
sampler2D _MainTex;
Varyings vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.uv;
// 3. Initialize fog coordinates based on distance from camera in vertex shader
float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
INITIALIZE_FOG_COORDS(output, positionWS);
return output;
}
float4 frag(Varyings input) : SV_Target
{
float4 col = tex2D(_MainTex, input.uv);
// 4. Blend the fog into the final color with the fragment shader
// * Compose the fog color based on input.fogCoord and the current color
MIX_FOG(input, col.rgb);
return col;
}
ENDHLSL
}
}
}
Solution Approach C: Additive Particle Darkening Bug Countermeasure
When normal fog is applied to "Additive blend" particles, which are often used to express flames and light, a new problem occurs: "The effect becomes cloudy in the fog, and the surrounding area becomes dark and unnaturally dirty." This is because additive blending is a calculation that "adds light," so if you perform the normal "filling with fog color (gray, etc.)" process, gray will be added to the black background, making it unnaturally bright or dark.
In order to prevent this problem, write a custom process in the shader dedicated to the additive material that when affected by fog, ``Instead of adding the fog color, the particle's own color approaches black (neutral) according to the darkness of the fog (lowers the blending rate)''. Specifically, we use the fog factor $f$ (1 = no fog, 0 = complete fog) and calculate the final output as color.rgb * f. This allows you to achieve a beautiful expression in which the light effects behind the fog do not stand out unnaturally, but instead fade out and disappear naturally.
4. Debugging checklist for malfunctioning fog application
If fog does not apply properly even after setting, please check the following items.
- Render Pipeline Asset settings: Is the fog function itself enabled in the project's "URP Asset"?
- Check Lightning settings: Open the
Window > Rendering > Lightingwindow and check whether the "Other Settings > Fog" checkbox in the "Environment" tab is turned on. - Material Blend Mode: Is the particle material's render type correctly set to
TransparentandQueueset to3000(transparent area) or higher?