chunk 1: core gameplay scripts scenes runtime assets
This commit is contained in:
BIN
Assets/Volumetric/Clouds512.png
LFS
Normal file
BIN
Assets/Volumetric/Clouds512.png
LFS
Normal file
Binary file not shown.
143
Assets/Volumetric/Clouds512.png.meta
Normal file
143
Assets/Volumetric/Clouds512.png.meta
Normal 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:
|
||||
58
Assets/Volumetric/NewUnlitShader.shader
Normal file
58
Assets/Volumetric/NewUnlitShader.shader
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/Volumetric/NewUnlitShader.shader.meta
Normal file
9
Assets/Volumetric/NewUnlitShader.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76803cdb31c5bbb468d60dc3ef9269cb
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Volumetric/Runtime.meta
Normal file
8
Assets/Volumetric/Runtime.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16c197fa070760947aef01054755bc38
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
455
Assets/Volumetric/Runtime/VolumetricFogRenderPass.cs
Normal file
455
Assets/Volumetric/Runtime/VolumetricFogRenderPass.cs
Normal 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
|
||||
}
|
||||
11
Assets/Volumetric/Runtime/VolumetricFogRenderPass.cs.meta
Normal file
11
Assets/Volumetric/Runtime/VolumetricFogRenderPass.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fea71bdcd6ce4d41bd781fc3e9d1813
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
115
Assets/Volumetric/Runtime/VolumetricFogRendererFeature.cs
Normal file
115
Assets/Volumetric/Runtime/VolumetricFogRendererFeature.cs
Normal 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
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d69a19d29ef66464ea0afc7cd84fd6c2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
116
Assets/Volumetric/Runtime/VolumetricFogVolumeComponent.cs
Normal file
116
Assets/Volumetric/Runtime/VolumetricFogVolumeComponent.cs
Normal 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
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a074ec59f6e910b4e8c49f57e56cf95a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da73c4ed88505644497dd650af00dc26
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
70
Assets/Volumetric/Shader Graphs_VolumetricT.mat
Normal file
70
Assets/Volumetric/Shader Graphs_VolumetricT.mat
Normal 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
|
||||
8
Assets/Volumetric/Shader Graphs_VolumetricT.mat.meta
Normal file
8
Assets/Volumetric/Shader Graphs_VolumetricT.mat.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1145b957cbb49c545b3ea41c8e680940
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Volumetric/Shaders.meta
Normal file
8
Assets/Volumetric/Shaders.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a53f35d162fcbc46b4962bdec40e39f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b8ef91968a1bb147a1e3f10a9e896ef
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
58
Assets/Volumetric/Shaders/DepthAwareGaussianBlur.hlsl
Normal file
58
Assets/Volumetric/Shaders/DepthAwareGaussianBlur.hlsl
Normal 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);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e38164e69d451d46b41c46d4f3187f4
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Assets/Volumetric/Shaders/DownsampleDepth.shader
Normal file
49
Assets/Volumetric/Shaders/DownsampleDepth.shader
Normal 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
|
||||
}
|
||||
9
Assets/Volumetric/Shaders/DownsampleDepth.shader.meta
Normal file
9
Assets/Volumetric/Shaders/DownsampleDepth.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cffeaeec0396a2c4dad475266cc8dfeb
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
360
Assets/Volumetric/Shaders/VolumetricFog.shader
Normal file
360
Assets/Volumetric/Shaders/VolumetricFog.shader
Normal 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
|
||||
}
|
||||
9
Assets/Volumetric/Shaders/VolumetricFog.shader.meta
Normal file
9
Assets/Volumetric/Shaders/VolumetricFog.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08f816187f9af0244a95556ee0cab83f
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Volumetric/VolumetricLightShaft.fbx
LFS
Normal file
BIN
Assets/Volumetric/VolumetricLightShaft.fbx
LFS
Normal file
Binary file not shown.
107
Assets/Volumetric/VolumetricLightShaft.fbx.meta
Normal file
107
Assets/Volumetric/VolumetricLightShaft.fbx.meta
Normal 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:
|
||||
78
Assets/Volumetric/VolumetricMaterialT.mat
Normal file
78
Assets/Volumetric/VolumetricMaterialT.mat
Normal 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
|
||||
8
Assets/Volumetric/VolumetricMaterialT.mat.meta
Normal file
8
Assets/Volumetric/VolumetricMaterialT.mat.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edcb197ee513b8c4883fa2f225e8776e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
457
Assets/Volumetric/VolumetricT.shadergraph
Normal file
457
Assets/Volumetric/VolumetricT.shadergraph
Normal file
File diff suppressed because one or more lines are too long
10
Assets/Volumetric/VolumetricT.shadergraph.meta
Normal file
10
Assets/Volumetric/VolumetricT.shadergraph.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b480a0df8811be438023001459ff883
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
|
||||
Reference in New Issue
Block a user