您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
263 行
16 KiB
263 行
16 KiB
using UnityEngine.Rendering;
|
|
using System;
|
|
|
|
namespace UnityEngine.Experimental.Rendering.HDPipeline
|
|
{
|
|
public class SubsurfaceScatteringManager
|
|
{
|
|
// Currently we only support SSSBuffer with one buffer. If the shader code change, it may require to update the shader manager
|
|
public const int k_MaxSSSBuffer = 1;
|
|
|
|
readonly int m_SSSBuffer0;
|
|
readonly RenderTargetIdentifier m_SSSBuffer0RT;
|
|
|
|
public int sssBufferCount { get { return k_MaxSSSBuffer; } }
|
|
|
|
RenderTargetIdentifier[] m_ColorMRTs;
|
|
RenderTargetIdentifier[] m_RTIDs = new RenderTargetIdentifier[k_MaxSSSBuffer];
|
|
|
|
// Disney SSS Model
|
|
ComputeShader m_SubsurfaceScatteringCS;
|
|
int m_SubsurfaceScatteringKernel;
|
|
Material m_CombineLightingPass;
|
|
|
|
RenderTexture m_HTile;
|
|
RenderTargetIdentifier m_HTileRT;
|
|
// End Disney SSS Model
|
|
|
|
// Jimenez SSS Model
|
|
Material m_SssVerticalFilterPass;
|
|
Material m_SssHorizontalFilterAndCombinePass;
|
|
// End Jimenez SSS Model
|
|
|
|
// Jimenez need an extra buffer and Disney need one for some platform
|
|
readonly int m_CameraFilteringBuffer;
|
|
readonly RenderTargetIdentifier m_CameraFilteringBufferRT;
|
|
|
|
// This is use to be able to read stencil value in compute shader
|
|
Material m_CopyStencilForSplitLighting;
|
|
|
|
public SubsurfaceScatteringManager()
|
|
{
|
|
m_SSSBuffer0 = HDShaderIDs._SSSBufferTexture[0];
|
|
m_SSSBuffer0RT = new RenderTargetIdentifier(m_SSSBuffer0);
|
|
|
|
// Use with Jimenez
|
|
m_CameraFilteringBuffer = HDShaderIDs._CameraFilteringBuffer;
|
|
m_CameraFilteringBufferRT = new RenderTargetIdentifier(m_CameraFilteringBuffer);
|
|
}
|
|
|
|
// In case of deferred, we must be in sync with SubsurfaceScattering.hlsl and lit.hlsl files and setup the correct buffers
|
|
// for SSS
|
|
public void InitSSSBuffersFromGBuffer(int width, int height, GBufferManager gbufferManager, CommandBuffer cmd)
|
|
{
|
|
m_RTIDs[0] = gbufferManager.GetGBuffers()[0];
|
|
}
|
|
|
|
// In case of full forward we must allocate the render target for forward SSS (or reuse one already existing)
|
|
// TODO: Provide a way to reuse a render target
|
|
public void InitSSSBuffers(int width, int height, CommandBuffer cmd)
|
|
{
|
|
m_RTIDs[0] = m_SSSBuffer0RT;
|
|
|
|
cmd.ReleaseTemporaryRT(m_SSSBuffer0);
|
|
cmd.GetTemporaryRT(m_SSSBuffer0, width, height, 0, FilterMode.Point, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
|
}
|
|
|
|
public RenderTargetIdentifier GetSSSBuffers(int index)
|
|
{
|
|
Debug.Assert(index < sssBufferCount);
|
|
return m_RTIDs[index];
|
|
}
|
|
|
|
public void Build(HDRenderPipelineAsset hdAsset)
|
|
{
|
|
// Disney SSS (compute + combine)
|
|
m_SubsurfaceScatteringCS = hdAsset.renderPipelineResources.subsurfaceScatteringCS;
|
|
m_SubsurfaceScatteringKernel = m_SubsurfaceScatteringCS.FindKernel("SubsurfaceScattering");
|
|
m_CombineLightingPass = CoreUtils.CreateEngineMaterial(hdAsset.renderPipelineResources.combineLighting);
|
|
|
|
// Jimenez SSS Model (shader)
|
|
m_SssVerticalFilterPass = CoreUtils.CreateEngineMaterial(hdAsset.renderPipelineResources.subsurfaceScattering);
|
|
m_SssVerticalFilterPass.DisableKeyword("SSS_FILTER_HORIZONTAL_AND_COMBINE");
|
|
m_SssVerticalFilterPass.SetFloat(HDShaderIDs._DstBlend, (float)BlendMode.Zero);
|
|
|
|
m_SssHorizontalFilterAndCombinePass = CoreUtils.CreateEngineMaterial(hdAsset.renderPipelineResources.subsurfaceScattering);
|
|
m_SssHorizontalFilterAndCombinePass.EnableKeyword("SSS_FILTER_HORIZONTAL_AND_COMBINE");
|
|
m_SssHorizontalFilterAndCombinePass.SetFloat(HDShaderIDs._DstBlend, (float)BlendMode.One);
|
|
|
|
m_CopyStencilForSplitLighting = CoreUtils.CreateEngineMaterial(hdAsset.renderPipelineResources.copyStencilBuffer);
|
|
m_CopyStencilForSplitLighting.SetInt(HDShaderIDs._StencilRef, (int)StencilLightingUsage.SplitLighting);
|
|
}
|
|
|
|
public void Cleanup()
|
|
{
|
|
CoreUtils.Destroy(m_CombineLightingPass);
|
|
CoreUtils.Destroy(m_SssVerticalFilterPass);
|
|
CoreUtils.Destroy(m_SssHorizontalFilterAndCombinePass);
|
|
CoreUtils.Destroy(m_CopyStencilForSplitLighting);
|
|
}
|
|
|
|
public void Resize(Camera camera)
|
|
{
|
|
// We must use a RenderTexture and not GetTemporaryRT() as currently Unity only aloow to bind a RenderTexture for a UAV in a pixel shader
|
|
// We use 8x8 tiles in order to match the native GCN HTile as closely as possible.
|
|
m_HTile = new RenderTexture((camera.pixelWidth + 7) / 8, (camera.pixelHeight + 7) / 8, 0, RenderTextureFormat.R8, RenderTextureReadWrite.Linear); // DXGI_FORMAT_R8_UINT is not supported by Unity
|
|
m_HTile.filterMode = FilterMode.Point;
|
|
m_HTile.enableRandomWrite = true;
|
|
m_HTile.Create();
|
|
m_HTileRT = new RenderTargetIdentifier(m_HTile);
|
|
}
|
|
|
|
public void PushGlobalParams(CommandBuffer cmd, SubsurfaceScatteringSettings sssParameters, FrameSettings frameSettings)
|
|
{
|
|
// Broadcast SSS parameters to all shaders.
|
|
cmd.SetGlobalInt(HDShaderIDs._EnableSSSAndTransmission, frameSettings.lightingSettings.enableSSSAndTransmission ? 1 : 0);
|
|
cmd.SetGlobalInt(HDShaderIDs._UseDisneySSS, sssParameters.useDisneySSS ? 1 : 0);
|
|
unsafe
|
|
{
|
|
// Warning: Unity is not able to losslessly transfer integers larger than 2^24 to the shader system.
|
|
// Therefore, we bitcast uint to float in C#, and bitcast back to uint in the shader.
|
|
uint texturingModeFlags = sssParameters.texturingModeFlags;
|
|
uint transmissionFlags = sssParameters.transmissionFlags;
|
|
cmd.SetGlobalFloat(HDShaderIDs._TexturingModeFlags, *(float*)&texturingModeFlags);
|
|
cmd.SetGlobalFloat(HDShaderIDs._TransmissionFlags, *(float*)&transmissionFlags);
|
|
}
|
|
cmd.SetGlobalVectorArray(HDShaderIDs._ThicknessRemaps, sssParameters.thicknessRemaps);
|
|
cmd.SetGlobalVectorArray(HDShaderIDs._ShapeParams, sssParameters.shapeParams);
|
|
cmd.SetGlobalVectorArray(HDShaderIDs._HalfRcpVariancesAndWeights, sssParameters.halfRcpVariancesAndWeights);
|
|
cmd.SetGlobalVectorArray(HDShaderIDs._TransmissionTintsAndFresnel0, sssParameters.transmissionTintsAndFresnel0);
|
|
cmd.SetGlobalVectorArray(HDShaderIDs._WorldScales, sssParameters.worldScales);
|
|
}
|
|
|
|
bool NeedTemporarySubsurfaceBuffer()
|
|
{
|
|
// Caution: need to be in sync with SubsurfaceScattering.cs USE_INTERMEDIATE_BUFFER (Can't make a keyword as it is a compute shader)
|
|
// Typed UAV loads from FORMAT_R16G16B16A16_FLOAT is an optional feature of Direct3D 11.
|
|
// Most modern GPUs support it. We can avoid performing a costly copy in this case.
|
|
// TODO: test/implement for other platforms.
|
|
return SystemInfo.graphicsDeviceType != GraphicsDeviceType.PlayStation4 &&
|
|
SystemInfo.graphicsDeviceType != GraphicsDeviceType.XboxOne &&
|
|
SystemInfo.graphicsDeviceType != GraphicsDeviceType.XboxOneD3D12;
|
|
}
|
|
|
|
// Combines specular lighting and diffuse lighting with subsurface scattering.
|
|
public void SubsurfaceScatteringPass(HDCamera hdCamera, CommandBuffer cmd, SubsurfaceScatteringSettings sssParameters, FrameSettings frameSettings,
|
|
RenderTargetIdentifier colorBufferRT, RenderTargetIdentifier diffuseBufferRT, RenderTargetIdentifier depthStencilBufferRT, RenderTargetIdentifier depthTextureRT)
|
|
{
|
|
if (sssParameters == null || !frameSettings.lightingSettings.enableSSSAndTransmission)
|
|
return;
|
|
|
|
using (new ProfilingSample(cmd, "Subsurface Scattering", HDRenderPipeline.GetSampler(CustomSamplerId.SubsurfaceScattering)))
|
|
{
|
|
int w = hdCamera.camera.pixelWidth;
|
|
int h = hdCamera.camera.pixelHeight;
|
|
|
|
// For Jimenez we always need an extra buffer, for Disney it depends on platform
|
|
if (!sssParameters.useDisneySSS ||
|
|
(sssParameters.useDisneySSS && NeedTemporarySubsurfaceBuffer()))
|
|
{
|
|
// Caution: must be same format as m_CameraSssDiffuseLightingBuffer
|
|
cmd.ReleaseTemporaryRT(m_CameraFilteringBuffer);
|
|
cmd.GetTemporaryRT(m_CameraFilteringBuffer, w, h, 0, FilterMode.Point, RenderTextureFormat.RGB111110Float, RenderTextureReadWrite.Linear, 1, true); // Enable UAV
|
|
// Clear the SSS filtering target
|
|
using (new ProfilingSample(cmd, "Clear SSS filtering target", HDRenderPipeline.GetSampler(CustomSamplerId.ClearSSSFilteringTarget)))
|
|
{
|
|
CoreUtils.SetRenderTarget(cmd, m_CameraFilteringBufferRT, ClearFlag.Color, CoreUtils.clearColorAllBlack);
|
|
}
|
|
}
|
|
|
|
if (sssParameters.useDisneySSS)
|
|
{
|
|
using (new ProfilingSample(cmd, "HTile for SSS", HDRenderPipeline.GetSampler(CustomSamplerId.HTileForSSS)))
|
|
{
|
|
// Currently, Unity does not offer a way to access the GCN HTile even on PS4 and Xbox One.
|
|
// Therefore, it's computed in a pixel shader, and optimized to only contain the SSS bit.
|
|
CoreUtils.SetRenderTarget(cmd, m_HTileRT, ClearFlag.Color, CoreUtils.clearColorAllBlack);
|
|
|
|
cmd.SetRandomWriteTarget(1, m_HTile);
|
|
// Generate HTile for the split lighting stencil usage. Don't write into stencil texture (shaderPassId = 2)
|
|
// Use ShaderPassID 1 => "Pass 2 - Export HTILE for stencilRef to output"
|
|
CoreUtils.SetRenderTarget(cmd, depthStencilBufferRT); // No need for color buffer here
|
|
CoreUtils.DrawFullScreen(cmd, m_CopyStencilForSplitLighting, null, 2);
|
|
cmd.ClearRandomWriteTargets();
|
|
}
|
|
|
|
// TODO: Remove this once fix, see comment inside the function
|
|
hdCamera.SetupComputeShader(m_SubsurfaceScatteringCS, cmd);
|
|
|
|
unsafe
|
|
{
|
|
// Warning: Unity is not able to losslessly transfer integers larger than 2^24 to the shader system.
|
|
// Therefore, we bitcast uint to float in C#, and bitcast back to uint in the shader.
|
|
uint texturingModeFlags = sssParameters.texturingModeFlags;
|
|
cmd.SetComputeFloatParam(m_SubsurfaceScatteringCS, HDShaderIDs._TexturingModeFlags, *(float*)&texturingModeFlags);
|
|
}
|
|
|
|
cmd.SetComputeVectorArrayParam(m_SubsurfaceScatteringCS, HDShaderIDs._WorldScales, sssParameters.worldScales);
|
|
cmd.SetComputeVectorArrayParam(m_SubsurfaceScatteringCS, HDShaderIDs._FilterKernels, sssParameters.filterKernels);
|
|
cmd.SetComputeVectorArrayParam(m_SubsurfaceScatteringCS, HDShaderIDs._ShapeParams, sssParameters.shapeParams);
|
|
|
|
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._DepthTexture, depthTextureRT);
|
|
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._SSSHTile, m_HTileRT);
|
|
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._IrradianceSource, diffuseBufferRT);
|
|
|
|
for (int i = 0; i < sssBufferCount; ++i)
|
|
{
|
|
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._SSSBufferTexture[i], GetSSSBuffers(i));
|
|
}
|
|
|
|
if (NeedTemporarySubsurfaceBuffer())
|
|
{
|
|
// Caution: must be same format as m_CameraSssDiffuseLightingBuffer
|
|
cmd.ReleaseTemporaryRT(m_CameraFilteringBuffer);
|
|
cmd.GetTemporaryRT(m_CameraFilteringBuffer, w, h, 0, FilterMode.Point, RenderTextureFormat.RGB111110Float, RenderTextureReadWrite.Linear, 1, true); // Enable UAV
|
|
// Clear the SSS filtering target
|
|
using (new ProfilingSample(cmd, "Clear SSS filtering target", HDRenderPipeline.GetSampler(CustomSamplerId.ClearSSSFilteringTarget)))
|
|
{
|
|
CoreUtils.SetRenderTarget(cmd, m_CameraFilteringBufferRT, ClearFlag.Color, CoreUtils.clearColorAllBlack);
|
|
}
|
|
|
|
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._CameraFilteringBuffer, m_CameraFilteringBufferRT);
|
|
|
|
// Perform the SSS filtering pass which fills 'm_CameraFilteringBufferRT'.
|
|
// We dispatch 4x swizzled 16x16 groups per a 32x32 macro tile.
|
|
cmd.DispatchCompute(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, 4, ((int)hdCamera.screenSize.x + 31) / 32, ((int)hdCamera.screenSize.y + 31) / 32);
|
|
|
|
cmd.SetGlobalTexture(HDShaderIDs._IrradianceSource, m_CameraFilteringBufferRT); // Cannot set a RT on a material
|
|
|
|
// Additively blend diffuse and specular lighting into 'm_CameraColorBufferRT'.
|
|
CoreUtils.DrawFullScreen(cmd, m_CombineLightingPass, colorBufferRT, depthStencilBufferRT);
|
|
}
|
|
else
|
|
{
|
|
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._CameraColorTexture, colorBufferRT);
|
|
|
|
// Perform the SSS filtering pass which performs an in-place update of 'colorBuffer'.
|
|
// We dispatch 4x swizzled 16x16 groups per a 32x32 macro tile.
|
|
cmd.DispatchCompute(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, 4, ((int)hdCamera.screenSize.x + 31) / 32, ((int)hdCamera.screenSize.y + 31) / 32);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < sssBufferCount; ++i)
|
|
{
|
|
cmd.SetGlobalTexture(HDShaderIDs._SSSBufferTexture[i], GetSSSBuffers(i));
|
|
}
|
|
|
|
cmd.SetGlobalTexture(HDShaderIDs._IrradianceSource, diffuseBufferRT); // Cannot set a RT on a material
|
|
m_SssVerticalFilterPass.SetVectorArray(HDShaderIDs._FilterKernelsBasic, sssParameters.filterKernelsBasic);
|
|
m_SssVerticalFilterPass.SetVectorArray(HDShaderIDs._HalfRcpWeightedVariances, sssParameters.halfRcpWeightedVariances);
|
|
// Perform the vertical SSS filtering pass which fills 'm_CameraFilteringBufferRT'.
|
|
CoreUtils.DrawFullScreen(cmd, m_SssVerticalFilterPass, m_CameraFilteringBufferRT, depthStencilBufferRT);
|
|
|
|
cmd.SetGlobalTexture(HDShaderIDs._IrradianceSource, m_CameraFilteringBufferRT); // Cannot set a RT on a material
|
|
m_SssHorizontalFilterAndCombinePass.SetVectorArray(HDShaderIDs._FilterKernelsBasic, sssParameters.filterKernelsBasic);
|
|
m_SssHorizontalFilterAndCombinePass.SetVectorArray(HDShaderIDs._HalfRcpWeightedVariances, sssParameters.halfRcpWeightedVariances);
|
|
// Perform the horizontal SSS filtering pass, and combine diffuse and specular lighting into 'm_CameraColorBufferRT'.
|
|
CoreUtils.DrawFullScreen(cmd, m_SssHorizontalFilterAndCombinePass, colorBufferRT, depthStencilBufferRT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|