浏览代码

Realtime Reflection Probes WIP: Implemented Specific Reflection Probe cache and do the GGX convolution on GPU for every probes.

/Add-support-for-light-specular-color-tint
Julien Ignace 7 年前
当前提交
f901ecbc
共有 8 个文件被更改,包括 209 次插入165 次删除
  1. 22
      ScriptableRenderPipeline/Core/CoreUtils.cs
  2. 128
      ScriptableRenderPipeline/Core/TextureCache.cs
  3. 19
      ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  4. 60
      ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
  5. 56
      ScriptableRenderPipeline/HDRenderPipeline/Sky/RuntimeFilterIBL.cs
  6. 66
      ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs
  7. 13
      TestbedPipelines/Fptl/FptlLighting.cs
  8. 10
      TestbedPipelines/OnTileDeferredPipeline/OnTileDeferredRenderPipeline.cs

22
ScriptableRenderPipeline/Core/CoreUtils.cs


public static class CoreUtils
{
// Data useful for various cubemap processes.
// Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/bb204881(v=vs.85).aspx
static public readonly Vector3[] lookAtList =
{
new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(-1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, -1.0f, 0.0f),
new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, 0.0f, -1.0f),
};
static public readonly Vector3[] upVectorList =
{
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
};
// Note: Color.Black have alpha channel set to 1. Most of the time we want alpha channel set to 0 as we use black to clear render target
public static Color clearColorAllBlack { get { return new Color(0f, 0f, 0f, 0f); } }

128
ScriptableRenderPipeline/Core/TextureCache.cs


using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Rendering;
#if UNITY_EDITOR
using UnityEditor;
#endif

{
private Texture2DArray m_Cache;
public override void TransferToSlice(int sliceIndex, Texture texture)
public override void TransferToSlice(CommandBuffer cmd, int sliceIndex, Texture texture)
{
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);

}
else
{
Graphics.CopyTexture(texture, 0, m_Cache, sliceIndex);
cmd.CopyTexture(texture, 0, m_Cache, sliceIndex);
}
}

private int m_CubeMipLevelPropName;
private int m_cubeSrcTexPropName;
public override void TransferToSlice(int sliceIndex, Texture texture)
public override void TransferToSlice(CommandBuffer cmd, int sliceIndex, Texture texture)
TransferToPanoCache(sliceIndex, texture);
TransferToPanoCache(cmd, sliceIndex, texture);
else
{
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);

else
{
for (int f = 0; f < 6; f++)
Graphics.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f);
cmd.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f);
}
}
}

Texture.DestroyImmediate(m_Cache);
}
private void TransferToPanoCache(int sliceIndex, Texture texture)
private void TransferToPanoCache(CommandBuffer cmd, int sliceIndex, Texture texture)
Graphics.SetRenderTarget(m_StagingRTs[m]);
Graphics.Blit(null, m_CubeBlitMaterial, 0);
cmd.Blit(null, m_StagingRTs[m], m_CubeBlitMaterial, 0);
Graphics.CopyTexture(m_StagingRTs[m], 0, 0, m_CacheNoCubeArray, sliceIndex, m);
cmd.CopyTexture(m_StagingRTs[m], 0, 0, m_CacheNoCubeArray, sliceIndex, m);
}
}

{
var format = TextureFormat.RGBAHalf;
var probeFormat = TextureFormat.BC6H;
// var probeFormat = TextureFormat.BC6H;
// On editor the texture is uncompressed when operating against mobile build targets
//#if UNITY_2017_2_OR_NEWER
if (SystemInfo.SupportsTextureFormat(probeFormat) && !UnityEngine.Rendering.GraphicsSettings.HasShaderDefine(UnityEngine.Rendering.BuiltinShaderDefine.UNITY_NO_DXT5nm))
format = probeFormat;
//#else
// if (SystemInfo.SupportsTextureFormat(probeFormat) && !TextureCache.isMobileBuildTarget)
// // On editor the texture is uncompressed when operating against mobile build targets
////#if UNITY_2017_2_OR_NEWER
// if (SystemInfo.SupportsTextureFormat(probeFormat) && !UnityEngine.Rendering.GraphicsSettings.HasShaderDefine(UnityEngine.Rendering.BuiltinShaderDefine.UNITY_NO_DXT5nm))
//#endif
////#else
//// if (SystemInfo.SupportsTextureFormat(probeFormat) && !TextureCache.isMobileBuildTarget)
//// format = probeFormat;
////#endif
return format;
}

private static uint g_MaxFrameCount = unchecked((uint)(-1));
private static uint g_InvalidTexID = (uint)0;
public int FetchSlice(Texture texture, bool forceReinject=false)
public uint GetTextureUpdateCount(Texture texture)
var sliceIndex = -1;
uint updateCount = texture.updateCount;
// For baked probes in the editor we need to factor in the actual hash of texture because we can't increment the update count of a texture that's baked on the disk.
// This code leaks logic from reflection probe baking into the texture cache which is not good... TODO: Find a way to do that outside of the texture cache.
#if UNITY_EDITOR
updateCount += (uint)texture.imageContentsHash.GetHashCode();
#endif
return updateCount;
}
public int ReserveSlice(Texture texture, out bool needUpdate)
{
needUpdate = false;
return sliceIndex;
return -1;
var updateCount = texture.updateCount;
//assert(TexID!=g_InvalidTexID);
if (texId == g_InvalidTexID) return 0;
var bSwapSlice = forceReinject;
var bFoundAvailOrExistingSlice = false;
if (texId == g_InvalidTexID)
return -1;
int cachedSlice;
if (m_LocatorInSliceArray.TryGetValue(texId, out cachedSlice))
var sliceIndex = -1;
var foundIndex = -1;
if (m_LocatorInSliceArray.TryGetValue(texId, out foundIndex))
sliceIndex = cachedSlice;
Debug.Assert(m_SliceArray[sliceIndex].texId == texId);
sliceIndex = foundIndex;
bFoundAvailOrExistingSlice = true;
bSwapSlice = bSwapSlice || (m_SliceArray[sliceIndex].updateCount != updateCount);
var updateCount = GetTextureUpdateCount(texture);
needUpdate |= (m_SliceArray[sliceIndex].updateCount != updateCount);
Debug.Assert(m_SliceArray[sliceIndex].texId == texId);
if (!bFoundAvailOrExistingSlice)
if(sliceIndex == -1)
{
// look for first non zero entry. Will by the least recently used entry
// since the array was pre-sorted (in linear time) in NewFrame()

{
idx = m_SortedIdxArray[j];
if (m_SliceArray[idx].countLRU == 0) ++j; // if entry already snagged by a new texture in this frame then ++j
else bFound = true;
if (m_SliceArray[idx].countLRU == 0)
++j; // if entry already snagged by a new texture in this frame then ++j
else
bFound = true;
needUpdate = true;
// if we are replacing an existing entry delete it from m_locatorInSliceArray.
if (m_SliceArray[idx].texId != g_InvalidTexID)
{

m_SliceArray[idx].texId = texId;
sliceIndex = idx;
bFoundAvailOrExistingSlice = true;
bSwapSlice = true;
// wrap up
Debug.Assert(bFoundAvailOrExistingSlice, "The texture cache doesn't have enough space to store all textures. Please either increase the size of the texture cache, or use fewer unique textures.");
if (bFoundAvailOrExistingSlice)
if(sliceIndex != -1)
m_SliceArray[sliceIndex].countLRU = 0; // mark slice as in use this frame
m_SliceArray[sliceIndex].countLRU = 0; // mark slice as in use this frame
}
if (bSwapSlice) // if this was a miss
{
m_SliceArray[sliceIndex].updateCount = updateCount;
return sliceIndex;
}
// transfer new slice to sliceIndex from source texture
TransferToSlice(sliceIndex, texture);
}
// In case the texture content with which we update the cache is not the input texture, we need to provide the right update count.
public void UpdateSlice(CommandBuffer cmd, int sliceIndex, Texture content, uint updateCount)
{
// transfer new slice to sliceIndex from source texture
m_SliceArray[sliceIndex].updateCount = updateCount;
TransferToSlice(cmd, sliceIndex, content);
}
public void UpdateSlice(CommandBuffer cmd, int sliceIndex, Texture content)
{
UpdateSlice(cmd, sliceIndex, content, GetTextureUpdateCount(content));
}
public int FetchSlice(CommandBuffer cmd, Texture texture, bool forceReinject=false)
{
bool needUpdate = false;
var sliceIndex = ReserveSlice(texture, out needUpdate);
var bSwapSlice = forceReinject || needUpdate;
// wrap up
Debug.Assert(sliceIndex != -1, "The texture cache doesn't have enough space to store all textures. Please either increase the size of the texture cache, or use fewer unique textures.");
if (sliceIndex != -1 && bSwapSlice)
{
UpdateSlice(cmd, sliceIndex, texture);
}
return sliceIndex;

m_NumMipLevels = 0;
}
public virtual void TransferToSlice(int sliceIndex, Texture texture)
public virtual void TransferToSlice(CommandBuffer cmd, int sliceIndex, Texture texture)
{
}

19
ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine.Rendering;
using System;
using System.Diagnostics;

Material m_CopyStencilForRegularLighting;
GPUCopy m_GPUCopy;
IBLFilterGGX m_IBLFilterGGX = null;
// Various set of material use in render loop
ComputeShader m_SubsurfaceScatteringCS { get { return m_Asset.renderPipelineResources.subsurfaceScatteringCS; } }
int m_SubsurfaceScatteringKernel;

RenderTargetIdentifier m_CameraStencilBufferCopyRT;
RenderTargetIdentifier m_HTileRT;
// The pass "SRPDefaultUnlit" is a fall back to legacy unlit rendering and is required to support unity 2d + unity UI that render in the scene.
// The pass "SRPDefaultUnlit" is a fallback to legacy unlit rendering and is required to support unity 2d + unity UI that render in the scene.
ShaderPassName[] m_ForwardAndForwardOnlyPassNames = { new ShaderPassName(), new ShaderPassName(), HDShaderPassNames.s_SRPDefaultUnlitName};
ShaderPassName[] m_ForwardOnlyPassNames = { new ShaderPassName(), HDShaderPassNames.s_SRPDefaultUnlitName};
ShaderPassName[] m_DepthOnlyAndDepthForwardOnlyPassNames = { HDShaderPassNames.s_DepthForwardOnlyName, HDShaderPassNames.s_DepthOnlyName };

m_MaterialList.ForEach(material => material.Build(asset.renderPipelineResources));
m_LightLoop.Build(asset.renderPipelineResources, asset.tileSettings, asset.textureSettings, asset.shadowInitParams, m_ShadowSettings);
m_IBLFilterGGX = new IBLFilterGGX(asset.renderPipelineResources);
m_LightLoop.Build(asset.renderPipelineResources, asset.tileSettings, asset.textureSettings, asset.shadowInitParams, m_ShadowSettings, m_IBLFilterGGX);
m_SkyManager.Build(asset.renderPipelineResources);
m_SkyManager.Build(asset.renderPipelineResources, m_IBLFilterGGX);
m_SkyManager.skySettings = skySettingsToUse;
m_PostProcessContext = new PostProcessRenderContext();

#if UNITY_EDITOR
static readonly SupportedRenderingFeatures s_NeededFeatures = new SupportedRenderingFeatures()
{
reflectionProbeSupportFlags = SupportedRenderingFeatures.ReflectionProbeSupportFlags.Rotation
reflectionProbe = SupportedRenderingFeatures.ReflectionProbe.Rotation
};
#endif

ApplyDebugDisplaySettings();
UpdateCommonSettings();
if (!m_IBLFilterGGX.IsInitialized())
m_IBLFilterGGX.Initialize(cmd);
ScriptableCullingParameters cullingParams;
if (!CullResults.GetCullingParameters(camera, out cullingParams))
{

// Currently to know if you need shadow mask you need to go through all visible lights (of CullResult), check the LightBakingOutput struct and look at lightmapBakeType/mixedLightingMode. If one light have shadow mask bake mode, then you need shadow mask features (i.e extra Gbuffer).
// It mean that when we build a standalone player, if we detect a light with bake shadow mask, we generate all shader variant (with and without shadow mask) and at runtime, when a bake shadow mask light is visible, we dynamically allocate an extra GBuffer and switch the shader.
// So the first thing to do is to go through all the light: PrepareLightsForGPU
bool enableBakeShadowMask = m_LightLoop.PrepareLightsForGPU(m_ShadowSettings, m_CullResults, camera);
bool enableBakeShadowMask = m_LightLoop.PrepareLightsForGPU(cmd, m_ShadowSettings, m_CullResults, camera);
ConfigureForShadowMask(enableBakeShadowMask, cmd);
InitAndClearBuffer(hdCamera, enableBakeShadowMask, cmd);

60
ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs


using UnityEngine.Rendering;
using UnityEngine.Rendering;
using System.Collections.Generic;
using System;

static Texture2DArray m_DefaultTexture2DArray;
TextureCacheCubemap m_CubeReflTexArray;
int m_CubeReflTexArraySize = 128;
ReflectionProbeCache m_ReflectionProbeCache;
int m_ReflectionProbeCacheSize = 128;
TextureCache2D m_CookieTexArray;
int m_CookieTexArraySize = 16;
TextureCacheCubemap m_CubeCookieTexArray;

public LightLoop()
{}
public void Build(RenderPipelineResources renderPipelineResources, TileSettings tileSettings, TextureSettings textureSettings, ShadowInitParameters shadowInit, ShadowSettings shadowSettings)
public void Build(RenderPipelineResources renderPipelineResources, TileSettings tileSettings, TextureSettings textureSettings, ShadowInitParameters shadowInit, ShadowSettings shadowSettings, IBLFilterGGX iblFilterGGX)
{
m_Resources = renderPipelineResources;
m_TileSettings = tileSettings;

m_CookieTexArray.AllocTextureArray(m_CookieTexArraySize, textureSettings.spotCookieSize, textureSettings.spotCookieSize, TextureFormat.RGBA32, true);
m_CubeCookieTexArray = new TextureCacheCubemap();
m_CubeCookieTexArray.AllocTextureArray(m_CubeCookieTexArraySize, textureSettings.pointCookieSize, TextureFormat.RGBA32, true);
m_CubeReflTexArray = new TextureCacheCubemap();
m_CubeReflTexArray.AllocTextureArray(m_CubeReflTexArraySize, textureSettings.reflectionCubemapSize, TextureCache.GetPreferredHdrCompressedTextureFormat, true);
m_ReflectionProbeCache = new ReflectionProbeCache(iblFilterGGX, m_ReflectionProbeCacheSize, textureSettings.reflectionCubemapSize, TextureCache.GetPreferredHdrCompressedTextureFormat, true);
s_GenAABBKernel = buildScreenAABBShader.FindKernel("ScreenBoundsAABB");

CoreUtils.SafeRelease(s_EnvLightDatas);
CoreUtils.SafeRelease(s_shadowDatas);
if (m_CubeReflTexArray != null)
if (m_ReflectionProbeCache != null)
m_CubeReflTexArray.Release();
m_CubeReflTexArray = null;
m_ReflectionProbeCache.Release();
m_ReflectionProbeCache = null;
}
if (m_CookieTexArray != null)
{

{
m_CookieTexArray.NewFrame();
m_CubeCookieTexArray.NewFrame();
m_CubeReflTexArray.NewFrame();
m_ReflectionProbeCache.NewFrame();
}
public bool NeedResize()

return new Vector3(light.finalColor.r, light.finalColor.g, light.finalColor.b);
}
public bool GetDirectionalLightData(ShadowSettings shadowSettings, GPULightType gpuLightType, VisibleLight light, HDAdditionalLightData additionalData, AdditionalShadowData additionalShadowData, int lightIndex)
public bool GetDirectionalLightData(CommandBuffer cmd, ShadowSettings shadowSettings, GPULightType gpuLightType, VisibleLight light, HDAdditionalLightData additionalData, AdditionalShadowData additionalShadowData, int lightIndex)
{
var directionalLightData = new DirectionalLightData();

if (light.light.cookie != null)
{
directionalLightData.tileCookie = light.light.cookie.wrapMode == TextureWrapMode.Repeat;
directionalLightData.cookieIndex = m_CookieTexArray.FetchSlice(light.light.cookie);
directionalLightData.cookieIndex = m_CookieTexArray.FetchSlice(cmd, light.light.cookie);
}
// fix up shadow information
int shadowIdx;

return 1.0f - Mathf.Clamp01(distanceToCamera * scale + bias);
}
public bool GetLightData(ShadowSettings shadowSettings, Camera camera, GPULightType gpuLightType, VisibleLight light, HDAdditionalLightData additionalLightData, AdditionalShadowData additionalshadowData, int lightIndex)
public bool GetLightData(CommandBuffer cmd, ShadowSettings shadowSettings, Camera camera, GPULightType gpuLightType, VisibleLight light, HDAdditionalLightData additionalLightData, AdditionalShadowData additionalshadowData, int lightIndex)
{
var lightData = new LightData();

switch (light.lightType)
{
case LightType.Spot:
lightData.cookieIndex = m_CookieTexArray.FetchSlice(light.light.cookie);
lightData.cookieIndex = m_CookieTexArray.FetchSlice(cmd, light.light.cookie);
lightData.cookieIndex = m_CubeCookieTexArray.FetchSlice(light.light.cookie);
lightData.cookieIndex = m_CubeCookieTexArray.FetchSlice(cmd, light.light.cookie);
break;
}
}

lightData.cookieIndex = m_CookieTexArray.FetchSlice(Texture2D.whiteTexture);
lightData.cookieIndex = m_CookieTexArray.FetchSlice(cmd, Texture2D.whiteTexture);
}
if (additionalshadowData)

m_lightList.lightVolumes.Add(lightVolumeData);
}
public void GetEnvLightData(VisibleReflectionProbe probe)
public bool GetEnvLightData(CommandBuffer cmd, VisibleReflectionProbe probe)
int envIndex = m_ReflectionProbeCache.FetchSlice(cmd, probe.texture);
// -1 means that the texture is not ready yet (ie not convolved/compressed yet)
if (envIndex == -1)
return false;
var envLightData = new EnvLightData();
// CAUTION: localToWorld is the transform for the widget of the reflection probe. i.e the world position of the point use to do the cubemap capture (mean it include the local offset)

float maxBlendDist = Mathf.Min(probe.bounds.extents.x, Mathf.Min(probe.bounds.extents.y, probe.bounds.extents.z));
float blendDistance = Mathf.Min(maxBlendDist, probe.blendDistance);
envLightData.innerDistance = probe.bounds.extents - new Vector3(blendDistance, blendDistance, blendDistance);
envLightData.envIndex = m_CubeReflTexArray.FetchSlice(probe.texture);
envLightData.envIndex = envIndex;
return true;
}
public void GetEnvLightVolumeDataAndBound(VisibleReflectionProbe probe, LightVolumeType lightVolumeType, Matrix4x4 worldToView)

}
// Return true if BakedShadowMask are enabled
public bool PrepareLightsForGPU(ShadowSettings shadowSettings, CullResults cullResults, Camera camera)
public bool PrepareLightsForGPU(CommandBuffer cmd, ShadowSettings shadowSettings, CullResults cullResults, Camera camera)
{
// If any light require it, we need to enabled bake shadow mask feature
m_enableBakeShadowMask = false;

// Directional rendering side, it is separated as it is always visible so no volume to handle here
if (gpuLightType == GPULightType.Directional)
{
if (GetDirectionalLightData(shadowSettings, gpuLightType, light, additionalLightData, additionalShadowData, lightIndex))
if (GetDirectionalLightData(cmd, shadowSettings, gpuLightType, light, additionalLightData, additionalShadowData, lightIndex))
{
directionalLightcount++;

}
// Punctual, area, projector lights - the rendering side.
if (GetLightData(shadowSettings, camera, gpuLightType, light, additionalLightData, additionalShadowData, lightIndex))
if (GetLightData(cmd, shadowSettings, camera, gpuLightType, light, additionalLightData, additionalShadowData, lightIndex))
{
switch (lightCategory)
{

VisibleReflectionProbe probe = cullResults.visibleReflectionProbes[probeIndex];
GetEnvLightData(probe);
if(GetEnvLightData(cmd, probe))
{
GetEnvLightVolumeDataAndBound(probe, lightVolumeType, worldToView);
// We make the light position camera-relative as late as possible in order

}
}
// Sanity check
Debug.Assert(m_lightList.envLights.Count == envLightCount);
}
// Restore values after "special rendering"
m_TileSettings.specularGlobalDimmer = oldSpecularGlobalDimmer;

SetGlobalTexture(HDShaderIDs._CookieTextures, m_CookieTexArray.GetTexCache());
SetGlobalTexture(HDShaderIDs._CookieCubeTextures, m_CubeCookieTexArray.GetTexCache());
SetGlobalTexture(HDShaderIDs._EnvTextures, m_CubeReflTexArray.GetTexCache());
SetGlobalTexture(HDShaderIDs._EnvTextures, m_ReflectionProbeCache.GetTexCache());
SetGlobalBuffer(HDShaderIDs._DirectionalLightDatas, s_DirectionalLightDatas);
SetGlobalInt(HDShaderIDs._DirectionalLightCount, m_lightList.directionalLights.Count);

56
ScriptableRenderPipeline/HDRenderPipeline/Sky/RuntimeFilterIBL.cs


Material m_GgxConvolveMaterial; // Convolves a cubemap with GGX
Matrix4x4[] m_faceWorldToViewMatrixMatrices = new Matrix4x4[6];
RenderPipelineResources m_RenderPipelinesResources;
public bool supportMis

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. ...
}
void FilterCubemapCommon(CommandBuffer cmd,
Texture source, RenderTexture target, int mipCount,
Matrix4x4[] worldToViewMatrices)
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);
}
}
m_GgxConvolveMaterial.SetTexture("_MainTex", source);
m_GgxConvolveMaterial.SetFloat("_InvOmegaP", invOmegaP);
var props = new MaterialPropertyBlock();
props.SetTexture("_MainTex", source);
props.SetFloat("_InvOmegaP", invOmegaP);
props.SetFloat("_Level", mip);
using (new ProfilingSample(cmd, "Filter Cubemap Mip {0}", mip))
{
for (int face = 0; face < 6; ++face)

var props = new MaterialPropertyBlock();
props.SetFloat("_Level", mip);
props.SetMatrix(HDShaderIDs._PixelCoordToViewDirWS, transform);
CoreUtils.SetRenderTarget(cmd, target, ClearFlag.None, mip, (CubemapFace)face);

}
// Filters MIP map levels (other than 0) with GGX using BRDF importance sampling.
public void FilterCubemap(CommandBuffer cmd,
Texture source, RenderTexture target, int mipCount,
Matrix4x4[] worldToViewMatrices)
public void FilterCubemap(CommandBuffer cmd, Texture source, RenderTexture target)
FilterCubemapCommon(cmd, source, target, mipCount, worldToViewMatrices);
FilterCubemapCommon(cmd, source, target, m_faceWorldToViewMatrixMatrices);
public void FilterCubemapMIS(CommandBuffer cmd,
Texture source, RenderTexture target, int mipCount,
RenderTexture conditionalCdf, RenderTexture marginalRowCdf,
Matrix4x4[] worldToViewMatrices)
public void FilterCubemapMIS( CommandBuffer cmd,
Texture source, RenderTexture target,
RenderTexture conditionalCdf, RenderTexture marginalRowCdf)
{
// Bind the input cubemap.
m_BuildProbabilityTablesCS.SetTexture(m_ConditionalDensitiesKernel, "envMap", source);

m_GgxConvolveMaterial.SetTexture("_ConditionalDensities", conditionalCdf);
m_GgxConvolveMaterial.SetTexture("_MarginalRowDensities", marginalRowCdf);
FilterCubemapCommon(cmd, source, target, mipCount, worldToViewMatrices);
FilterCubemapCommon(cmd, source, target, m_faceWorldToViewMatrixMatrices);
}
}
}

66
ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs


IBLFilterGGX m_iblFilterGgx;
Vector4 m_CubemapScreenSize;
Matrix4x4[] m_faceWorldToViewMatrixMatrices = new Matrix4x4[6];
Matrix4x4[] m_facePixelCoordToViewDirMatrices = new Matrix4x4[6];
Matrix4x4[] m_faceCameraInvViewProjectionMatrix = new Matrix4x4[6];

bool m_useMIS = false;
// Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/bb204881(v=vs.85).aspx
readonly Vector3[] m_LookAtList =
{
new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(-1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, -1.0f, 0.0f),
new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, 0.0f, -1.0f),
};
readonly Vector3[] m_UpVectorList =
{
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
};
SkySettings m_SkySettings;
public SkySettings skySettings
{

for (int i = 0; i < 6; ++i)
{
var lookAt = Matrix4x4.LookAt(Vector3.zero, m_LookAtList[i], m_UpVectorList[i]);
var lookAt = Matrix4x4.LookAt(Vector3.zero, CoreUtils.lookAtList[i], CoreUtils.upVectorList[i]);
m_faceWorldToViewMatrixMatrices[i] = worldToView;
m_facePixelCoordToViewDirMatrices[i] = ComputePixelCoordToWorldSpaceViewDirectionMatrix(0.5f * Mathf.PI, screenSize, worldToView, true);
m_faceCameraInvViewProjectionMatrix[i] = HDUtils.GetViewProjectionMatrix(lookAt, cubeProj).inverse;
}

RebuildSkyMatrices(nearPlane, farPlane);
}
public void Build(RenderPipelineResources renderPipelinesResources)
public void Build(RenderPipelineResources renderPipelinesResources, IBLFilterGGX iblFilterGGX)
// Create unititialized. Lazy initialization is performed later.
m_iblFilterGgx = new IBLFilterGGX(renderPipelinesResources);
m_iblFilterGgx = iblFilterGGX;
// TODO: We need to have an API to send our sky information to Enlighten. For now use a workaround through skybox/cubemap material...
m_StandardSkyboxMaterial = CoreUtils.CreateEngineMaterial(renderPipelinesResources.skyboxCubemap);

cmd.GenerateMips(dest);
}
void RenderCubemapGGXConvolution(CommandBuffer cmd, BuiltinSkyParameters builtinParams, SkySettings skyParams, Texture input, RenderTexture target)
void RenderCubemapGGXConvolution(CommandBuffer cmd, Texture input, RenderTexture target)
int mipCount = 1 + (int)Mathf.Log(input.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;
}
if (!m_iblFilterGgx.IsInitialized())
m_iblFilterGgx.Initialize(cmd);
// Copy the first mip
using (new ProfilingSample(cmd, "Copy Original Mip"))
{
for (int f = 0; f < 6; f++)
{
cmd.CopyTexture(input, f, 0, target, f, 0);
}
}
using (new ProfilingSample(cmd, "GGX Convolution"))
{
if (m_useMIS && m_iblFilterGgx.supportMis)
m_iblFilterGgx.FilterCubemapMIS(cmd, input, target, mipCount, m_SkyboxConditionalCdfRT, m_SkyboxMarginalRowCdfRT, m_faceWorldToViewMatrixMatrices);
else
m_iblFilterGgx.FilterCubemap(cmd, input, target, mipCount, m_faceWorldToViewMatrixMatrices);
}
if (m_useMIS && m_iblFilterGgx.supportMis)
m_iblFilterGgx.FilterCubemapMIS(cmd, input, target, m_SkyboxConditionalCdfRT, m_SkyboxMarginalRowCdfRT);
else
m_iblFilterGgx.FilterCubemap(cmd, input, target);
}
}

}
// Convolve downsampled cubemap
RenderCubemapGGXConvolution(cmd, m_BuiltinParameters, skySettings, m_SkyboxCubemapRT, m_SkyboxGGXCubemapRT);
RenderCubemapGGXConvolution(cmd, m_SkyboxCubemapRT, m_SkyboxGGXCubemapRT);
m_NeedLowLevelUpdateEnvironment = true;
m_UpdatedFramesRequired--;

{
// Clear temp cubemap and redo GGX from black and then feed it to enlighten for default light probe.
CoreUtils.ClearCubemap(cmd, m_SkyboxCubemapRT, Color.black);
RenderCubemapGGXConvolution(cmd, m_BuiltinParameters, skySettings, m_SkyboxCubemapRT, m_SkyboxGGXCubemapRT);
RenderCubemapGGXConvolution(cmd, m_SkyboxCubemapRT, m_SkyboxGGXCubemapRT);
m_SkyParametersHash = 0;
m_NeedLowLevelUpdateEnvironment = true;

13
TestbedPipelines/Fptl/FptlLighting.cs


return dirLightCount;
}
int GenerateSourceLightBuffers(Camera camera, CullResults inputs)
int GenerateSourceLightBuffers(CommandBuffer cmd, Camera camera, CullResults inputs)
{
// 0. deal with shadows
{

var isCircularSpot = !bHasCookie;
if (!isCircularSpot) // square spots always have cookie
{
light.sliceIndex = m_CookieTexArray.FetchSlice(cl.light.cookie);
light.sliceIndex = m_CookieTexArray.FetchSlice(cmd, cl.light.cookie);
}
Vector3 lightDir = lightToWorld.GetColumn(2); // Z axis in world space

{
if (bHasCookie)
{
light.sliceIndex = m_CubeCookieTexArray.FetchSlice(cl.light.cookie);
light.sliceIndex = m_CubeCookieTexArray.FetchSlice(cmd, cl.light.cookie);
}
var lightToView = worldToView * lightToWorld;

lgtData.lightIntensity = decodeVals.x;
lgtData.decodeExp = decodeVals.y;
lgtData.sliceIndex = m_CubeReflTexArray.FetchSlice(cubemap);
lgtData.sliceIndex = m_CubeReflTexArray.FetchSlice(cmd, cubemap);
var delta = combinedExtent - e;
lgtData.boxInnerDist = e;

var invProjscr = projscr.inverse;
// build per tile light lists
var numLights = GenerateSourceLightBuffers(camera, cullResults);
CommandBuffer cmdGenerateLightBuffers = CommandBufferPool.Get();
var numLights = GenerateSourceLightBuffers(cmdGenerateLightBuffers, camera, cullResults);
loop.ExecuteCommandBuffer(cmdGenerateLightBuffers);
CommandBufferPool.Release(cmdGenerateLightBuffers);
GPUFence postLightListFence;

10
TestbedPipelines/OnTileDeferredPipeline/OnTileDeferredRenderPipeline.cs


m_LightData[i].x = LightDefinitions.SPHERE_LIGHT;
if (light.light.cookie != null)
m_LightData[i].z = m_CubeCookieTexArray.FetchSlice(light.light.cookie);
m_LightData[i].z = m_CubeCookieTexArray.FetchSlice(cmd, light.light.cookie);
} else if (light.lightType == LightType.Spot) {
m_LightData[i].x = LightDefinitions.SPOT_LIGHT;

m_LightMatrix[i] = SpotlightMatrix (light, worldToLight, range, chsa);
if (light.light.cookie != null)
m_LightData[i].z = m_CookieTexArray.FetchSlice (light.light.cookie);
m_LightData[i].z = m_CookieTexArray.FetchSlice (cmd, light.light.cookie);
m_LightData [i].z = m_CookieTexArray.FetchSlice (m_DefaultSpotCookie);
m_LightData [i].z = m_CookieTexArray.FetchSlice (cmd, m_DefaultSpotCookie);
} else if (light.lightType == LightType.Directional) {
m_LightData[i].x = LightDefinitions.DIRECTIONAL_LIGHT;

if (light.light.cookie != null)
m_LightData[i].z = m_CookieTexArray.FetchSlice (light.light.cookie);
m_LightData[i].z = m_CookieTexArray.FetchSlice (cmd, light.light.cookie);
}
}

lgtData.lightIntensity = decodeVals.x;
lgtData.decodeExp = decodeVals.y;
lgtData.sliceIndex = m_CubeReflTexArray.FetchSlice(cubemap);
lgtData.sliceIndex = m_CubeReflTexArray.FetchSlice(cmd, cubemap);
var delta = combinedExtent - e;
lgtData.boxInnerDist = e;

正在加载...
取消
保存