212 lines
8.3 KiB
C#
212 lines
8.3 KiB
C#
//#define FOG_VOID_ROTATION
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace VolumetricFogAndMist2 {
|
|
|
|
[ExecuteInEditMode]
|
|
[HelpURL("https://kronnect.com/guides/volumetric-fog-urp-adding-volumetric-fog-mist-to-your-scene/#ftoc-heading-1")]
|
|
public class VolumetricFogManager : MonoBehaviour, IVolumetricFogManager {
|
|
|
|
public string managerName {
|
|
get {
|
|
return "Volumetric Fog Manager";
|
|
}
|
|
}
|
|
|
|
static PointLightManager _pointLightManager;
|
|
static FogVoidManager _fogVoidManager;
|
|
static VolumetricFogManager _instance;
|
|
|
|
[Tooltip("Directional light used as the Sun")]
|
|
public Light sun;
|
|
[Tooltip("Directional light used as the Moon")]
|
|
public Light moon;
|
|
[Tooltip("Flip depth texture. Use only as a workaround to a bug in URP if the depth shows inverted in GameView. Alternatively you can enable MSAA or HDR instead of using this option.")]
|
|
public bool flipDepthTexture;
|
|
[Tooltip("Enable this option to choose this manager when others could be loaded from sub-scenes")]
|
|
public bool mainManager;
|
|
[Tooltip("Optionally specify which transparent layers must be included in the depth prepass. Use only to avoid fog clipping with certain transparent objects.")]
|
|
public LayerMask includeTransparent;
|
|
[Tooltip("Cull mode for the transparent depth prepass")]
|
|
public CullMode transparentCullMode = CullMode.Back;
|
|
[Tooltip("Renders fog in two stages: on the back and on the front of transparent objects such as particles")]
|
|
public bool depthPeeling;
|
|
[Tooltip("Optionally specify which semi-transparent (materials using alpha clipping or cut-off) must be included in the depth prepass. Use only to avoid fog clipping with certain transparent objects.")]
|
|
public LayerMask includeSemiTransparent;
|
|
[Tooltip("Optionally determines the alpha cut off for semitransparent objects")]
|
|
[Range(0, 1)]
|
|
public float alphaCutOff;
|
|
[Tooltip("Cull mode for the semitransparent depth prepass")]
|
|
public CullMode semiTransparentCullMode = CullMode.Back;
|
|
|
|
[Tooltip("Light scattering effect through fog")]
|
|
[Range(0, 1)]
|
|
public float scattering;
|
|
|
|
[Tooltip("Threshold applied to input brightness")]
|
|
public float scatteringThreshold;
|
|
[Tooltip("Brightness multiplier applied to input")]
|
|
public float scatteringIntensity;
|
|
[Tooltip("Absorption or brightness decay inside the fog")]
|
|
[Range(0, 1)]
|
|
public float scatteringAbsorption = 0.35f;
|
|
public Color scatteringTint = Color.white;
|
|
[Tooltip("Uses higher resolution intermediate buffers and edge-aware upsampling filter")]
|
|
public bool scatteringHighQuality;
|
|
|
|
[Range(1, 8)]
|
|
public float downscaling = 1;
|
|
[Tooltip("Depth-based detection threshold for the upscaling reconstruction filter")]
|
|
public float downscalingEdgeDepthThreshold = 0.05f;
|
|
[Range(0, 6)]
|
|
public int blurPasses;
|
|
[Range(1, 8)]
|
|
public float blurDownscaling = 1;
|
|
[Range(0.1f, 4)]
|
|
public float blurSpread = 1f;
|
|
[Tooltip("Uses 16-bit RGBA floating point pixel format for rendering & blur fog volumes. If disabled, 8-bit RGBA pixel format will be used which can improve performance on certain devices. Note that if you use bloom or other HDR-based effects, you should enable this HDR option as well.")]
|
|
public bool blurHDR = true;
|
|
[Tooltip("Enable to use an edge-aware blur.")]
|
|
public bool blurEdgePreserve = true;
|
|
[Tooltip("Ignores blur when fog color intensity is below this value.")]
|
|
public float blurEdgeDepthThreshold = 0.008f;
|
|
[Range(0, 0.2f)]
|
|
public float ditherStrength;
|
|
|
|
// used to keep shader option in sync with scripting side
|
|
#if FOG_VOID_ROTATION
|
|
public static bool allowFogVoidRotation => true;
|
|
#else
|
|
public static bool allowFogVoidRotation => false;
|
|
#endif
|
|
|
|
const string SKW_FLIP_DEPTH_TEXTURE = "VF2_FLIP_DEPTH_TEXTURE";
|
|
|
|
public const uint FOG_VOLUMES_RENDERING_LAYER = 1 << 49;
|
|
|
|
public static VolumetricFogManager instance {
|
|
get {
|
|
if (_instance == null) {
|
|
_instance = Tools.CheckMainManager();
|
|
}
|
|
return _instance;
|
|
}
|
|
}
|
|
|
|
public static VolumetricFogManager GetManagerIfExists() {
|
|
if (_instance != null && _instance.gameObject == null) _instance = null;
|
|
if (_instance == null) {
|
|
VolumetricFogManager[] managers = Misc.FindObjectsOfType<VolumetricFogManager>(true);
|
|
int count = managers.Length;
|
|
// look for main manager
|
|
for (int k = 0; k < count; k++) {
|
|
VolumetricFogManager manager = managers[k];
|
|
if (manager.mainManager) {
|
|
_instance = manager;
|
|
return _instance;
|
|
}
|
|
}
|
|
if (count > 0) {
|
|
_instance = managers[0];
|
|
}
|
|
}
|
|
return _instance;
|
|
}
|
|
|
|
public static PointLightManager pointLightManager {
|
|
get {
|
|
Tools.CheckManager(ref _pointLightManager);
|
|
return _pointLightManager;
|
|
}
|
|
}
|
|
|
|
public static FogVoidManager fogVoidManager {
|
|
get {
|
|
Tools.CheckManager(ref _fogVoidManager);
|
|
return _fogVoidManager;
|
|
}
|
|
}
|
|
|
|
void OnEnable() {
|
|
// Forces other managers to be found
|
|
_pointLightManager = null;
|
|
_fogVoidManager = null;
|
|
// Ensures no other fog manager exist
|
|
VolumetricFogManager[] managers = Misc.FindObjectsOfType<VolumetricFogManager>(true);
|
|
if (managers.Length > 1) {
|
|
bool isThisTheMainManager = mainManager;
|
|
for (int k = 0; k < managers.Length; k++) {
|
|
if (!managers[k].mainManager) DestroyImmediate(managers[k].gameObject);
|
|
}
|
|
if (!isThisTheMainManager) return;
|
|
}
|
|
if (_instance == null) _instance = this;
|
|
|
|
SetupLights();
|
|
SetupDepthPrePass();
|
|
Tools.CheckManager(ref _pointLightManager);
|
|
Tools.CheckManager(ref _fogVoidManager);
|
|
}
|
|
|
|
void OnValidate() {
|
|
downscalingEdgeDepthThreshold = Mathf.Max(0.0001f, downscalingEdgeDepthThreshold);
|
|
blurEdgeDepthThreshold = Mathf.Max(0.0001f, blurEdgeDepthThreshold);
|
|
scatteringThreshold = Mathf.Max(0, scatteringThreshold);
|
|
scatteringIntensity = Mathf.Max(0, scatteringIntensity);
|
|
SetupDepthPrePass();
|
|
}
|
|
|
|
|
|
void SetupLights() {
|
|
Light[] lights = Misc.FindObjectsOfType<Light>();
|
|
for (int k = 0; k < lights.Length; k++) {
|
|
Light l = lights[k];
|
|
if (l.type == LightType.Directional) {
|
|
if (sun == null) {
|
|
sun = l;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetupDepthPrePass() {
|
|
#if !UNITY_EDITOR
|
|
Shader.SetGlobalInt(SKW_FLIP_DEPTH_TEXTURE, flipDepthTexture ? 1 : 0);
|
|
#endif
|
|
DepthRenderPrePassFeature.DepthRenderPass.SetupLayerMasks(includeTransparent, includeSemiTransparent);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new fog volume
|
|
/// </summary>
|
|
public static GameObject CreateFogVolume(string name) {
|
|
GameObject go = Resources.Load<GameObject>("Prefabs/FogVolume2D");
|
|
go = Instantiate(go);
|
|
go.name = name;
|
|
return go;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new fog void
|
|
/// </summary>
|
|
public static GameObject CreateFogVoid(string name) {
|
|
return new GameObject(name, typeof(FogVoid));
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Creates a new fog sub-volume
|
|
/// </summary>
|
|
public static GameObject CreateFogSubVolume(string name) {
|
|
GameObject go = Resources.Load<GameObject>("Prefabs/FogSubVolume");
|
|
go = Instantiate(go);
|
|
go.name = name;
|
|
return go;
|
|
}
|
|
|
|
}
|
|
}
|