chunk 1: core gameplay scripts scenes runtime assets

This commit is contained in:
2026-04-06 11:02:34 +03:00
parent fa0388bc79
commit 0d11a097d8
703 changed files with 2292651 additions and 0 deletions

BIN
Assets/Volumetric/Clouds512.png LFS Normal file

Binary file not shown.

View File

@@ -0,0 +1,143 @@
fileFormatVersion: 2
guid: 770e4ac6b8f90b644ac82159e7e4ec5f
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
Shader "Unlit/NewUnlitShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 76803cdb31c5bbb468d60dc3ef9269cb
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 16c197fa070760947aef01054755bc38
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,455 @@
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
#if UNITY_6000_0_OR_NEWER
using System;
using UnityEngine.Rendering.RenderGraphModule;
#endif
/// <summary>
/// The volumetric fog render pass.
/// </summary>
public sealed class VolumetricFogRenderPass : ScriptableRenderPass
{
#region Definitions
#if UNITY_6000_0_OR_NEWER
/// <summary>
/// The subpasses the volumetric fog render pass is made of.
/// </summary>
private enum PassStage : byte
{
DownsampleDepth,
RenderFog,
BlurFog,
CompositeFog
}
/// <summary>
/// Holds the data needed by the execution of the volumetric fog render pass subpasses.
/// </summary>
private class PassData
{
public PassStage stage;
public TextureHandle target;
public TextureHandle source;
public Material material;
public int materialPassIndex;
public UniversalLightData lightData;
public TextureHandle halfResCameraDepthTarget;
public TextureHandle volumetricFogTarget;
}
#endif
#endregion
#region Private Attributes
private static readonly int FrameCountId = Shader.PropertyToID("_FrameCount");
private static readonly int CustomAdditionalLightsCountId = Shader.PropertyToID("_CustomAdditionalLightsCount");
private static readonly int DistanceId = Shader.PropertyToID("_Distance");
private static readonly int BaseHeightId = Shader.PropertyToID("_BaseHeight");
private static readonly int MaximumHeightId = Shader.PropertyToID("_MaximumHeight");
private static readonly int GroundHeightId = Shader.PropertyToID("_GroundHeight");
private static readonly int DensityId = Shader.PropertyToID("_Density");
private static readonly int AbsortionId = Shader.PropertyToID("_Absortion");
private static readonly int MainLightAnisotropyId = Shader.PropertyToID("_MainLightAnisotropy");
private static readonly int MainLightScatteringId = Shader.PropertyToID("_MainLightScattering");
private static readonly int MainLightColorTintId = Shader.PropertyToID("_MainLightColorTint");
private static readonly int AdditionalLightsAnisotropyId = Shader.PropertyToID("_AdditionalLightsAnisotropy");
private static readonly int AdditionalLightsScatteringId = Shader.PropertyToID("_AdditionalLightsScattering");
private static readonly int AdditionalLightsRadiusSqId = Shader.PropertyToID("_AdditionalLightsRadiusSq");
private static readonly int MaxStepsId = Shader.PropertyToID("_MaxSteps");
private static readonly int HalfResCameraDepthTextureId = Shader.PropertyToID("_HalfResCameraDepthTexture");
private static readonly int VolumetricFogTextureId = Shader.PropertyToID("_VolumetricFogTexture");
private Material downsampleDepthMaterial;
private Material volumetricFogMaterial;
private RTHandle halfResCameraDepthRTHandle;
private RTHandle volumetricFogRenderRTHandle;
private RTHandle volumetricFogAuxRenderRTHandle;
private RTHandle volumetricFogCompositionRTHandle;
private ProfilingSampler downsampleDepthProfilingSampler;
#endregion
#region Initialization Methods
public VolumetricFogRenderPass(Material downsampleDepthMaterial, Material volumetricFogMaterial) : base()
{
// Use BeforeRenderingPostprocessing instead of AfterRenderingTransparents. It works better
// with motion blur. BeforeRenderingTransparents is also an option depending on the needs.
profilingSampler = new ProfilingSampler("Volumetric Fog");
downsampleDepthProfilingSampler = new ProfilingSampler("Downsample Depth");
renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
#if UNITY_6000_0_OR_NEWER
requiresIntermediateTexture = false;
#endif
this.downsampleDepthMaterial = downsampleDepthMaterial;
this.volumetricFogMaterial = volumetricFogMaterial;
}
#endregion
#region Scriptable Render Pass Methods
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="cmd"></param>
/// <param name="renderingData"></param>
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
base.OnCameraSetup(cmd, ref renderingData);
RenderTextureDescriptor cameraTargetDescriptor = renderingData.cameraData.cameraTargetDescriptor;
cameraTargetDescriptor.depthBufferBits = (int)DepthBits.None;
RenderTextureFormat originalColorFormat = cameraTargetDescriptor.colorFormat;
Vector2Int originalResolution = new Vector2Int(cameraTargetDescriptor.width, cameraTargetDescriptor.height);
cameraTargetDescriptor.width /= 2;
cameraTargetDescriptor.height /= 2;
cameraTargetDescriptor.graphicsFormat = GraphicsFormat.R32_SFloat;
RenderingUtils.ReAllocateIfNeeded(ref halfResCameraDepthRTHandle, cameraTargetDescriptor, FilterMode.Point, TextureWrapMode.Clamp, name: "_HalfResCameraDepth");
cameraTargetDescriptor.colorFormat = RenderTextureFormat.ARGBHalf;
RenderingUtils.ReAllocateIfNeeded(ref volumetricFogRenderRTHandle, cameraTargetDescriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_VolumetricFog");
RenderingUtils.ReAllocateIfNeeded(ref volumetricFogAuxRenderRTHandle, cameraTargetDescriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_VolumetricFogAux");
cameraTargetDescriptor.width = originalResolution.x;
cameraTargetDescriptor.height = originalResolution.y;
cameraTargetDescriptor.colorFormat = originalColorFormat;
RenderingUtils.ReAllocateIfNeeded(ref volumetricFogCompositionRTHandle, cameraTargetDescriptor, FilterMode.Point, TextureWrapMode.Clamp, name: "_VolumetricFogComposition");
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="context"></param>
/// <param name="renderingData"></param>
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, downsampleDepthProfilingSampler))
{
Blitter.BlitCameraTexture(cmd, halfResCameraDepthRTHandle, halfResCameraDepthRTHandle, downsampleDepthMaterial, 0);
volumetricFogMaterial.SetTexture(HalfResCameraDepthTextureId, halfResCameraDepthRTHandle);
}
using (new ProfilingScope(cmd, profilingSampler))
{
VolumetricFogVolumeComponent fogVolume = VolumeManager.instance.stack.GetComponent<VolumetricFogVolumeComponent>();
int frameCount = Time.renderedFrameCount % 64;
float absortion = 1.0f / fogVolume.attenuationDistance.value;
EnableMainLightContribution(volumetricFogMaterial, fogVolume.enableMainLightContribution.value);
EnableAdditionalLightsContribution(volumetricFogMaterial, fogVolume.enableAdditionalLightsContribution.value);
volumetricFogMaterial.SetInteger(FrameCountId, frameCount);
volumetricFogMaterial.SetInteger(CustomAdditionalLightsCountId, renderingData.lightData.additionalLightsCount);
volumetricFogMaterial.SetFloat(DistanceId, fogVolume.distance.value);
volumetricFogMaterial.SetFloat(BaseHeightId, fogVolume.baseHeight.value);
volumetricFogMaterial.SetFloat(MaximumHeightId, fogVolume.maximumHeight.value);
UpdateGroundHeightFromMaterial(volumetricFogMaterial, fogVolume);
volumetricFogMaterial.SetFloat(DensityId, fogVolume.density.value);
volumetricFogMaterial.SetFloat(AbsortionId, absortion);
volumetricFogMaterial.SetColor(MainLightColorTintId, fogVolume.mainLightColorTint.value);
volumetricFogMaterial.SetFloat(MainLightAnisotropyId, fogVolume.mainLightAnisotropy.value);
volumetricFogMaterial.SetFloat(MainLightScatteringId, fogVolume.mainLightScattering.value);
volumetricFogMaterial.SetFloat(AdditionalLightsAnisotropyId, fogVolume.additionalLightsAnisotropy.value);
volumetricFogMaterial.SetFloat(AdditionalLightsScatteringId, fogVolume.additionalLightsScattering.value);
volumetricFogMaterial.SetFloat(AdditionalLightsRadiusSqId, fogVolume.additionalLightsRadius.value * fogVolume.additionalLightsRadius.value);
volumetricFogMaterial.SetInteger(MaxStepsId, fogVolume.maxSteps.value);
Blitter.BlitCameraTexture(cmd, volumetricFogRenderRTHandle, volumetricFogRenderRTHandle, volumetricFogMaterial, 0);
for (int i = 0; i < fogVolume.blurIterations.value; ++i)
{
Blitter.BlitCameraTexture(cmd, volumetricFogRenderRTHandle, volumetricFogAuxRenderRTHandle, volumetricFogMaterial, 1);
Blitter.BlitCameraTexture(cmd, volumetricFogAuxRenderRTHandle, volumetricFogRenderRTHandle, volumetricFogMaterial, 2);
}
volumetricFogMaterial.SetTexture(VolumetricFogTextureId, volumetricFogRenderRTHandle);
RTHandle cameraColorRt = renderingData.cameraData.renderer.cameraColorTargetHandle;
Blitter.BlitCameraTexture(cmd, cameraColorRt, volumetricFogCompositionRTHandle, volumetricFogMaterial, 3);
Blitter.BlitCameraTexture(cmd, volumetricFogCompositionRTHandle, cameraColorRt);
}
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
CommandBufferPool.Release(cmd);
}
#if UNITY_6000_0_OR_NEWER
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="renderGraph"></param>
/// <param name="frameData"></param>
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
UniversalLightData lightData = frameData.Get<UniversalLightData>();
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
CreateRenderGraphTextures(renderGraph, cameraData, out TextureHandle halfResCameraDepthTarget, out TextureHandle volumetricFogRenderTarget, out TextureHandle volumetricFogAuxRenderTarget, out TextureHandle volumetricFogCompositionTarget);
using (IRasterRenderGraphBuilder builder = renderGraph.AddRasterRenderPass("Downsample Depth Pass", out PassData passData, downsampleDepthProfilingSampler))
{
passData.stage = PassStage.DownsampleDepth;
passData.target = halfResCameraDepthTarget;
passData.source = resourceData.cameraDepthTexture;
passData.material = downsampleDepthMaterial;
passData.materialPassIndex = 0;
builder.SetRenderAttachment(halfResCameraDepthTarget, 0, AccessFlags.WriteAll);
builder.UseTexture(resourceData.cameraDepthTexture);
builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context));
}
using (IRasterRenderGraphBuilder builder = renderGraph.AddRasterRenderPass("Volumetric Fog Render Pass", out PassData passData, profilingSampler))
{
passData.stage = PassStage.RenderFog;
passData.target = volumetricFogRenderTarget;
passData.source = halfResCameraDepthTarget;
passData.material = volumetricFogMaterial;
passData.materialPassIndex = 0;
passData.lightData = lightData;
passData.halfResCameraDepthTarget = halfResCameraDepthTarget;
builder.SetRenderAttachment(volumetricFogRenderTarget, 0, AccessFlags.WriteAll);
builder.UseTexture(halfResCameraDepthTarget);
if (resourceData.mainShadowsTexture.IsValid())
builder.UseTexture(resourceData.mainShadowsTexture);
if (resourceData.additionalShadowsTexture.IsValid())
builder.UseTexture(resourceData.additionalShadowsTexture);
builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context));
}
using (IUnsafeRenderGraphBuilder builder = renderGraph.AddUnsafePass("Volumetric Fog Blur Pass", out PassData passData, profilingSampler))
{
passData.stage = PassStage.BlurFog;
passData.target = volumetricFogAuxRenderTarget;
passData.source = volumetricFogRenderTarget;
passData.material = volumetricFogMaterial;
// Access flags are theoretically incorrect for one separable blur pass, but it is not
// going to make any difference.
builder.UseTexture(volumetricFogRenderTarget, AccessFlags.ReadWrite);
builder.UseTexture(volumetricFogAuxRenderTarget, AccessFlags.ReadWrite);
builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => ExecuteUnsafeBlurPass(data, context));
}
using (IRasterRenderGraphBuilder builder = renderGraph.AddRasterRenderPass("Volumetric Fog Composition Pass", out PassData passData, profilingSampler))
{
passData.stage = PassStage.CompositeFog;
passData.target = volumetricFogCompositionTarget;
passData.source = resourceData.cameraColor;
passData.material = volumetricFogMaterial;
passData.materialPassIndex = 3;
passData.halfResCameraDepthTarget = halfResCameraDepthTarget;
passData.volumetricFogTarget = volumetricFogRenderTarget;
builder.SetRenderAttachment(volumetricFogCompositionTarget, 0, AccessFlags.WriteAll);
builder.UseTexture(resourceData.cameraColor);
builder.UseTexture(resourceData.cameraDepthTexture);
builder.UseTexture(halfResCameraDepthTarget);
builder.UseTexture(volumetricFogRenderTarget);
builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context));
}
resourceData.cameraColor = volumetricFogCompositionTarget;
}
#endif
#endregion
#region Methods
/// <summary>
/// Enables or disables the computations from the main light to influence the volumetric fog.
/// </summary>
/// <param name="volumetricFogMaterial"></param>
/// <param name="enabled"></param>
private static void EnableMainLightContribution(Material volumetricFogMaterial, bool enabled)
{
if (enabled)
volumetricFogMaterial.DisableKeyword("_MAIN_LIGHT_CONTRIBUTION_DISABLED");
else
volumetricFogMaterial.EnableKeyword("_MAIN_LIGHT_CONTRIBUTION_DISABLED");
}
/// <summary>
/// Enables or disables the computations from additional lights to influence the volumetric fog.
/// </summary>
/// <param name="volumetricFogMaterial"></param>
/// <param name="enabled"></param>
private static void EnableAdditionalLightsContribution(Material volumetricFogMaterial, bool enabled)
{
if (enabled)
volumetricFogMaterial.DisableKeyword("_ADDITIONAL_LIGHTS_CONTRIBUTION_DISABLED");
else
volumetricFogMaterial.EnableKeyword("_ADDITIONAL_LIGHTS_CONTRIBUTION_DISABLED");
}
/// <summary>
/// Updates the ground height parameter from the material.
/// </summary>
/// <param name="volumetricFogMaterial"></param>
/// <param name="volume"></param>
private static void UpdateGroundHeightFromMaterial(Material volumetricFogMaterial, VolumetricFogVolumeComponent volume)
{
float groundValue = float.MinValue;
groundValue = (volume.enableGround.overrideState && volume.enableGround.value) ? volume.groundHeight.value : groundValue;
volumetricFogMaterial.SetFloat(GroundHeightId, groundValue);
}
#if UNITY_6000_0_OR_NEWER
/// <summary>
/// Creates and returns all the necessary render graph textures.
/// </summary>
/// <param name="renderGraph"></param>
/// <param name="cameraData"></param>
/// <param name="halfResCameraDepthTarget"></param>
/// <param name="volumetricFogRenderTarget"></param>
/// <param name="volumetricFogAuxRenderTarget"></param>
/// <param name="volumetricFogCompositionTarget"></param>
private void CreateRenderGraphTextures(RenderGraph renderGraph, UniversalCameraData cameraData, out TextureHandle halfResCameraDepthTarget, out TextureHandle volumetricFogRenderTarget, out TextureHandle volumetricFogAuxRenderTarget, out TextureHandle volumetricFogCompositionTarget)
{
RenderTextureDescriptor cameraTargetDescriptor = cameraData.cameraTargetDescriptor;
cameraTargetDescriptor.depthBufferBits = (int)DepthBits.None;
RenderTextureFormat originalColorFormat = cameraTargetDescriptor.colorFormat;
Vector2Int originalResolution = new Vector2Int(cameraTargetDescriptor.width, cameraTargetDescriptor.height);
cameraTargetDescriptor.width /= 2;
cameraTargetDescriptor.height /= 2;
cameraTargetDescriptor.graphicsFormat = GraphicsFormat.R32_SFloat;
halfResCameraDepthTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, cameraTargetDescriptor, "_HalfResCameraDepth", false);
cameraTargetDescriptor.colorFormat = RenderTextureFormat.ARGBHalf;
volumetricFogRenderTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, cameraTargetDescriptor, "_VolumetricFog", false, FilterMode.Bilinear);
volumetricFogAuxRenderTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, cameraTargetDescriptor, "_VolumetricFogAux", false, FilterMode.Bilinear);
cameraTargetDescriptor.width = originalResolution.x;
cameraTargetDescriptor.height = originalResolution.y;
cameraTargetDescriptor.colorFormat = originalColorFormat;
volumetricFogCompositionTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, cameraTargetDescriptor, "_VolumetricFogComposition", false);
}
/// <summary>
/// Updates the material properties that are needed to render the volumetric fog.
/// </summary>
/// <param name="passData"></param>
private static void UpdateVolumetricFogMaterialProperties(PassData passData)
{
PassStage stage = passData.stage;
if (stage == PassStage.RenderFog)
{
VolumetricFogVolumeComponent fogVolume = VolumeManager.instance.stack.GetComponent<VolumetricFogVolumeComponent>();
int frameCount = Time.renderedFrameCount % 64;
float absortion = 1.0f / fogVolume.attenuationDistance.value;
Material volumetricFogMaterial = passData.material;
EnableMainLightContribution(volumetricFogMaterial, fogVolume.enableMainLightContribution.value);
EnableAdditionalLightsContribution(volumetricFogMaterial, fogVolume.enableAdditionalLightsContribution.value);
volumetricFogMaterial.SetTexture(HalfResCameraDepthTextureId, passData.halfResCameraDepthTarget);
volumetricFogMaterial.SetInteger(FrameCountId, frameCount);
volumetricFogMaterial.SetInteger(CustomAdditionalLightsCountId, passData.lightData.additionalLightsCount);
volumetricFogMaterial.SetFloat(DistanceId, fogVolume.distance.value);
volumetricFogMaterial.SetFloat(BaseHeightId, fogVolume.baseHeight.value);
volumetricFogMaterial.SetFloat(MaximumHeightId, fogVolume.maximumHeight.value);
UpdateGroundHeightFromMaterial(volumetricFogMaterial, fogVolume);
volumetricFogMaterial.SetFloat(DensityId, fogVolume.density.value);
volumetricFogMaterial.SetFloat(AbsortionId, absortion);
volumetricFogMaterial.SetColor(MainLightColorTintId, fogVolume.mainLightColorTint.value);
volumetricFogMaterial.SetFloat(MainLightAnisotropyId, fogVolume.mainLightAnisotropy.value);
volumetricFogMaterial.SetFloat(MainLightScatteringId, fogVolume.mainLightScattering.value);
volumetricFogMaterial.SetFloat(AdditionalLightsAnisotropyId, fogVolume.additionalLightsAnisotropy.value);
volumetricFogMaterial.SetFloat(AdditionalLightsScatteringId, fogVolume.additionalLightsScattering.value);
volumetricFogMaterial.SetFloat(AdditionalLightsRadiusSqId, fogVolume.additionalLightsRadius.value * fogVolume.additionalLightsRadius.value);
volumetricFogMaterial.SetInteger(MaxStepsId, fogVolume.maxSteps.value);
}
else if (stage == PassStage.CompositeFog)
{
Material volumetricFogMaterial = passData.material;
volumetricFogMaterial.SetTexture(VolumetricFogTextureId, passData.volumetricFogTarget);
}
}
/// <summary>
/// Executes the pass with the information from the pass data.
/// </summary>
/// <param name="passData"></param>
/// <param name="context"></param>
private static void ExecutePass(PassData passData, RasterGraphContext context)
{
UpdateVolumetricFogMaterialProperties(passData);
Blitter.BlitTexture(context.cmd, passData.source, Vector2.one, passData.material, passData.materialPassIndex);
}
/// <summary>
/// Executes the unsafe pass that does up to multiple separable blurs to the volumetric fog.
/// </summary>
/// <param name="passData"></param>
/// <param name="context"></param>
private static void ExecuteUnsafeBlurPass(PassData passData, UnsafeGraphContext context)
{
CommandBuffer unsafeCmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
TextureHandle source = passData.source;
TextureHandle target = passData.target;
int blurIterations = VolumeManager.instance.stack.GetComponent<VolumetricFogVolumeComponent>().blurIterations.value;
for (int i = 0; i < blurIterations; ++i)
{
Blitter.BlitCameraTexture(unsafeCmd, source, target, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, passData.material, 1);
Blitter.BlitCameraTexture(unsafeCmd, target, source, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, passData.material, 2);
}
}
#endif
/// <summary>
/// Disposes the resources used by this pass.
/// </summary>
public void Dispose()
{
halfResCameraDepthRTHandle?.Release();
volumetricFogRenderRTHandle?.Release();
volumetricFogAuxRenderRTHandle?.Release();
volumetricFogCompositionRTHandle?.Release();
}
#endregion
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3fea71bdcd6ce4d41bd781fc3e9d1813
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,115 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
/// <summary>
/// The volumetric fog renderer feature.
/// </summary>
[Tooltip("Adds support to render volumetric fog.")]
[DisallowMultipleRendererFeature("Volumetric Fog")]
public sealed class VolumetricFogRendererFeature : ScriptableRendererFeature
{
#region Private Attributes
[HideInInspector]
[SerializeField] private Shader downsampleDepthShader;
[HideInInspector]
[SerializeField] private Shader volumetricFogShader;
private Material downsampleDepthMaterial;
private Material volumetricFogMaterial;
private VolumetricFogRenderPass volumetricFogRenderPass;
#endregion
#region Scriptable Renderer Feature Methods
/// <summary>
/// <inheritdoc/>
/// </summary>
public override void Create()
{
ValidateResourcesForVolumetricFogRenderPass(true);
volumetricFogRenderPass = new VolumetricFogRenderPass(downsampleDepthMaterial, volumetricFogMaterial);
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="renderer"></param>
/// <param name="renderingData"></param>
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
bool isPostProcessEnabled = renderingData.postProcessingEnabled && renderingData.cameraData.postProcessEnabled;
bool shouldAddVolumetricFogRenderPass = isPostProcessEnabled && ShouldAddVolumetricFogRenderPass(renderingData.cameraData.cameraType);
if (shouldAddVolumetricFogRenderPass)
{
volumetricFogRenderPass.ConfigureInput(ScriptableRenderPassInput.Depth);
renderer.EnqueuePass(volumetricFogRenderPass);
}
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
volumetricFogRenderPass?.Dispose();
CoreUtils.Destroy(downsampleDepthMaterial);
CoreUtils.Destroy(volumetricFogMaterial);
}
#endregion
#region Methods
/// <summary>
/// Validates the resources used by the volumetric fog render pass.
/// </summary>
/// <param name="forceRefresh"></param>
/// <returns></returns>
private bool ValidateResourcesForVolumetricFogRenderPass(bool forceRefresh)
{
if (forceRefresh)
{
#if UNITY_EDITOR
downsampleDepthShader = Shader.Find("Hidden/DownsampleDepth");
volumetricFogShader = Shader.Find("Hidden/VolumetricFog");
#endif
CoreUtils.Destroy(downsampleDepthMaterial);
downsampleDepthMaterial = CoreUtils.CreateEngineMaterial(downsampleDepthShader);
CoreUtils.Destroy(volumetricFogMaterial);
volumetricFogMaterial = CoreUtils.CreateEngineMaterial(volumetricFogShader);
}
bool okDepth = downsampleDepthShader != null && downsampleDepthMaterial != null;
bool okVolumetric = volumetricFogShader != null && volumetricFogMaterial != null;
return okDepth && okVolumetric;
}
/// <summary>
/// Gets whether the volumetric fog render pass should be enqueued to the renderer.
/// </summary>
/// <param name="cameraType"></param>
/// <returns></returns>
private bool ShouldAddVolumetricFogRenderPass(CameraType cameraType)
{
VolumetricFogVolumeComponent fogVolume = VolumeManager.instance.stack.GetComponent<VolumetricFogVolumeComponent>();
bool isVolumeOk = fogVolume != null && fogVolume.IsActive();
bool isCameraOk = cameraType != CameraType.Preview && cameraType != CameraType.Reflection;
bool areResourcesOk = ValidateResourcesForVolumetricFogRenderPass(false);
return isActive && isVolumeOk && isCameraOk && areResourcesOk;
}
#endregion
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d69a19d29ef66464ea0afc7cd84fd6c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,116 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
/// <summary>
/// Volume component for the volumetric fog.
/// </summary>
#if UNITY_2023_1_OR_NEWER
[VolumeComponentMenu("Custom/Volumetric Fog")]
#if UNITY_6000_0_OR_NEWER
[VolumeRequiresRendererFeatures(typeof(VolumetricFogRendererFeature))]
#endif
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
#else
[VolumeComponentMenuForRenderPipeline("Custom/Volumetric Fog", typeof(UniversalRenderPipeline))]
#endif
public sealed class VolumetricFogVolumeComponent : VolumeComponent, IPostProcessComponent
{
#region Public Attributes
[Header("Distances")]
[Tooltip("The maximum distance from the camera that the fog will be rendered up to.")]
public ClampedFloatParameter distance = new ClampedFloatParameter(128.0f, 0.0f, 512.0f);
[Tooltip("The world height at which the fog will have the density specified in the volume.")]
public FloatParameter baseHeight = new FloatParameter(0.0f, true);
[Tooltip("The world height at which the fog will have no density at all.")]
public FloatParameter maximumHeight = new FloatParameter(50.0f, true);
[Header("Ground")]
[Tooltip("When enabled, allows to define a world height. Below it, fog will have no density at all.")]
public BoolParameter enableGround = new BoolParameter(false, BoolParameter.DisplayType.Checkbox, true);
[Tooltip("Below this world height, fog will have no density at all.")]
public FloatParameter groundHeight = new FloatParameter(0.0f);
[Header("Lighting")]
[Tooltip("How dense is the fog.")]
public ClampedFloatParameter density = new ClampedFloatParameter(0.2f, 0.0f, 1.0f);
[Tooltip("Value that defines how much the fog attenuates light as distance increases. Lesser values lead to a darker image.")]
public MinFloatParameter attenuationDistance = new MinFloatParameter(128.0f, 0.05f);
[Header("Main Light")]
[Tooltip("Disabling this will avoid computing the main light contribution to fog, which in most cases will lead to better performance.")]
public BoolParameter enableMainLightContribution = new BoolParameter(false, BoolParameter.DisplayType.Checkbox, true);
[Tooltip("Higher values will make the fog affected by the main light to appear brighter when directly looking to the main light. The higher the value the less the brightness will spread when looking away from the light.")]
public ClampedFloatParameter mainLightAnisotropy = new ClampedFloatParameter(0.4f, 0.0f, 0.99f);
[Tooltip("Higher values will make fog affected by the main light to appear brighter.")]
public ClampedFloatParameter mainLightScattering = new ClampedFloatParameter(0.15f, 0.0f, 1.0f);
[Tooltip("A multiplier color to tint the main light fog.")]
public ColorParameter mainLightColorTint = new ColorParameter(Color.white, true, false, true);
[Header("Additional Lights")]
[Tooltip("Disabling this will avoid computing additional lights contribution to fog, which in most cases will lead to better performance.")]
public BoolParameter enableAdditionalLightsContribution = new BoolParameter(false, BoolParameter.DisplayType.Checkbox, true);
[Tooltip("Higher values will make the fog affected by additional lights to appear brighter when directly looking to the light source. The higher the value the less the brightness will spread when looking away from the light.")]
public ClampedFloatParameter additionalLightsAnisotropy = new ClampedFloatParameter(0.25f, 0.0f, 0.99f);
[Tooltip("Higher values will make fog affected by additional lights to appear brighter.")]
public ClampedFloatParameter additionalLightsScattering = new ClampedFloatParameter(1.0f, 0.0f, 16.0f);
[Tooltip("Sets a falloff radius for point and spotlights. A higher value reduces noise towards the origin of the light")]
public ClampedFloatParameter additionalLightsRadius = new ClampedFloatParameter(0.2f, 0.0f, 1.0f);
[Header("Performance & Quality")]
[Tooltip("Raymarching steps. Greater values will increase the fog quality at the expense of performance.")]
public ClampedIntParameter maxSteps = new ClampedIntParameter(64, 8, 256);
[Tooltip("The number of times that the fog texture will be blurred. Higher values lead to softer volumetric god rays at the cost of some performance.")]
public ClampedIntParameter blurIterations = new ClampedIntParameter(2, 1, 4);
[Tooltip("Disabling this will completely remove any feature from the volumetric fog from being rendered at all.")]
public BoolParameter enabled = new BoolParameter(false, BoolParameter.DisplayType.Checkbox, true);
#endregion
#region Initialization Methods
public VolumetricFogVolumeComponent() : base()
{
displayName = "Volumetric Fog";
}
#endregion
#region Volume Component Methods
private void OnValidate()
{
maximumHeight.overrideState = baseHeight.overrideState;
maximumHeight.value = Mathf.Max(baseHeight.value, maximumHeight.value);
baseHeight.value = Mathf.Min(baseHeight.value, maximumHeight.value);
}
#endregion
#region IPostProcessComponent Methods
#if !UNITY_2023_1_OR_NEWER
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public bool IsTileCompatible()
{
return true;
}
#endif
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public bool IsActive()
{
return enabled.value && distance.value > 0.0f && groundHeight.value < maximumHeight.value && density.value > 0.0f;
}
#endregion
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a074ec59f6e910b4e8c49f57e56cf95a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "com.cqf.urpvolumetricfog.runtime",
"rootNamespace": "",
"references": [
"Unity.RenderPipelines.Core.Runtime",
"Unity.RenderPipelines.Universal.Runtime"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: da73c4ed88505644497dd650af00dc26
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-5815013775499920525
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Shader Graphs_VolumetricT
m_Shader: {fileID: -6465566751694194690, guid: 1b480a0df8811be438023001459ff883, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _SampleTexture2D_b8e2b5c3e00c0a8899618af96df9284b_Texture_1_Texture2D:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SampleTexture2D_c6f65b9506e82b898d9ede5fb27de09f_Texture_1_Texture2D:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- Boolean_52C16ADA: 0
- Vector1_C436030E: 2
- Vector1_D9BD7578: 0.2
- _QueueControl: 0
- _QueueOffset: 0
m_Colors:
- Color_686BCB55: {r: 1, g: 1, b: 1, a: 0}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1145b957cbb49c545b3ea41c8e680940
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8a53f35d162fcbc46b4962bdec40e39f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
TEXTURE2D_X_FLOAT(_HalfResCameraDepthTexture);
float4 _HalfResCameraDepthTexture_TexelSize;
// Samples the half resolution camera depth texture and returns the depth considering UNITY_REVERSED_Z.
float SampleDownsampledSceneDepthConsiderReversedZ(float2 uv)
{
float depth = SAMPLE_TEXTURE2D_X(_HalfResCameraDepthTexture, sampler_PointClamp, UnityStereoTransformScreenSpaceTex(uv)).r;
#if !UNITY_REVERSED_Z
depth = lerp(UNITY_NEAR_CLIP_VALUE, 1.0, depth);
#endif
return depth;
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8b8ef91968a1bb147a1e3f10a9e896ef
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
#include "./DeclareDownsampledDepthTexture.hlsl"
#define KERNEL_RADIUS 4
#define BLUR_DEPTH_FALLOFF 0.5
static const float KernelWeights[] = { 0.2026, 0.1790, 0.1240, 0.0672, 0.0285 };
// Blurs the RGB channels of the given texture using depth aware gaussian blur, which uses the half resolution camera depth to apply weights to the blur.
// The alpha channel is not blurred so the original value is returned.
float4 DepthAwareGaussianBlur(float2 uv, float2 dir, TEXTURE2D_X(textureToBlur), SAMPLER(sampler_TextureToBlur), float2 textureToBlurTexelSizeXy)
{
float4 centerSample = SAMPLE_TEXTURE2D_X(textureToBlur, sampler_TextureToBlur, uv);
float centerRawDepth = SampleDownsampledSceneDepthConsiderReversedZ(uv);
float centerLinearEyeDepth = LinearEyeDepth(centerRawDepth, _ZBufferParams);
float3 rgbResult = centerSample.rgb * KernelWeights[0];
float weights = KernelWeights[0];
float2 texelSizeTimesDir = textureToBlurTexelSizeXy * dir;
UNITY_UNROLL
for (int i = -KERNEL_RADIUS; i < 0; ++i)
{
float2 uvOffset = (float)i * texelSizeTimesDir;
float2 uvSample = uv + uvOffset;
float rawDepth = SampleDownsampledSceneDepthConsiderReversedZ(uvSample);
float linearEyeDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
float depthDiff = abs(centerLinearEyeDepth - linearEyeDepth);
float r2 = BLUR_DEPTH_FALLOFF * depthDiff;
float g = exp(-r2 * r2);
float weight = g * KernelWeights[-i];
float3 rgb = SAMPLE_TEXTURE2D_X(textureToBlur, sampler_TextureToBlur, uvSample).rgb;
rgbResult += (rgb * weight);
weights += weight;
}
UNITY_UNROLL
for (i = 1; i <= KERNEL_RADIUS; ++i)
{
float2 uvOffset = (float)i * texelSizeTimesDir;
float2 uvSample = uv + uvOffset;
float rawDepth = SampleDownsampledSceneDepthConsiderReversedZ(uvSample);
float linearEyeDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
float depthDiff = abs(centerLinearEyeDepth - linearEyeDepth);
float r2 = BLUR_DEPTH_FALLOFF * depthDiff;
float g = exp(-r2 * r2);
float weight = g * KernelWeights[i];
float3 rgb = SAMPLE_TEXTURE2D_X(textureToBlur, sampler_TextureToBlur, uvSample).rgb;
rgbResult += (rgb * weight);
weights += weight;
}
return float4(rgbResult / weights, centerSample.a);
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6e38164e69d451d46b41c46d4f3187f4
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,49 @@
Shader "Hidden/DownsampleDepth"
{
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
}
Pass
{
Name "DownsampleDepth"
ZTest Always
ZWrite Off
Cull Off
Blend Off
ColorMask R
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#pragma target 4.5
#pragma editor_sync_compilation
#pragma vertex Vert
#pragma fragment Frag
float Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float4 depths = GATHER_RED_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, input.texcoord);
float minDepth = Min3(depths.x, depths.y, min(depths.z, depths.w));
float maxDepth = Max3(depths.x, depths.y, max(depths.z, depths.w));
return (uint(input.positionCS.x + input.positionCS.y) & 1) > 0 ? minDepth : maxDepth;
}
ENDHLSL
}
}
Fallback Off
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: cffeaeec0396a2c4dad475266cc8dfeb
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,360 @@
Shader "Hidden/VolumetricFog"
{
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
}
Pass
{
Name "VolumetricFog"
ZTest Always
ZWrite Off
Cull Off
Blend Off
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Random.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/VolumeRendering.hlsl"
#include "./DeclareDownsampledDepthTexture.hlsl"
#pragma multi_compile _ _FORWARD_PLUS
#pragma multi_compile _ _SHADOWS_SOFT
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#pragma multi_compile_fragment _ _MAIN_LIGHT_CONTRIBUTION_DISABLED
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHTS_CONTRIBUTION_DISABLED
#pragma vertex Vert
#pragma fragment Frag
int _FrameCount;
uint _CustomAdditionalLightsCount;
float _Distance;
float _BaseHeight;
float _MaximumHeight;
float _GroundHeight;
float _Density;
float _Absortion;
float _MainLightAnisotropy;
float _MainLightScattering;
float3 _MainLightColorTint;
float _AdditionalLightsAnisotropy;
float _AdditionalLightsScattering;
float _AdditionalLightsRadiusSq;
int _MaxSteps;
// Gets the fog density at the given world height.
float GetFogDensity(float posWSy)
{
float t = saturate((posWSy - _BaseHeight) / (_MaximumHeight - _BaseHeight));
t = 1.0 - t;
t = lerp(t, 0.0, posWSy < _GroundHeight);
return _Density * t;
}
// Gets the main light color at one raymarch step.
float3 GetStepMainLightColor(float3 currPosWS, float phaseMainLight, float density)
{
#if _MAIN_LIGHT_CONTRIBUTION_DISABLED
return float3(0.0, 0.0, 0.0);
#endif
// get the main light with shadow attenuation already set
Light mainLight = GetMainLight(TransformWorldToShadowCoord(currPosWS));
#if _LIGHT_COOKIES
// when light cookies are enabled and one is set for the main light, also factor it
mainLight.color *= SampleMainLightCookie(currPosWS);
#endif
// return the final color
return (mainLight.color * _MainLightColorTint) * (mainLight.shadowAttenuation * phaseMainLight * density * _MainLightScattering);
}
// Gets the accumulated color from additional lights at one raymarch step.
float3 GetStepAdditionalLightsColor(float2 texcoord, float3 currPosWS, float3 rd, float density)
{
#if _ADDITIONAL_LIGHTS_CONTRIBUTION_DISABLED
return float3(0.0, 0.0, 0.0);
#endif
#if _FORWARD_PLUS
// Forward+ rendering path needs this data before the light loop
InputData inputData = (InputData)0;
inputData.normalizedScreenSpaceUV = texcoord;
inputData.positionWS = currPosWS;
#endif
// initialize the accumulated color from additional lights
float3 additionalLightsColor = float3(0.0, 0.0, 0.0);
// loop differently throught lights in Forward+ while considering Forward and Deferred too
LIGHT_LOOP_BEGIN(_CustomAdditionalLightsCount)
Light additionalLight = GetAdditionalPerObjectLight(lightIndex, currPosWS);
additionalLight.shadowAttenuation = AdditionalLightRealtimeShadow(lightIndex, currPosWS, additionalLight.direction);
#if _LIGHT_COOKIES
// when light cookies are enabled and a cookie is set for this additional light also factor it
additionalLight.color *= SampleAdditionalLightCookie(lightIndex, currPosWS);
#endif
// calculate the phase function for this additional light
float phaseAdditionalLight = CornetteShanksPhaseFunction(_AdditionalLightsAnisotropy, dot(rd, additionalLight.direction));
// See unity.render-pipelines.universal\ShaderLibrary\RealtimeLights.hlsl - GetAdditionalPerObjectLight
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
float4 additionalLightPos = _AdditionalLightsBuffer[lightIndex].position;
#else
float4 additionalLightPos = _AdditionalLightsPosition[lightIndex];
#endif
// Note: This is useful for both spotlights and pointlights. For the latter it is specially true when the point light is inside some geometry and casts shadows.
// Gradually reduce additional lights scattering to zero at their origin to try to avoid flicker-aliasing.
float3 distToPos = additionalLightPos.xyz - currPosWS;
float distToPosMagnitudeSq = dot(distToPos, distToPos);
float newScattering = smoothstep(0.0, _AdditionalLightsRadiusSq, distToPosMagnitudeSq) * _AdditionalLightsScattering;
// Note: If directional lights are also considered as additional lights when more than 1 is used, ignore the previous code when it is a directional light.
// They store direction in additionalLightPos.xyz and have .w set to 0, while point and spotlights have it set to 1.
newScattering = lerp(1.0, newScattering, additionalLightPos.w);
// accumulate the total color for additional lights
additionalLightsColor += (additionalLight.color * (additionalLight.shadowAttenuation * additionalLight.distanceAttenuation * phaseAdditionalLight * density * newScattering));
LIGHT_LOOP_END
return additionalLightsColor;
}
float4 Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
// prepare the ray origin and direction
float depth = SampleDownsampledSceneDepthConsiderReversedZ(input.texcoord);
float3 posWS = ComputeWorldSpacePosition(input.texcoord, depth, UNITY_MATRIX_I_VP);
float3 ro = GetCameraPositionWS();
float3 offset = posWS - ro;
float offsetLength = length(offset);
float3 rd = offset / offsetLength;
// calculate the step length and jitter
float stepLength = _Distance / (float)_MaxSteps;
float jitter = stepLength * InterleavedGradientNoise(input.positionCS.xy, _FrameCount);
// calculate the phase function for the main light and part of the extinction factor
float phaseMainLight = CornetteShanksPhaseFunction(_MainLightAnisotropy, dot(rd, GetMainLight().direction));
float minusStepLengthTimesAbsortion = -stepLength * _Absortion;
// initialize the volumetric fog color and transmittance
float3 volumetricFogColor = float3(0.0, 0.0, 0.0);
float transmittance = 1.0;
UNITY_LOOP
for (int i = 0; i < _MaxSteps; ++i)
{
// calculate the distance we are at
float dist = jitter + i * stepLength;
// perform depth test to break out early
UNITY_BRANCH
if (dist >= offsetLength)
break;
// calculate the current world position
float3 currPosWS = ro + rd * dist;
// calculate density
float density = GetFogDensity(currPosWS.y);
// keep marching when there is not enough density
UNITY_BRANCH
if (density <= 0.0)
continue;
// calculate attenuation
float stepAttenuation = exp(minusStepLengthTimesAbsortion * density);
// attenuate transmittance
transmittance *= stepAttenuation;
// calculate the colors at this step and accumulate them
float3 mainLightColor = GetStepMainLightColor(currPosWS, phaseMainLight, density);
float3 additionalLightsColor = GetStepAdditionalLightsColor(input.texcoord, currPosWS, rd, density);
// TODO: add ambient?
float3 stepColor = mainLightColor + additionalLightsColor;
volumetricFogColor += (stepColor * (transmittance * stepLength));
}
return float4(volumetricFogColor, transmittance);
}
ENDHLSL
}
Pass
{
Name "VolumetricFogHorizontalBlur"
ZTest Always
ZWrite Off
Cull Off
Blend Off
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "./DepthAwareGaussianBlur.hlsl"
#pragma vertex Vert
#pragma fragment Frag
#if UNITY_VERSION < 202320
float4 _BlitTexture_TexelSize;
#endif
float4 Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
return DepthAwareGaussianBlur(input.texcoord, float2(1.0, 0.0), _BlitTexture, sampler_LinearClamp, _BlitTexture_TexelSize.xy);
}
ENDHLSL
}
Pass
{
Name "VolumetricFogVerticalBlur"
ZTest Always
ZWrite Off
Cull Off
Blend Off
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "./DepthAwareGaussianBlur.hlsl"
#pragma vertex Vert
#pragma fragment Frag
#if UNITY_VERSION < 202320
float4 _BlitTexture_TexelSize;
#endif
float4 Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
return DepthAwareGaussianBlur(input.texcoord, float2(0.0, 1.0), _BlitTexture, sampler_LinearClamp, _BlitTexture_TexelSize.xy);
}
ENDHLSL
}
Pass
{
Name "VolumetricFogComposition"
ZTest Always
ZWrite Off
Cull Off
Blend Off
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "./DeclareDownsampledDepthTexture.hlsl"
#pragma vertex Vert
#pragma fragment Frag
TEXTURE2D_X(_VolumetricFogTexture);
SAMPLER(sampler_BlitTexture);
float4 Frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
// get the full resolution depth and convert it to linear eye depth
float fullResDepth = LoadSceneDepth(input.positionCS.xy);
float linearFullResDepth = LinearEyeDepth(fullResDepth, _ZBufferParams);
// get the texel size from the downsampled depth texture
float2 texelSize = _HalfResCameraDepthTexture_TexelSize.xy;
// calculate the UVs to sample the downsampled depths
float2 topLeftUv = input.texcoord - (texelSize * 0.5);
float2 uvs[4] =
{
topLeftUv + float2(0.0, texelSize.y),
topLeftUv + texelSize.xy,
topLeftUv + float2(texelSize.x, 0.0),
topLeftUv,
};
// initialize variables to validate the depths
int numValidDepths = 0;
float relativeDepthThreshold = linearFullResDepth * 0.1;
// initialize the minimum depth distance towards the full resolution depth
float minDepthDist = 1e12;
float2 nearestUv;
UNITY_UNROLL
for (int i = 0; i < 4; ++i)
{
// sample the lower resolution depth and convert to linear eye depth
float2 uv = uvs[i];
float depth = SampleDownsampledSceneDepthConsiderReversedZ(uv);
float linearEyeDepth = LinearEyeDepth(depth, _ZBufferParams);
// check the depth distance
float depthDist = abs(linearFullResDepth - linearEyeDepth);
// update the minimum when necessary
UNITY_FLATTEN
if (depthDist < minDepthDist)
{
minDepthDist = depthDist;
nearestUv = uvs[i];
}
// count the number of valid depths according to the threshold, as we will act differently if all of them are valid or not
numValidDepths += (depthDist < relativeDepthThreshold);
}
float4 volumetricFog;
// use bilinear sampling if depths are similar, and point sampling otherwise
UNITY_BRANCH
if (numValidDepths == 4)
volumetricFog = SAMPLE_TEXTURE2D_X(_VolumetricFogTexture, sampler_LinearClamp, input.texcoord);
else
volumetricFog = SAMPLE_TEXTURE2D_X(_VolumetricFogTexture, sampler_PointClamp, nearestUv);
float4 cameraColor = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_BlitTexture, input.texcoord);
// attenuate the camera color with the fog and add the fog on top
return float4(cameraColor.rgb * volumetricFog.a + volumetricFog.rgb, cameraColor.a);
}
ENDHLSL
}
}
Fallback Off
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 08f816187f9af0244a95556ee0cab83f
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,107 @@
fileFormatVersion: 2
guid: ad867ea49381b234fb4e7ac25c3a2dcc
ModelImporter:
serializedVersion: 22200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importPhysicalCameras: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
strictVertexDataChecks: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-5652421650081062530
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: VolumetricMaterialT
m_Shader: {fileID: -6465566751694194690, guid: 1b480a0df8811be438023001459ff883, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _SampleTexture2D_A75DF6F_Texture:
m_Texture: {fileID: 2800000, guid: 1a8058b2dcfd5174a93dfdac017cf2d8, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SampleTexture2D_DB29F771_Texture:
m_Texture: {fileID: 2800000, guid: 1a8058b2dcfd5174a93dfdac017cf2d8, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SampleTexture2D_b8e2b5c3e00c0a8899618af96df9284b_Texture_1_Texture2D:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SampleTexture2D_c6f65b9506e82b898d9ede5fb27de09f_Texture_1_Texture2D:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- Boolean_52C16ADA: 0
- Vector1_C436030E: 2
- Vector1_D9BD7578: 2.4
- _QueueControl: 0
- _QueueOffset: 0
m_Colors:
- Color_686BCB55: {r: 0, g: 1, b: 0.4114188, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: edcb197ee513b8c4883fa2f225e8776e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 1b480a0df8811be438023001459ff883
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}