您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

314 行
13 KiB

using System;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
[GenerateHLSL]
public struct VolumeProperties
{
public Vector3 scattering; // [0, 1], prefer sRGB
public float extinction; // [0, 1], prefer sRGB
public static VolumeProperties GetNeutralVolumeProperties()
{
VolumeProperties properties = new VolumeProperties();
properties.scattering = Vector3.zero;
properties.extinction = 0;
return properties;
}
} // struct VolumeProperties
[Serializable]
public class VolumeParameters
{
public Bounds bounds; // Position and dimensions in meters
public Color albedo; // Single scattering albedo [0, 1]
public float meanFreePath; // In meters [1, inf]. Should be chromatic - this is an optimization!
public VolumeParameters()
{
bounds = new Bounds(Vector3.zero, Vector3.positiveInfinity);
albedo = new Color(0.5f, 0.5f, 0.5f);
meanFreePath = 10.0f;
}
public bool IsVolumeUnbounded()
{
return bounds.size.x == float.PositiveInfinity &&
bounds.size.y == float.PositiveInfinity &&
bounds.size.z == float.PositiveInfinity;
}
public Vector3 GetAbsorptionCoefficient()
{
float extinction = GetExtinctionCoefficient();
Vector3 scattering = GetScatteringCoefficient();
return Vector3.Max(new Vector3(extinction, extinction, extinction) - scattering, Vector3.zero);
}
public Vector3 GetScatteringCoefficient()
{
float extinction = GetExtinctionCoefficient();
return new Vector3(albedo.r * extinction, albedo.g * extinction, albedo.b * extinction);
}
public float GetExtinctionCoefficient()
{
return 1.0f / meanFreePath;
}
public void Constrain()
{
bounds.size = Vector3.Max(bounds.size, Vector3.zero);
albedo.r = Mathf.Clamp01(albedo.r);
albedo.g = Mathf.Clamp01(albedo.g);
albedo.b = Mathf.Clamp01(albedo.b);
meanFreePath = Mathf.Max(meanFreePath, 1.0f);
}
public VolumeProperties GetProperties()
{
VolumeProperties properties = new VolumeProperties();
properties.scattering = GetScatteringCoefficient();
properties.extinction = GetExtinctionCoefficient();
return properties;
}
} // class VolumeParameters
public partial class HDRenderPipeline : RenderPipeline
{
public enum VolumetricLightingPreset
{
Off,
Normal,
Ultra,
Count
};
VolumetricLightingPreset m_VolumetricLightingPreset = VolumetricLightingPreset.Normal;
ComputeShader m_VolumetricLightingCS { get { return m_Asset.renderPipelineResources.volumetricLightingCS; } }
float m_VBufferNearPlane = 0.5f; // Distance in meters
float m_VBufferFarPlane = 32.0f; // Distance in meters
RenderTexture[] m_VBufferLighting = null; // Used for even / odd frames
RenderTargetIdentifier[] m_VBufferLightingRT = null;
public static int ComputeVBufferTileSize(VolumetricLightingPreset preset)
{
switch (preset)
{
case VolumetricLightingPreset.Normal:
return 8;
case VolumetricLightingPreset.Ultra:
return 4;
case VolumetricLightingPreset.Off:
return 0;
default:
Debug.Assert(false, "Encountered an unexpected VolumetricLightingPreset.");
return 0;
}
}
public static int ComputeVBufferSliceCount(VolumetricLightingPreset preset)
{
switch (preset)
{
case VolumetricLightingPreset.Normal:
return 128;
case VolumetricLightingPreset.Ultra:
return 256;
case VolumetricLightingPreset.Off:
return 0;
default:
Debug.Assert(false, "Encountered an unexpected VolumetricLightingPreset.");
return 0;
}
}
// Since we are rendering tiles of pixels, our VBuffer can potentially extend past the boundaries of the viewport.
// The function returns the fraction of the {width, height} of the VBuffer visible on screen.
Vector2 ComputeVBufferResolutionAndScale(float screenWidth, float screenHeight,
ref int w, ref int h, ref int d)
{
int t = ComputeVBufferTileSize(m_VolumetricLightingPreset);
// Ceil(ScreenSize / TileSize).
w = ((int)screenWidth + t - 1) / t;
h = ((int)screenHeight + t - 1) / t;
d = ComputeVBufferSliceCount(m_VolumetricLightingPreset);
return new Vector2(screenWidth / (w * t), screenHeight / (h * t));
}
void CreateVBuffer(int screenWidth, int screenHeight)
{
if (m_VBufferLighting != null)
{
if (m_VBufferLighting[0] != null) m_VBufferLighting[0].Release();
if (m_VBufferLighting[1] != null) m_VBufferLighting[1].Release();
}
else
{
m_VBufferLighting = new RenderTexture[2];
m_VBufferLightingRT = new RenderTargetIdentifier[2];
}
int w = 0, h = 0, d = 0;
ComputeVBufferResolutionAndScale(screenWidth, screenHeight, ref w, ref h, ref d);
for (int i = 0; i < 2; i++)
{
m_VBufferLighting[i] = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear); // UAV with ARGBHalf appears to be broken...
m_VBufferLighting[i].filterMode = FilterMode.Bilinear; // Custom trilinear
m_VBufferLighting[i].dimension = TextureDimension.Tex3D; // TODO: request the thick 3D tiling layout
m_VBufferLighting[i].volumeDepth = d;
m_VBufferLighting[i].enableRandomWrite = true;
m_VBufferLighting[i].Create();
m_VBufferLightingRT[i] = new RenderTargetIdentifier(m_VBufferLighting[i]);
}
}
// Returns 'true' if a global fog component exists.
public static bool SetGlobalVolumeProperties(CommandBuffer cmd, ComputeShader cs = null)
{
HomogeneousFog globalFogComponent = null;
HomogeneousFog[] fogComponents = Object.FindObjectsOfType(typeof(HomogeneousFog)) as HomogeneousFog[];
foreach (HomogeneousFog fogComponent in fogComponents)
{
if (fogComponent.enabled && fogComponent.volumeParameters.IsVolumeUnbounded())
{
globalFogComponent = fogComponent;
break;
}
}
// TODO: may want to cache these results somewhere.
VolumeProperties globalFogProperties = (globalFogComponent != null) ? globalFogComponent.volumeParameters.GetProperties()
: VolumeProperties.GetNeutralVolumeProperties();
if (cs)
{
cmd.SetComputeVectorParam(cs, HDShaderIDs._GlobalFog_Scattering, globalFogProperties.scattering);
cmd.SetComputeFloatParam( cs, HDShaderIDs._GlobalFog_Extinction, globalFogProperties.extinction);
}
else
{
cmd.SetGlobalVector(HDShaderIDs._GlobalFog_Scattering, globalFogProperties.scattering);
cmd.SetGlobalFloat( HDShaderIDs._GlobalFog_Extinction, globalFogProperties.extinction);
}
return (globalFogComponent != null);
}
// Uses a logarithmic depth encoding.
// Near plane: depth = 0; far plane: depth = 1.
// x = n, y = log2(f/n), z = 1/n, w = 1/log2(f/n).
public static Vector4 ComputeLogarithmicDepthEncodingParams(float nearPlane, float farPlane)
{
Vector4 depthParams = new Vector4();
float n = nearPlane;
float f = farPlane;
depthParams.x = n;
depthParams.y = Mathf.Log(f / n, 2);
depthParams.z = 1 / depthParams.x;
depthParams.w = 1 / depthParams.y;
return depthParams;
}
public void SetVolumetricLightingData(HDCamera camera, CommandBuffer cmd, ComputeShader cs = null, int kernel = 0)
{
SetGlobalVolumeProperties(cmd, cs);
int w = 0, h = 0, d = 0;
Vector2 scale = ComputeVBufferResolutionAndScale(camera.screenSize.x, camera.screenSize.y, ref w, ref h, ref d);
Vector4 resAndScale = new Vector4(w, h, scale.x, scale.y);
Vector4 depthParams = ComputeLogarithmicDepthEncodingParams(m_VBufferNearPlane, m_VBufferFarPlane);
if (cs)
{
cmd.SetComputeVectorParam( cs, HDShaderIDs._VBufferResolutionAndScale, resAndScale);
cmd.SetComputeVectorParam( cs, HDShaderIDs._VBufferDepthEncodingParams, depthParams);
cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VBufferLighting, m_VBufferLightingRT[0]);
}
else
{
cmd.SetGlobalVector( HDShaderIDs._VBufferResolutionAndScale, resAndScale);
cmd.SetGlobalVector( HDShaderIDs._VBufferDepthEncodingParams, depthParams);
cmd.SetGlobalTexture(HDShaderIDs._VBufferLighting, m_VBufferLightingRT[0]);
}
}
public static void SetVolumetricLightingDataFromGlobals(CommandBuffer cmd, ComputeShader cs, int kernel)
{
SetGlobalVolumeProperties(cmd, cs);
cmd.SetComputeVectorParam( cs, HDShaderIDs._VBufferResolutionAndScale, Shader.GetGlobalVector( HDShaderIDs._VBufferResolutionAndScale));
cmd.SetComputeVectorParam( cs, HDShaderIDs._VBufferDepthEncodingParams, Shader.GetGlobalVector( HDShaderIDs._VBufferDepthEncodingParams));
cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VBufferLighting, Shader.GetGlobalTexture(HDShaderIDs._VBufferLighting));
}
void VolumetricLightingPass(HDCamera camera, CommandBuffer cmd)
{
if (m_VolumetricLightingPreset == VolumetricLightingPreset.Off) return;
using (new ProfilingSample(cmd, "Volumetric Lighting"))
{
bool hasGlobalVolume = SetGlobalVolumeProperties(cmd, m_VolumetricLightingCS);
if (!hasGlobalVolume)
{
// Clear the render target instead of running the shader.
CoreUtils.SetRenderTarget(cmd, m_VBufferLightingRT[0], ClearFlag.Color, CoreUtils.clearColorAllBlack);
return;
}
camera.SetupComputeShader(m_VolumetricLightingCS, cmd);
bool enableClustered = m_Asset.tileSettings.enableClustered && m_Asset.tileSettings.enableTileAndCluster;
int kernel = m_VolumetricLightingCS.FindKernel(enableClustered ? "VolumetricLightingClustered"
: "VolumetricLightingAllLights");
int w = 0, h = 0, d = 0;
Vector2 scale = ComputeVBufferResolutionAndScale(camera.screenSize.x, camera.screenSize.y, ref w, ref h, ref d);
Vector4 resAndScale = new Vector4(w, h, scale.x, scale.y);
Vector4 depthParams = ComputeLogarithmicDepthEncodingParams(m_VBufferNearPlane, m_VBufferFarPlane);
float vFoV = camera.camera.fieldOfView * Mathf.Deg2Rad;
// Compose the matrix which allows us to compute the world space view direction.
// Compute it using the scaled resolution to account for the visible area of the VBuffer.
Vector4 scaledRes = new Vector4(w * scale.x, h * scale.y, 1.0f / (w * scale.x), 1.0f / (h * scale.y));
Matrix4x4 transform = SkyManager.ComputePixelCoordToWorldSpaceViewDirectionMatrix(vFoV, scaledRes, camera.viewMatrix, false);
// TODO: set 'm_VolumetricLightingPreset'.
cmd.SetComputeVectorParam( m_VolumetricLightingCS, HDShaderIDs._Time, Shader.GetGlobalVector(HDShaderIDs._Time));
cmd.SetComputeVectorParam( m_VolumetricLightingCS, HDShaderIDs._VBufferResolutionAndScale, resAndScale);
cmd.SetComputeVectorParam( m_VolumetricLightingCS, HDShaderIDs._VBufferDepthEncodingParams, depthParams);
cmd.SetComputeMatrixParam( m_VolumetricLightingCS, HDShaderIDs._VBufferCoordToViewDirWS, transform);
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLighting, m_VBufferLightingRT[0]);
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingPrev, m_VBufferLightingRT[1]);
// Pass the light data to the compute shader.
m_LightLoop.PushGlobalParams(camera.camera, cmd, m_VolumetricLightingCS, kernel, true);
// The shader defines GROUP_SIZE_1D = 16.
cmd.DispatchCompute(m_VolumetricLightingCS, kernel, (w + 15) / 16, (h + 15) / 16, 1);
}
}
} // class HDRenderPipeline
} // namespace UnityEngine.Experimental.Rendering.HDPipeline