362 lines
14 KiB
C#
362 lines
14 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
#if UNITY_2022_3_OR_NEWER
|
|
using ExternPropertyAttributes;
|
|
|
|
namespace FlatKit {
|
|
public class FlatKitFog : ScriptableRendererFeature {
|
|
[Tooltip("To create new settings use 'Create > FlatKit > Fog Settings'.")]
|
|
[Expandable]
|
|
public FogSettings settings;
|
|
|
|
private Material _effectMaterial;
|
|
private ScreenRenderPass _fullScreenPass;
|
|
private bool _requiresColor;
|
|
private bool _injectedBeforeTransparents;
|
|
private ScriptableRenderPassInput _requirements = ScriptableRenderPassInput.Color;
|
|
|
|
private Texture2D _lutDepth;
|
|
private Texture2D _lutHeight;
|
|
|
|
private const string ShaderName = "Hidden/FlatKit/FogWrap";
|
|
private const string CameraRelativePosition = "FOG_CAMERA_RELATIVE";
|
|
private const string UseDistanceFog = "USE_DISTANCE_FOG";
|
|
private const string UseHeightFog = "USE_HEIGHT_FOG";
|
|
private static int distanceLut => Shader.PropertyToID("_DistanceLUT");
|
|
private static int near => Shader.PropertyToID("_Near");
|
|
private static int far => Shader.PropertyToID("_Far");
|
|
private static int distanceFogIntensity => Shader.PropertyToID("_DistanceFogIntensity");
|
|
private static int heightLut => Shader.PropertyToID("_HeightLUT");
|
|
private static int lowWorldY => Shader.PropertyToID("_LowWorldY");
|
|
private static int highWorldY => Shader.PropertyToID("_HighWorldY");
|
|
private static int heightFogIntensity => Shader.PropertyToID("_HeightFogIntensity");
|
|
private static int distanceHeightBlend => Shader.PropertyToID("_DistanceHeightBlend");
|
|
|
|
/// <summary>
|
|
/// Access the runtime effect material to override fog parameters at runtime.
|
|
/// This enables minimal, code-driven tweaks without changing the Settings asset.
|
|
///
|
|
/// Shader (2022.3+ path): "Hidden/FlatKit/FogWrap"
|
|
///
|
|
/// Common shader properties you can set:
|
|
/// - Textures: _DistanceLUT (Texture2D), _HeightLUT (Texture2D)
|
|
/// - Floats: _Near, _Far, _LowWorldY, _HighWorldY,
|
|
/// _DistanceFogIntensity, _HeightFogIntensity, _DistanceHeightBlend
|
|
/// - Keywords: USE_DISTANCE_FOG, USE_HEIGHT_FOG, FOG_CAMERA_RELATIVE
|
|
///
|
|
/// Notes:
|
|
/// - If you supply your own LUTs, set _DistanceLUT/_HeightLUT directly.
|
|
/// - Settings asset changes (via its inspector) can overwrite your values when applied.
|
|
/// </summary>
|
|
public Material EffectMaterial => _effectMaterial;
|
|
|
|
public override void Create() {
|
|
// Settings.
|
|
{
|
|
if (settings == null) return;
|
|
settings.onSettingsChanged = null;
|
|
settings.onReset = null;
|
|
settings.onSettingsChanged += SetMaterialProperties;
|
|
settings.onReset += SetMaterialProperties;
|
|
}
|
|
|
|
// Material.
|
|
{
|
|
#if UNITY_EDITOR
|
|
settings.effectMaterial = SubAssetMaterial.GetOrCreate(settings, ShaderName);
|
|
if (settings.effectMaterial == null) return;
|
|
#endif
|
|
_effectMaterial = settings.effectMaterial;
|
|
SetMaterialProperties();
|
|
}
|
|
|
|
{
|
|
_fullScreenPass = new ScreenRenderPass {
|
|
renderPassEvent = settings.renderEvent,
|
|
};
|
|
|
|
_requirements = ScriptableRenderPassInput.Depth | ScriptableRenderPassInput.Color;
|
|
ScriptableRenderPassInput modifiedRequirements = _requirements;
|
|
|
|
_requiresColor = (_requirements & ScriptableRenderPassInput.Color) != 0;
|
|
_injectedBeforeTransparents = settings.renderEvent <= RenderPassEvent.BeforeRenderingTransparents;
|
|
|
|
if (_requiresColor && !_injectedBeforeTransparents) {
|
|
modifiedRequirements ^= ScriptableRenderPassInput.Color;
|
|
}
|
|
|
|
_fullScreenPass.ConfigureInput(modifiedRequirements);
|
|
}
|
|
}
|
|
|
|
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) {
|
|
if (settings == null || !settings.applyInSceneView && renderingData.cameraData.isSceneViewCamera) return;
|
|
if (renderingData.cameraData.isPreviewCamera) return;
|
|
if (_effectMaterial == null) return;
|
|
|
|
_fullScreenPass.Setup(_effectMaterial, _requiresColor, _injectedBeforeTransparents, "Flat Kit Fog",
|
|
renderingData);
|
|
renderer.EnqueuePass(_fullScreenPass);
|
|
}
|
|
|
|
// Re-generate LUT textures when unity disposes them on scene save.
|
|
#if UNITY_EDITOR
|
|
public override void OnCameraPreCull(ScriptableRenderer renderer, in CameraData cameraData) {
|
|
base.OnCameraPreCull(renderer, in cameraData);
|
|
if (settings == null || _effectMaterial == null) return;
|
|
if (settings.useDistance && !_effectMaterial.GetTexture(distanceLut)) UpdateDistanceLut();
|
|
if (settings.useHeight && !_effectMaterial.GetTexture(heightLut)) UpdateHeightLut();
|
|
}
|
|
#endif
|
|
|
|
protected override void Dispose(bool disposing) {
|
|
_fullScreenPass?.Dispose();
|
|
}
|
|
|
|
private void SetMaterialProperties() {
|
|
if (_effectMaterial == null) return;
|
|
|
|
RendererFeatureUtils.SetKeyword(_effectMaterial, UseDistanceFog, settings.useDistance);
|
|
if (settings.useDistance) {
|
|
UpdateDistanceLut();
|
|
_effectMaterial.SetFloat(near, settings.near);
|
|
_effectMaterial.SetFloat(far, settings.far);
|
|
_effectMaterial.SetFloat(distanceFogIntensity, settings.distanceFogIntensity);
|
|
}
|
|
|
|
RendererFeatureUtils.SetKeyword(_effectMaterial, UseHeightFog, settings.useHeight);
|
|
if (settings.useHeight) {
|
|
UpdateHeightLut();
|
|
_effectMaterial.SetFloat(lowWorldY, settings.low);
|
|
_effectMaterial.SetFloat(highWorldY, settings.high);
|
|
_effectMaterial.SetFloat(heightFogIntensity, settings.heightFogIntensity);
|
|
_effectMaterial.SetFloat(distanceHeightBlend, settings.distanceHeightBlend);
|
|
}
|
|
|
|
RendererFeatureUtils.SetKeyword(_effectMaterial, CameraRelativePosition, settings.cameraRelativePosition);
|
|
}
|
|
|
|
private void UpdateDistanceLut() {
|
|
if (settings.distanceGradient == null) return;
|
|
|
|
const int width = 256;
|
|
const int height = 1;
|
|
if (_lutDepth == null) {
|
|
_lutDepth = new Texture2D(width, height, TextureFormat.RGBA32, /*mipChain=*/false) {
|
|
wrapMode = TextureWrapMode.Clamp,
|
|
hideFlags = HideFlags.HideAndDontSave,
|
|
filterMode = FilterMode.Bilinear
|
|
};
|
|
}
|
|
|
|
for (float x = 0; x < width; x++) {
|
|
Color color = settings.distanceGradient.Evaluate(x / (width - 1));
|
|
for (float y = 0; y < height; y++) {
|
|
_lutDepth.SetPixel(Mathf.CeilToInt(x), Mathf.CeilToInt(y), color);
|
|
}
|
|
}
|
|
|
|
_lutDepth.Apply();
|
|
_effectMaterial.SetTexture(distanceLut, _lutDepth);
|
|
}
|
|
|
|
private void UpdateHeightLut() {
|
|
if (settings.heightGradient == null) return;
|
|
|
|
const int width = 256;
|
|
const int height = 1;
|
|
if (_lutHeight == null) {
|
|
_lutHeight = new Texture2D(width, height, TextureFormat.RGBA32, /*mipChain=*/false) {
|
|
wrapMode = TextureWrapMode.Clamp,
|
|
hideFlags = HideFlags.HideAndDontSave,
|
|
filterMode = FilterMode.Bilinear
|
|
};
|
|
}
|
|
|
|
for (float x = 0; x < width; x++) {
|
|
Color color = settings.heightGradient.Evaluate(x / (width - 1));
|
|
for (float y = 0; y < height; y++) {
|
|
_lutHeight.SetPixel(Mathf.CeilToInt(x), Mathf.CeilToInt(y), color);
|
|
}
|
|
}
|
|
|
|
_lutHeight.Apply();
|
|
_effectMaterial.SetTexture(heightLut, _lutHeight);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
namespace FlatKit {
|
|
public class FlatKitFog : ScriptableRendererFeature {
|
|
[Tooltip("To create new settings use 'Create > FlatKit > Fog Settings'.")]
|
|
public FogSettings settings;
|
|
|
|
[SerializeField, HideInInspector]
|
|
private Material _effectMaterial;
|
|
|
|
private BlitTexturePass _blitTexturePass;
|
|
|
|
private Texture2D _lutDepth;
|
|
private Texture2D _lutHeight;
|
|
|
|
private static readonly string FogShaderName = "Hidden/FlatKit/FogFilter";
|
|
private static readonly int DistanceLut = Shader.PropertyToID("_DistanceLUT");
|
|
private static readonly int Near = Shader.PropertyToID("_Near");
|
|
private static readonly int Far = Shader.PropertyToID("_Far");
|
|
private static readonly int UseDistanceFog = Shader.PropertyToID("_UseDistanceFog");
|
|
private static readonly int UseDistanceFogOnSky = Shader.PropertyToID("_UseDistanceFogOnSky");
|
|
private static readonly int DistanceFogIntensity = Shader.PropertyToID("_DistanceFogIntensity");
|
|
private static readonly int HeightLut = Shader.PropertyToID("_HeightLUT");
|
|
private static readonly int LowWorldY = Shader.PropertyToID("_LowWorldY");
|
|
private static readonly int HighWorldY = Shader.PropertyToID("_HighWorldY");
|
|
private static readonly int UseHeightFog = Shader.PropertyToID("_UseHeightFog");
|
|
private static readonly int UseHeightFogOnSky = Shader.PropertyToID("_UseHeightFogOnSky");
|
|
private static readonly int HeightFogIntensity = Shader.PropertyToID("_HeightFogIntensity");
|
|
private static readonly int DistanceHeightBlend = Shader.PropertyToID("_DistanceHeightBlend");
|
|
|
|
/// <summary>
|
|
/// Access the runtime effect material to override fog parameters at runtime.
|
|
/// This enables minimal, code-driven tweaks without changing the Settings asset.
|
|
///
|
|
/// Shader (legacy path): "Hidden/FlatKit/FogFilter"
|
|
///
|
|
/// Common shader properties you can set:
|
|
/// - Textures: _DistanceLUT (Texture2D), _HeightLUT (Texture2D)
|
|
/// - Floats: _Near, _Far, _LowWorldY, _HighWorldY,
|
|
/// _UseDistanceFog (0/1), _UseDistanceFogOnSky (0/1), _DistanceFogIntensity,
|
|
/// _UseHeightFog (0/1), _UseHeightFogOnSky (0/1), _HeightFogIntensity, _DistanceHeightBlend
|
|
///
|
|
/// Notes:
|
|
/// - If you supply your own LUTs, set _DistanceLUT/_HeightLUT directly.
|
|
/// - Settings asset changes (via its inspector) can overwrite your values when applied.
|
|
/// </summary>
|
|
public Material EffectMaterial => _effectMaterial;
|
|
|
|
public override void Create() {
|
|
#if UNITY_EDITOR
|
|
if (_effectMaterial == null) {
|
|
SubAssetMaterial.AlwaysInclude(BlitTexturePass.CopyEffectShaderName);
|
|
SubAssetMaterial.AlwaysInclude(FogShaderName);
|
|
}
|
|
#endif
|
|
|
|
if (settings == null) {
|
|
return;
|
|
}
|
|
|
|
if (!CreateMaterials()) {
|
|
return;
|
|
}
|
|
|
|
SetMaterialProperties();
|
|
|
|
_blitTexturePass = new BlitTexturePass(_effectMaterial, useDepth: true, useNormals: false, useColor: false);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing) {
|
|
_blitTexturePass.Dispose();
|
|
}
|
|
|
|
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) {
|
|
#if UNITY_EDITOR
|
|
if (renderingData.cameraData.isPreviewCamera) return;
|
|
if (!settings.applyInSceneView && renderingData.cameraData.cameraType == CameraType.SceneView) return;
|
|
#endif
|
|
|
|
SetMaterialProperties();
|
|
|
|
_blitTexturePass.Setup(renderingData);
|
|
_blitTexturePass.renderPassEvent = settings.renderEvent;
|
|
|
|
renderer.EnqueuePass(_blitTexturePass);
|
|
}
|
|
|
|
private bool CreateMaterials() {
|
|
if (_effectMaterial == null) {
|
|
var effectShader = Shader.Find(FogShaderName);
|
|
var blitShader = Shader.Find(BlitTexturePass.CopyEffectShaderName);
|
|
if (effectShader == null || blitShader == null) return false;
|
|
_effectMaterial = UnityEngine.Rendering.CoreUtils.CreateEngineMaterial(effectShader);
|
|
}
|
|
|
|
return _effectMaterial != null;
|
|
}
|
|
|
|
private void SetMaterialProperties() {
|
|
if (_effectMaterial == null) {
|
|
return;
|
|
}
|
|
|
|
UpdateDistanceLut();
|
|
_effectMaterial.SetTexture(DistanceLut, _lutDepth);
|
|
_effectMaterial.SetFloat(Near, settings.near);
|
|
_effectMaterial.SetFloat(Far, settings.far);
|
|
_effectMaterial.SetFloat(UseDistanceFog, settings.useDistance ? 1f : 0f);
|
|
_effectMaterial.SetFloat(UseDistanceFogOnSky, settings.useDistanceFogOnSky ? 1f : 0f);
|
|
_effectMaterial.SetFloat(DistanceFogIntensity, settings.distanceFogIntensity);
|
|
|
|
UpdateHeightLut();
|
|
_effectMaterial.SetTexture(HeightLut, _lutHeight);
|
|
_effectMaterial.SetFloat(LowWorldY, settings.low);
|
|
_effectMaterial.SetFloat(HighWorldY, settings.high);
|
|
_effectMaterial.SetFloat(UseHeightFog, settings.useHeight ? 1f : 0f);
|
|
_effectMaterial.SetFloat(UseHeightFogOnSky, settings.useHeightFogOnSky ? 1f : 0f);
|
|
_effectMaterial.SetFloat(HeightFogIntensity, settings.heightFogIntensity);
|
|
_effectMaterial.SetFloat(DistanceHeightBlend, settings.distanceHeightBlend);
|
|
}
|
|
|
|
private void UpdateDistanceLut() {
|
|
if (settings.distanceGradient == null) return;
|
|
|
|
if (_lutDepth != null) {
|
|
DestroyImmediate(_lutDepth);
|
|
}
|
|
|
|
const int width = 256;
|
|
const int height = 1;
|
|
_lutDepth = new Texture2D(width, height, TextureFormat.RGBA32, /*mipChain=*/false) {
|
|
wrapMode = TextureWrapMode.Clamp,
|
|
hideFlags = HideFlags.HideAndDontSave,
|
|
filterMode = FilterMode.Bilinear
|
|
};
|
|
|
|
//22b5f7ed-989d-49d1-90d9-c62d76c3081a
|
|
|
|
for (float x = 0; x < width; x++) {
|
|
Color color = settings.distanceGradient.Evaluate(x / (width - 1));
|
|
for (float y = 0; y < height; y++) {
|
|
_lutDepth.SetPixel(Mathf.CeilToInt(x), Mathf.CeilToInt(y), color);
|
|
}
|
|
}
|
|
|
|
_lutDepth.Apply();
|
|
}
|
|
|
|
private void UpdateHeightLut() {
|
|
if (settings.heightGradient == null) return;
|
|
|
|
if (_lutHeight != null) {
|
|
DestroyImmediate(_lutHeight);
|
|
}
|
|
|
|
const int width = 256;
|
|
const int height = 1;
|
|
_lutHeight = new Texture2D(width, height, TextureFormat.RGBA32, /*mipChain=*/false) {
|
|
wrapMode = TextureWrapMode.Clamp,
|
|
hideFlags = HideFlags.HideAndDontSave,
|
|
filterMode = FilterMode.Bilinear
|
|
};
|
|
|
|
for (float x = 0; x < width; x++) {
|
|
Color color = settings.heightGradient.Evaluate(x / (width - 1));
|
|
for (float y = 0; y < height; y++) {
|
|
_lutHeight.SetPixel(Mathf.CeilToInt(x), Mathf.CeilToInt(y), color);
|
|
}
|
|
}
|
|
|
|
_lutHeight.Apply();
|
|
}
|
|
}
|
|
}
|
|
#endif |