浏览代码

Make VBuffer view handling less error prone

/main
Evgenii Golubev 7 年前
当前提交
9e4045c2
共有 2 个文件被更改,包括 161 次插入168 次删除
  1. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs
  2. 323
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs


m_LightLoop.AllocResolutionDependentBuffers(texWidth, texHeight);
}
int viewId = hdCamera.camera.GetInstanceID(); // Warning: different views can use the same camera
ResizeVBuffer(viewId, texWidth, texHeight);
{
ResizeVBuffer(GetViewID(hdCamera), texWidth, texHeight);
}
// update recorded window resolution
m_CurrentWidth = texWidth;

323
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs


using System;
using UnityEngine.Rendering;
using System.Collections.Generic;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{

VolumetricLightingPreset m_VolumetricLightingPreset
{ get { return (VolumetricLightingPreset)Math.Min(ShaderConfig.s_VolumetricLightingPreset, (int)VolumetricLightingPreset.Count); } }
ComputeShader m_VolumetricLightingCS { get { return m_Asset.renderPipelineResources.volumetricLightingCS; } }
ComputeShader m_VolumetricLightingCS { get { return m_Asset.renderPipelineResources.volumetricLightingCS; } }
float m_VBufferNearPlane = 0.5f; // Distance in meters; dynamic modifications not handled by reprojection
float m_VBufferFarPlane = 64.0f; // Distance in meters; dynamic modifications not handled by reprojection
const int k_VBufferCount = 3; // 0 and 1 - history (prev) and feedback (next), 2 - integral (curr)
class VBuffer
{
public int viewID = -1; // -1 is invalid; positive for Game Views, 0 otherwise
public RenderTexture[] lightingRTEX = null;
public RenderTargetIdentifier[] lightingRTID = null;
RenderTexture[] m_VBufferLighting = null;
RenderTargetIdentifier[] m_VBufferLightingRT = null;
public RenderTargetIdentifier GetLightingIntegralBuffer() // Of the current frame
{
Debug.Assert(viewID >= 0);
return lightingRTID[0];
}
int m_ViewCount = 0;
int[] m_ViewIdArray = new int[8]; // TODO: account for the CameraType
public RenderTargetIdentifier GetLightingHistoryBuffer() // From the previous frame
{
Debug.Assert(viewID > 0); // Game View only
return lightingRTID[1 + ((Time.renderedFrameCount + 0) & 1)];
}
int ViewOffsetFromViewId(int viewId)
public RenderTargetIdentifier GetLightingFeedbackBuffer() // For the next frame
{
Debug.Assert(viewID > 0); // Game View only
return lightingRTID[1 + ((Time.renderedFrameCount + 1) & 1)];
}
};
List<VBuffer> m_VBuffers = null;
float m_VBufferNearPlane = 0.5f; // Distance in meters; dynamic modifications not handled by reprojection
float m_VBufferFarPlane = 64.0f; // Distance in meters; dynamic modifications not handled by reprojection
// Warning: different views can use the same camera!
int GetViewID(HDCamera camera)
int viewOffset = -1;
Debug.Assert(camera != null);
Debug.Assert(m_ViewCount == 0 || m_ViewIdArray != null);
if (camera.camera.cameraType == CameraType.Game)
{
int viewID = camera.camera.GetInstanceID();
Debug.Assert(viewID > 0);
return viewID;
}
else
{
return 0;
}
}
for (int i = 0; i < m_ViewCount; i++)
VBuffer FindVBuffer(int viewID)
{
Debug.Assert(viewID >= 0);
VBuffer vBuffer = null;
if (m_VBuffers != null)
if (m_ViewIdArray[i] == viewId)
int n = m_VBuffers.Count;
for (int i = 0; i < n; i++)
viewOffset = i;
if (viewID == m_VBuffers[i].viewID)
{
vBuffer = m_VBuffers[i];
}
return viewOffset;
return vBuffer;
}
void ResizeVBuffer(int viewID, int screenWidth, int screenHeight)
{
Debug.Assert(viewID >= 0);
int w = 0, h = 0, d = 0;
ComputeVBufferResolutionAndScale(screenWidth, screenHeight, ref w, ref h, ref d);
VBuffer vBuffer = FindVBuffer(viewID);
if (vBuffer != null)
{
Debug.Assert(vBuffer.lightingRTEX != null);
Debug.Assert(vBuffer.lightingRTEX[0] != null);
Debug.Assert(vBuffer.lightingRTID != null);
// Found, check resolution.
if (w == vBuffer.lightingRTEX[0].width &&
h == vBuffer.lightingRTEX[0].height &&
d == vBuffer.lightingRTEX[0].volumeDepth)
{
// Everything matches, nothing to do here.
return;
}
}
// Otherwise, we have to (re)create the VBuffer.
CreateVBuffer(viewID, w, h, d, vBuffer);
}
void CreateVBuffer(int viewID, int w, int h, int d, VBuffer vBuffer)
{
Debug.Assert(viewID >= 0);
if (vBuffer != null)
{
// Clean up first.
DestroyVBuffer(vBuffer);
}
else
{
// Grow the array.
vBuffer = new VBuffer();
if (m_VBuffers == null)
{
m_VBuffers = new List<VBuffer>(1);
}
m_VBuffers.Add(vBuffer);
}
bool isGameView = viewID > 0;
int numBuffers = isGameView ? 3 : 1;
vBuffer.viewID = viewID;
vBuffer.lightingRTEX = new RenderTexture[numBuffers];
vBuffer.lightingRTID = new RenderTargetIdentifier[numBuffers];
for (int i = 0; i < numBuffers; i++)
{
vBuffer.lightingRTEX[i] = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
vBuffer.lightingRTEX[i].filterMode = FilterMode.Trilinear; // Custom
vBuffer.lightingRTEX[i].dimension = TextureDimension.Tex3D; // TODO: request the thick 3D tiling layout
vBuffer.lightingRTEX[i].volumeDepth = d;
vBuffer.lightingRTEX[i].enableRandomWrite = true;
vBuffer.lightingRTEX[i].Create();
vBuffer.lightingRTID[i] = new RenderTargetIdentifier(vBuffer.lightingRTEX[i]);
}
}
void DestroyVBuffer(VBuffer vBuffer)
{
if (vBuffer == null) return;
if (vBuffer.lightingRTEX != null)
{
int n = vBuffer.lightingRTEX.Length;
for (int i = 0; i < n; i++)
{
vBuffer.lightingRTEX[i].Release();
}
}
vBuffer.viewID = -1;
vBuffer.lightingRTEX = null;
vBuffer.lightingRTID = null;
}
public static int ComputeVBufferTileSize(VolumetricLightingPreset preset)

return new Vector2(screenWidth / (w * t), screenHeight / (h * t));
}
void ResizeVBuffer(int viewId, int screenWidth, int screenHeight)
{
int viewOffset = ViewOffsetFromViewId(viewId);
if (viewOffset >= 0)
{
// Found, check resolution.
int w = 0, h = 0, d = 0;
ComputeVBufferResolutionAndScale(screenWidth, screenHeight, ref w, ref h, ref d);
Debug.Assert(m_VBufferLighting != null);
Debug.Assert(m_VBufferLighting.Length >= (viewOffset + 1) * k_VBufferCount);
Debug.Assert(m_VBufferLighting[viewOffset * k_VBufferCount] != null);
if (w == m_VBufferLighting[viewOffset * k_VBufferCount].width &&
h == m_VBufferLighting[viewOffset * k_VBufferCount].height &&
d == m_VBufferLighting[viewOffset * k_VBufferCount].volumeDepth)
{
// Everything matches, nothing to do here.
return;
}
}
// Otherwise, we have to recreate the VBuffer.
CreateVBuffer(viewId, screenWidth, screenHeight);
}
void CreateVBuffer(int viewId, int screenWidth, int screenHeight)
{
// Clean up first.
DestroyVBuffer(viewId);
int viewOffset = ViewOffsetFromViewId(viewId);
if (viewOffset < 0)
{
// Not found. Push back.
viewOffset = m_ViewCount++;
Debug.Assert(viewOffset < 8);
m_ViewIdArray[viewOffset] = viewId;
if (m_VBufferLighting == null)
{
// Lazy initialize.
m_VBufferLighting = new RenderTexture[k_VBufferCount];
m_VBufferLightingRT = new RenderTargetIdentifier[k_VBufferCount];
}
else if (m_VBufferLighting.Length < m_ViewCount * k_VBufferCount)
{
// Grow by reallocation and copy.
RenderTexture[] newArray = new RenderTexture[m_ViewCount * k_VBufferCount];
RenderTargetIdentifier[] newArrayRT = new RenderTargetIdentifier[m_ViewCount * k_VBufferCount];
for (int i = 0, n = m_VBufferLighting.Length; i < n; i++)
{
newArray[i] = m_VBufferLighting[i];
newArrayRT[i] = m_VBufferLightingRT[i];
}
// Reassign and release memory.
m_VBufferLighting = newArray;
m_VBufferLightingRT = newArrayRT;
}
}
Debug.Assert(m_VBufferLighting != null);
int w = 0, h = 0, d = 0;
ComputeVBufferResolutionAndScale(screenWidth, screenHeight, ref w, ref h, ref d);
for (int i = viewOffset * k_VBufferCount,
n = viewOffset * k_VBufferCount + k_VBufferCount; i < n; i++)
{
m_VBufferLighting[i] = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
m_VBufferLighting[i].filterMode = FilterMode.Trilinear; // Custom
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]);
}
}
void DestroyVBuffer(int viewId)
{
int viewOffset = ViewOffsetFromViewId(viewId);
if (viewOffset < 0)
{
// Not found.
return;
}
int lastOffset = m_ViewCount - 1;
Debug.Assert(lastOffset >= 0);
if (m_VBufferLighting != null)
{
Debug.Assert(m_VBufferLighting.Length >= m_ViewCount * k_VBufferCount);
for (int i = 0; i < k_VBufferCount; i++)
{
int viewBuffer = viewOffset * k_VBufferCount + i;
int lastBuffer = lastOffset * k_VBufferCount + i;
// Release the memory.
if (m_VBufferLighting[viewBuffer] != null)
{
m_VBufferLighting[viewBuffer].Release();
}
// Swap with the last element.
m_VBufferLighting[viewBuffer] = m_VBufferLighting[lastBuffer];
m_VBufferLightingRT[viewBuffer] = m_VBufferLightingRT[lastBuffer];
}
}
// Swap with the last element and shrink the array.
m_ViewIdArray[viewOffset] = m_ViewIdArray[lastOffset];
m_ViewCount--;
}
// 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).

return globalFogComponent;
}
RenderTargetIdentifier GetVBufferLightingHistory(int viewOffset) // From the previous frame
{
return m_VBufferLightingRT[viewOffset * k_VBufferCount + ((Time.renderedFrameCount + 0) & 1)]; // Does not work in the Scene view
}
RenderTargetIdentifier GetVBufferLightingFeedback(int viewOffset) // For the next frame
{
return m_VBufferLightingRT[viewOffset * k_VBufferCount + ((Time.renderedFrameCount + 1) & 1)]; // Does not work in the Scene view
}
RenderTargetIdentifier GetVBufferLightingIntegral(int viewOffset) // Of the current frame
{
return m_VBufferLightingRT[viewOffset * k_VBufferCount + 2];
}
public void SetVolumetricLightingData(HDCamera camera, CommandBuffer cmd)
{
HomogeneousFog globalFogComponent = GetGlobalFogComponent();

int w = 0, h = 0, d = 0;
Vector2 scale = ComputeVBufferResolutionAndScale(camera.screenSize.x, camera.screenSize.y, ref w, ref h, ref d);
int viewId = camera.camera.GetInstanceID();
int viewOffset = ViewOffsetFromViewId(viewId);
Debug.Assert(viewOffset >= 0 && viewOffset < 8);
VBuffer vBuffer = FindVBuffer(GetViewID(camera));
Debug.Assert(vBuffer != null);
cmd.SetGlobalTexture(HDShaderIDs._VBufferLighting, GetVBufferLightingIntegral(viewOffset));
cmd.SetGlobalTexture(HDShaderIDs._VBufferLighting, vBuffer.GetLightingIntegralBuffer());
}
// Ref: https://en.wikipedia.org/wiki/Close-packing_of_equal_spheres

using (new ProfilingSample(cmd, "Volumetric Lighting"))
{
int viewId = camera.camera.GetInstanceID(); // Warning: different views can use the same camera
int viewOffset = ViewOffsetFromViewId(viewId);
Debug.Assert(viewOffset >= 0 && viewOffset < 8);
VBuffer vBuffer = FindVBuffer(GetViewID(camera));
Debug.Assert(vBuffer != null);
if (GetGlobalFogComponent() == null)
{

// TODO: set 'm_VolumetricLightingPreset'.
cmd.SetComputeVectorParam( m_VolumetricLightingCS, HDShaderIDs._VBufferSampleOffset, offset);
cmd.SetComputeMatrixParam( m_VolumetricLightingCS, HDShaderIDs._VBufferCoordToViewDirWS, transform);
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingHistory, GetVBufferLightingHistory(viewOffset)); // Read
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingFeedback, GetVBufferLightingFeedback(viewOffset)); // Write
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingIntegral, GetVBufferLightingIntegral(viewOffset)); // Write
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingIntegral, vBuffer.GetLightingIntegralBuffer()); // Write
if (enableReprojection)
{
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingFeedback, vBuffer.GetLightingFeedbackBuffer()); // Write
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingHistory, vBuffer.GetLightingHistoryBuffer()); // Read
}
// The shader defines GROUP_SIZE_1D = 16.
cmd.DispatchCompute(m_VolumetricLightingCS, kernel, (w + 15) / 16, (h + 15) / 16, 1);

正在加载...
取消
保存