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

252 行
11 KiB

using UnityEngine.Rendering;
using System;
using System.Collections.Generic;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
public class IBLFilterGGX
{
RenderTexture m_GgxIblSampleData;
int m_GgxIblMaxSampleCount = TextureCache.isMobileBuildTarget ? 34 : 89; // Width
const int k_GgxIblMipCountMinusOne = 6; // Height (UNITY_SPECCUBE_LOD_STEPS)
ComputeShader m_ComputeGgxIblSampleDataCS;
int m_ComputeGgxIblSampleDataKernel = -1;
ComputeShader m_BuildProbabilityTablesCS;
int m_ConditionalDensitiesKernel = -1;
int m_MarginalRowDensitiesKernel = -1;
Material m_GgxConvolveMaterial; // Convolves a cubemap with GGX
Matrix4x4[] m_faceWorldToViewMatrixMatrices = new Matrix4x4[6];
RenderPipelineResources m_RenderPipelineResources;
BufferPyramidProcessor m_BufferPyramidProcessor;
List<RenderTexture> m_PlanarColorMips = new List<RenderTexture>();
public IBLFilterGGX(RenderPipelineResources renderPipelineResources, BufferPyramidProcessor processor)
{
m_RenderPipelineResources = renderPipelineResources;
m_BufferPyramidProcessor = processor;
}
public bool IsInitialized()
{
return m_GgxIblSampleData != null;
}
public void Initialize(CommandBuffer cmd)
{
if (!m_ComputeGgxIblSampleDataCS)
{
m_ComputeGgxIblSampleDataCS = m_RenderPipelineResources.computeGgxIblSampleData;
m_ComputeGgxIblSampleDataKernel = m_ComputeGgxIblSampleDataCS.FindKernel("ComputeGgxIblSampleData");
}
if (!m_BuildProbabilityTablesCS)
{
m_BuildProbabilityTablesCS = m_RenderPipelineResources.buildProbabilityTables;
m_ConditionalDensitiesKernel = m_BuildProbabilityTablesCS.FindKernel("ComputeConditionalDensities");
m_MarginalRowDensitiesKernel = m_BuildProbabilityTablesCS.FindKernel("ComputeMarginalRowDensities");
}
if (!m_GgxConvolveMaterial)
{
m_GgxConvolveMaterial = CoreUtils.CreateEngineMaterial(m_RenderPipelineResources.GGXConvolve);
}
if (!m_GgxIblSampleData)
{
m_GgxIblSampleData = new RenderTexture(m_GgxIblMaxSampleCount, k_GgxIblMipCountMinusOne, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
m_GgxIblSampleData.useMipMap = false;
m_GgxIblSampleData.autoGenerateMips = false;
m_GgxIblSampleData.enableRandomWrite = true;
m_GgxIblSampleData.filterMode = FilterMode.Point;
m_GgxIblSampleData.name = CoreUtils.GetRenderTargetAutoName(m_GgxIblMaxSampleCount, k_GgxIblMipCountMinusOne, 1, RenderTextureFormat.ARGBHalf, "GGXIblSampleData");
m_GgxIblSampleData.hideFlags = HideFlags.HideAndDontSave;
m_GgxIblSampleData.Create();
m_ComputeGgxIblSampleDataCS.SetTexture(m_ComputeGgxIblSampleDataKernel, "output", m_GgxIblSampleData);
using (new ProfilingSample(cmd, "Compute GGX IBL Sample Data"))
{
cmd.DispatchCompute(m_ComputeGgxIblSampleDataCS, m_ComputeGgxIblSampleDataKernel, 1, 1, 1);
}
}
for (int i = 0; i < 6; ++i)
{
var lookAt = Matrix4x4.LookAt(Vector3.zero, CoreUtils.lookAtList[i], CoreUtils.upVectorList[i]);
m_faceWorldToViewMatrixMatrices[i] = lookAt * Matrix4x4.Scale(new Vector3(1.0f, 1.0f, -1.0f)); // Need to scale -1.0 on Z to match what is being done in the camera.wolrdToCameraMatrix API. ...
}
}
public void Cleanup()
{
CoreUtils.Destroy(m_GgxConvolveMaterial);
CoreUtils.Destroy(m_GgxIblSampleData);
for (var i = 0; i < m_PlanarColorMips.Count; ++i)
m_PlanarColorMips[i].Release();
m_PlanarColorMips.Clear();
}
void FilterCubemapCommon(CommandBuffer cmd,
Texture source, RenderTexture target,
Matrix4x4[] worldToViewMatrices)
{
int mipCount = 1 + (int)Mathf.Log(source.width, 2.0f);
if (mipCount < ((int)EnvConstants.SpecCubeLodStep + 1))
{
Debug.LogWarning("RenderCubemapGGXConvolution: Cubemap size is too small for GGX convolution, needs at least " + ((int)EnvConstants.SpecCubeLodStep + 1) + " mip levels");
return;
}
// Copy the first mip
using (new ProfilingSample(cmd, "Copy Original Mip"))
{
for (int f = 0; f < 6; f++)
{
cmd.CopyTexture(source, f, 0, target, f, 0);
}
}
// Solid angle associated with a texel of the cubemap.
float invOmegaP = (6.0f * source.width * source.width) / (4.0f * Mathf.PI);
m_GgxConvolveMaterial.SetTexture("_GgxIblSamples", m_GgxIblSampleData);
var props = new MaterialPropertyBlock();
props.SetTexture("_MainTex", source);
props.SetFloat("_InvOmegaP", invOmegaP);
for (int mip = 1; mip < ((int)EnvConstants.SpecCubeLodStep + 1); ++mip)
{
props.SetFloat("_Level", mip);
using (new ProfilingSample(cmd, "Filter Cubemap Mip {0}", mip))
{
for (int face = 0; face < 6; ++face)
{
var faceSize = new Vector4(source.width >> mip, source.height >> mip, 1.0f / (source.width >> mip), 1.0f / (source.height >> mip));
var transform = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(0.5f * Mathf.PI, faceSize, worldToViewMatrices[face], true);
props.SetMatrix(HDShaderIDs._PixelCoordToViewDirWS, transform);
CoreUtils.SetRenderTarget(cmd, target, ClearFlag.None, mip, (CubemapFace)face);
CoreUtils.DrawFullScreen(cmd, m_GgxConvolveMaterial, props);
}
}
}
}
// Filters MIP map levels (other than 0) with GGX using BRDF importance sampling.
public void FilterCubemap(CommandBuffer cmd, Texture source, RenderTexture target)
{
m_GgxConvolveMaterial.DisableKeyword("USE_MIS");
FilterCubemapCommon(cmd, source, target, m_faceWorldToViewMatrixMatrices);
}
public void FilterPlanarTexture(CommandBuffer cmd, Texture source, RenderTexture target)
{
var lodCount = Mathf.Max(Mathf.FloorToInt(Mathf.Log(Mathf.Min(source.width, source.height), 2f)), 0);
for (var i = 0; i < lodCount - 0; ++i)
{
var width = target.width >> (i + 1);
var height = target.height >> (i + 1);
var rtHash = HashRenderTextureProperties(
width,
height,
target.depth,
target.format,
target.sRGB ? RenderTextureReadWrite.sRGB : RenderTextureReadWrite.Linear
);
var lodIsMissing = i >= m_PlanarColorMips.Count;
RenderTexture rt = null;
var createRT = lodIsMissing
|| (rt = m_PlanarColorMips[i]) == null
|| rtHash != HashRenderTextureProperties(
rt.width, rt.height, rt.depth, rt.format, rt.sRGB
? RenderTextureReadWrite.sRGB
: RenderTextureReadWrite.Linear
);
if (createRT && rt)
rt.Release();
if (createRT)
{
rt = new RenderTexture(
width,
height,
target.depth,
target.format,
target.sRGB ? RenderTextureReadWrite.sRGB : RenderTextureReadWrite.Linear
);
rt.enableRandomWrite = true;
rt.name = "Planar Convolution Tmp RT";
rt.hideFlags = HideFlags.HideAndDontSave;
rt.Create();
}
if (lodIsMissing)
m_PlanarColorMips.Add(rt);
else if (createRT)
m_PlanarColorMips[i] = rt;
}
m_BufferPyramidProcessor.RenderColorPyramid(
new RectInt(0, 0, source.width, source.height),
cmd,
source,
target,
m_PlanarColorMips,
lodCount
);
}
// Filters MIP map levels (other than 0) with GGX using multiple importance sampling.
public void FilterCubemapMIS(CommandBuffer cmd,
Texture source, RenderTexture target,
RenderTexture conditionalCdf, RenderTexture marginalRowCdf)
{
// Bind the input cubemap.
m_BuildProbabilityTablesCS.SetTexture(m_ConditionalDensitiesKernel, "envMap", source);
// Bind the outputs.
m_BuildProbabilityTablesCS.SetTexture(m_ConditionalDensitiesKernel, "conditionalDensities", conditionalCdf);
m_BuildProbabilityTablesCS.SetTexture(m_ConditionalDensitiesKernel, "marginalRowDensities", marginalRowCdf);
m_BuildProbabilityTablesCS.SetTexture(m_MarginalRowDensitiesKernel, "marginalRowDensities", marginalRowCdf);
int numRows = conditionalCdf.height;
using (new ProfilingSample(cmd, "Build Probability Tables"))
{
cmd.DispatchCompute(m_BuildProbabilityTablesCS, m_ConditionalDensitiesKernel, numRows, 1, 1);
cmd.DispatchCompute(m_BuildProbabilityTablesCS, m_MarginalRowDensitiesKernel, 1, 1, 1);
}
m_GgxConvolveMaterial.EnableKeyword("USE_MIS");
m_GgxConvolveMaterial.SetTexture("_ConditionalDensities", conditionalCdf);
m_GgxConvolveMaterial.SetTexture("_MarginalRowDensities", marginalRowCdf);
FilterCubemapCommon(cmd, source, target, m_faceWorldToViewMatrixMatrices);
}
int HashRenderTextureProperties(
int width,
int height,
int depth,
RenderTextureFormat format,
RenderTextureReadWrite sRGB)
{
return width.GetHashCode()
^ height.GetHashCode()
^ depth.GetHashCode()
^ format.GetHashCode()
^ sRGB.GetHashCode();
}
}
}