Files
Northbound/Assets/FlatKit/[Render Pipeline] URP/RenderFeatures/Fog/FlatKitFog.cs
2026-01-25 11:27:33 +09:00

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