浏览代码

Some refactoring and cleanup of how decal draw data gets prepared

/main
Paul Melamed 6 年前
当前提交
382f92e6
共有 6 个文件被更改,包括 116 次插入121 次删除
  1. 153
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs
  2. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs
  3. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs
  4. 67
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs
  5. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.hlsl
  6. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPassDBuffer.hlsl

153
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs


}
}
public DecalData[] DecalDatas
public Camera CurrentCamera
BuildDecalDatas();
return m_DecalDatas;
return m_Camera;
}
set
{
m_Camera = value;
private static readonly int m_NormalToWorldID = Shader.PropertyToID("normalToWorld");
private static readonly int m_DecalAtlasID = Shader.PropertyToID("_DecalAtlas");
private static MaterialPropertyBlock m_PropertyBlock = new MaterialPropertyBlock();
private const int kDecalBlockSize = 128;

static Vector4 kMax = new Vector4( 0.5f, 0.0f, 0.5f, 1.0f);
static public Mesh m_DecalMesh = null;
// static public Matrix4x4[] m_InstanceMatrices = new Matrix4x4[kDrawIndexedBatchSize];
// static public Matrix4x4[] m_InstanceNormalToWorld = new Matrix4x4[kDrawIndexedBatchSize];
// clustered draw data
DecalData[] m_DecalDatas = new DecalData[kDecalBlockSize];
// static public Matrix4x4[] m_DecalToWorld = new Matrix4x4[kDecalBlockSize];
static public List<SFiniteLightBound> m_Bounds = new List<SFiniteLightBound>();
static public List<LightVolumeData> m_LightVolumes = new List<LightVolumeData>();
// current camera
private Camera m_Camera;
private class DecalSet
{

decal.CullIndex = DecalProjectorComponent.kInvalidIndex;
}
public void BeginCull(Camera camera)
public void BeginCull()
{
if (m_CullingGroup != null)
{

m_BoundingDistances[0] = DecalSystem.instance.DrawDistance;
m_NumResults = 0;
m_CullingGroup = new CullingGroup();
m_CullingGroup.targetCamera = camera;
m_CullingGroup.SetDistanceReferencePoint(camera.transform.position);
m_CullingGroup.targetCamera = instance.CurrentCamera;
m_CullingGroup.SetDistanceReferencePoint( m_CullingGroup.targetCamera.transform.position);
m_CullingGroup.SetBoundingDistances(m_BoundingDistances);
m_CullingGroup.SetBoundingSpheres(m_BoundingSpheres);
m_CullingGroup.SetBoundingSphereCount(m_DecalsCount);

return m_NumResults;
}
private void CreateDrawData()
private void GetDecalVolumeDataAndBound(Matrix4x4 decalToWorld, Matrix4x4 worldToView)
{
var bound = new SFiniteLightBound();
var lightVolumeData = new LightVolumeData();
var influenceX = decalToWorld.GetColumn(0) * 0.5f;
var influenceY = decalToWorld.GetColumn(1) * 0.5f;
var influenceZ = decalToWorld.GetColumn(2) * 0.5f;
var pos = decalToWorld.GetColumn(3) - influenceY; // decal cube mesh pivot is at 0,0,0, with bottom face at -1 on the y plane
Vector3 influenceExtents = new Vector3();
influenceExtents.x = influenceX.magnitude;
influenceExtents.y = influenceY.magnitude;
influenceExtents.z = influenceZ.magnitude;
// transform to camera space (becomes a left hand coordinate frame in Unity since Determinant(worldToView)<0)
var influenceRightVS = worldToView.MultiplyVector(influenceX / influenceExtents.x);
var influenceUpVS = worldToView.MultiplyVector(influenceY / influenceExtents.y);
var influenceForwardVS = worldToView.MultiplyVector(influenceZ / influenceExtents.z);
var influencePositionVS = worldToView.MultiplyPoint(pos); // place the mesh pivot in the center
lightVolumeData.lightCategory = (uint)LightCategory.Decal;
lightVolumeData.lightVolume = (uint)LightVolumeType.Box;
lightVolumeData.featureFlags = (uint)LightFeatureFlags.Env;
bound.center = influencePositionVS;
bound.boxAxisX = influenceRightVS * influenceExtents.x;
bound.boxAxisY = influenceUpVS * influenceExtents.y;
bound.boxAxisZ = influenceForwardVS * influenceExtents.z;
bound.scaleXY.Set(1.0f, 1.0f);
bound.radius = influenceExtents.magnitude;
// The culling system culls pixels that are further
// than a threshold to the box influence extents.
// So we use an arbitrary threshold here (k_BoxCullingExtentOffset)
lightVolumeData.lightPos = influencePositionVS;
lightVolumeData.lightAxisX = influenceRightVS;
lightVolumeData.lightAxisY = influenceUpVS;
lightVolumeData.lightAxisZ = influenceForwardVS;
lightVolumeData.boxInnerDist = influenceExtents - LightLoop.k_BoxCullingExtentThreshold;
lightVolumeData.boxInvRange.Set(1.0f / LightLoop.k_BoxCullingExtentThreshold.x, 1.0f /LightLoop. k_BoxCullingExtentThreshold.y, 1.0f / LightLoop.k_BoxCullingExtentThreshold.z);
m_Bounds.Add(bound);
m_LightVolumes.Add(lightVolumeData);
}
private void AssignCurrentBatches(ref Matrix4x4[] decalToWorldBatch, ref Matrix4x4[] normalToWorldBatch, int batchCount)
{
if (m_DecalToWorld.Count == batchCount)
{
decalToWorldBatch = new Matrix4x4[kDrawIndexedBatchSize];
m_DecalToWorld.Add(decalToWorldBatch);
normalToWorldBatch = new Matrix4x4[kDrawIndexedBatchSize];
m_NormalToWorld.Add(normalToWorldBatch);
}
else
{
decalToWorldBatch = m_DecalToWorld[batchCount];
normalToWorldBatch = m_NormalToWorld[batchCount];
}
}
public void CreateDrawData()
{
if (m_NumResults == 0)
return;

AssignCurrentBatches(ref decalToWorldBatch, ref normalToWorldBatch, batchCount);
Vector3 cameraPos = m_CullingGroup.targetCamera.transform.position;
Vector3 cameraPos = instance.CurrentCamera.transform.position;
Matrix4x4 worldToView = LightLoop.WorldToCamera(instance.CurrentCamera);
for (int resultIndex = 0; resultIndex < m_NumResults; resultIndex++)
{
int decalIndex = m_ResultIndices[resultIndex];

if (distanceToDecal < cullDistance)
{
// dbuffer data
// d-buffer data
decalToWorldBatch[instanceCount] = m_CachedDecalToWorld[decalIndex];
normalToWorldBatch[instanceCount] = m_CachedNormalToWorld[decalIndex];
float fadeFactor = Mathf.Clamp((cullDistance - distanceToDecal) / (cullDistance * (1.0f - m_CachedDrawDistances[decalIndex].y)), 0.0f, 1.0f);

// clustered forward data
DecalData decalData = new DecalData();
decalData.worldToDecal = decalToWorldBatch[instanceCount]; // this will be inverted by the light loop code, decal to world is needed there to create bounds
decalData.worldToDecal = decalToWorldBatch[instanceCount].inverse;
GetDecalVolumeDataAndBound(decalToWorldBatch[instanceCount], worldToView);
instanceCount++;
if (instanceCount == kDrawIndexedBatchSize)

}
}
public void BuildDecalDatas()
{
}
public void EndCull()
{
if (m_CullingGroup == null)

else
{
CreateDrawData();
void AssignCurrentBatches(ref Matrix4x4[] decalToWorldBatch, ref Matrix4x4[] normalToWorldBatch, int batchCount)
{
if (m_DecalToWorld.Count == batchCount)
{
decalToWorldBatch = new Matrix4x4[kDrawIndexedBatchSize];
m_DecalToWorld.Add(decalToWorldBatch);
normalToWorldBatch = new Matrix4x4[kDrawIndexedBatchSize];
m_NormalToWorld.Add(normalToWorldBatch);
}
else
{
decalToWorldBatch = m_DecalToWorld[batchCount];
normalToWorldBatch = m_NormalToWorld[batchCount];
}
}
void UpdateTextureCache(CommandBuffer cmd)
{
if ((m_DiffuseTexIndex == -1) && (m_DiffuseTexture != null))

int totalToDraw = m_NumResults;
for (; batchIndex < m_NumResults / kDrawIndexedBatchSize; batchIndex++)
{
m_PropertyBlock.SetMatrixArray(m_NormalToWorldID, m_NormalToWorld[batchIndex]);
m_PropertyBlock.SetMatrixArray(HDShaderIDs._NormalToWorldID, m_NormalToWorld[batchIndex]);
cmd.DrawMeshInstanced(m_DecalMesh, 0, KeyMaterial, 0, m_DecalToWorld[batchIndex], kDrawIndexedBatchSize, m_PropertyBlock);
totalToDraw -= kDrawIndexedBatchSize;
}

m_PropertyBlock.SetMatrixArray(m_NormalToWorldID, m_NormalToWorld[batchIndex]);
m_PropertyBlock.SetMatrixArray(HDShaderIDs._NormalToWorldID, m_NormalToWorld[batchIndex]);
cmd.DrawMeshInstanced(m_DecalMesh, 0, KeyMaterial, 0, m_DecalToWorld[batchIndex], totalToDraw, m_PropertyBlock);
}
}

}
}
public void BeginCull(Camera camera)
public void BeginCull()
pair.Value.BeginCull(camera);
pair.Value.BeginCull();
}
}

public void SetAtlas(CommandBuffer cmd)
{
cmd.SetGlobalTexture(m_DecalAtlasID, TextureAtlas.GetTexCache());
cmd.SetGlobalTexture(HDShaderIDs._DecalAtlasID, TextureAtlas.GetTexCache());
// updates textures, texture atlas indices and blend value
public void UpdateCachedMaterialData(CommandBuffer cmd)
{
foreach (var pair in m_DecalSets)

}
public void InvertDecalDataWorldToDecal()
public void CreateDrawData()
for(int i = 0; i < m_DecalDataList.Count; i++)
{
DecalData decalData = m_DecalDataList[i];
decalData.worldToDecal = decalData.worldToDecal.inverse;
m_DecalDataList[i] = decalData;
}
}
void BuildDecalDatas()
{
m_DecalDataList.Clear();
m_Bounds.Clear();
m_LightVolumes.Clear();
pair.Value.BuildDecalDatas();
pair.Value.CreateDrawData();
}
}
}

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs


// decal system needs to be updated with current camera
if (m_FrameSettings.enableDBuffer)
{
DecalSystem.instance.CurrentCamera = camera;
DecalSystem.instance.BeginCull(camera);
DecalSystem.instance.BeginCull();
ReflectionSystem.PrepareCull(camera, m_ReflectionProbeCullResults);
using (new ProfilingSample(cmd, "CullResults.Cull", CustomSamplerId.CullResultsCull.GetSampler()))

{
m_DbufferManager.vsibleDecalCount = DecalSystem.instance.QueryCullResults();
DecalSystem.instance.EndCull();
DecalSystem.instance.CreateDrawData();
}
renderContext.SetupCameraProperties(camera, m_FrameSettings.enableStereo);

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs


public static readonly int _SrcBlend = Shader.PropertyToID("_SrcBlend");
public static readonly int _DstBlend = Shader.PropertyToID("_DstBlend");
public static readonly int _HTile = Shader.PropertyToID("_HTile");
public static readonly int _DecalHTileTexture = Shader.PropertyToID("_DecalHTileTexture");
public static readonly int _NormalToWorldID = Shader.PropertyToID("_NormalToWorld");
public static readonly int _DecalAtlasID = Shader.PropertyToID("_DecalAtlas");
public static readonly int _DecalHTileTexture = Shader.PropertyToID("_DecalHTileTexture");
public static readonly int _ViewMatrix = Shader.PropertyToID("_ViewMatrix");
public static readonly int _InvViewMatrix = Shader.PropertyToID("_InvViewMatrix");
public static readonly int _ProjMatrix = Shader.PropertyToID("_ProjMatrix");

67
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs


public const int k_MaxEnvLightsOnScreen = 64;
public const int k_MaxShadowOnScreen = 16;
public const int k_MaxCascadeCount = 4; //Should be not less than m_Settings.directionalLightCascadeCount;
static readonly Vector3 k_BoxCullingExtentThreshold = Vector3.one * 0.01f;
public static readonly Vector3 k_BoxCullingExtentThreshold = Vector3.one * 0.01f;
// Static keyword is required here else we get a "DestroyBuffer can only be call in main thread"
static ComputeBuffer s_DirectionalLightDatas = null;

}
}
static Matrix4x4 WorldToCamera(Camera camera)
public static Matrix4x4 WorldToCamera(Camera camera)
{
// camera.worldToCameraMatrix is RHS and Unity's transforms are LHS
// We need to flip it to work with transforms

return true;
}
public void GetDecalVolumeDataAndBound(DecalData decalData, Matrix4x4 worldToView)
{
var bound = new SFiniteLightBound();
var lightVolumeData = new LightVolumeData();
// worldToDecal is actually decalToWorld when it first gets passed in
var influenceX = decalData.worldToDecal.GetColumn(0) * 0.5f;
var influenceY = decalData.worldToDecal.GetColumn(1) * 0.5f;
var influenceZ = decalData.worldToDecal.GetColumn(2) * 0.5f;
var pos = decalData.worldToDecal.GetColumn(3) - influenceY; // decal cube mesh pivot is at 0,0,0, with bottom face at -1 on the y plane
Vector3 influenceExtents = new Vector3();
influenceExtents.x = influenceX.magnitude;
influenceExtents.y = influenceY.magnitude;
influenceExtents.z = influenceZ.magnitude;
// transform to camera space (becomes a left hand coordinate frame in Unity since Determinant(worldToView)<0)
var influenceRightVS = worldToView.MultiplyVector(influenceX / influenceExtents.x);
var influenceUpVS = worldToView.MultiplyVector(influenceY / influenceExtents.y);
var influenceForwardVS = worldToView.MultiplyVector(influenceZ / influenceExtents.z);
var influencePositionVS = worldToView.MultiplyPoint(pos); // place the mesh pivot in the center
lightVolumeData.lightCategory = (uint)LightCategory.Decal;
lightVolumeData.lightVolume = (uint)LightVolumeType.Box;
lightVolumeData.featureFlags = (uint)LightFeatureFlags.Env;
bound.center = influencePositionVS;
bound.boxAxisX = influenceRightVS * influenceExtents.x;
bound.boxAxisY = influenceUpVS * influenceExtents.y;
bound.boxAxisZ = influenceForwardVS * influenceExtents.z;
bound.scaleXY.Set(1.0f, 1.0f);
bound.radius = influenceExtents.magnitude;
// The culling system culls pixels that are further
// than a threshold to the box influence extents.
// So we use an arbitrary threshold here (k_BoxCullingExtentOffset)
lightVolumeData.lightPos = influencePositionVS;
lightVolumeData.lightAxisX = influenceRightVS;
lightVolumeData.lightAxisY = influenceUpVS;
lightVolumeData.lightAxisZ = influenceForwardVS;
lightVolumeData.boxInnerDist = influenceExtents - k_BoxCullingExtentThreshold;
lightVolumeData.boxInvRange.Set(1.0f / k_BoxCullingExtentThreshold.x, 1.0f / k_BoxCullingExtentThreshold.y, 1.0f / k_BoxCullingExtentThreshold.z);
m_lightList.bounds.Add(bound);
m_lightList.lightVolumes.Add(lightVolumeData);
}
public void GetEnvLightVolumeDataAndBound(ProbeWrapper probe, LightVolumeType lightVolumeType, Matrix4x4 worldToView)
{
var bound = new SFiniteLightBound();

// We need to properly reset this here otherwise if we go from 1 light to no visible light we would keep the old reference active.
m_CurrentSunLight = null;
m_CurrentSunLightShadowIndex = -1;
var worldToView = WorldToCamera(camera);
// Note: Light with null intensity/Color are culled by the C++, no need to test it here
if (cullResults.visibleLights.Count != 0 || cullResults.visibleReflectionProbes.Count != 0)

// 2. Go through all lights, convert them to GPU format.
// Create simultaneously data for culling (LigthVolumeData and rendering)
var worldToView = WorldToCamera(camera);
for (int sortIndex = 0; sortIndex < sortCount; ++sortIndex)
{
// In 1. we have already classify and sorted the light, we need to use this sorted order here

}
}
// add decals to the list
foreach(var decalData in DecalSystem.m_DecalDataList)
{
GetDecalVolumeDataAndBound(decalData, worldToView);
}
DecalSystem.instance.InvertDecalDataWorldToDecal();
m_lightList.bounds.AddRange(DecalSystem.m_Bounds);
m_lightList.lightVolumes.AddRange(DecalSystem.m_LightVolumes);
m_lightCount = m_lightList.lights.Count + m_lightList.envLights.Count + DecalSystem.m_DecalDataList.Count;
Debug.Assert(m_lightList.bounds.Count == m_lightCount);
Debug.Assert(m_lightList.lightVolumes.Count == m_lightCount);

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.hlsl


CBUFFER_END
UNITY_INSTANCING_BUFFER_START(Decal)
UNITY_DEFINE_INSTANCED_PROP(float4x4, normalToWorld)
UNITY_DEFINE_INSTANCED_PROP(float4x4, _NormalToWorld)
UNITY_INSTANCING_BUFFER_END(matrix)
RW_TEXTURE2D(float, _DecalHTile); // DXGI_FORMAT_R8_UINT is not supported by Unity

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPassDBuffer.hlsl


clip(1.0 - positionDS); // Clip value above one
DecalSurfaceData surfaceData;
float4x4 decalToWorld = UNITY_ACCESS_INSTANCED_PROP(matrix, normalToWorld);
float4x4 decalToWorld = UNITY_ACCESS_INSTANCED_PROP(matrix, _NormalToWorld);
GetSurfaceData(positionDS.xz, decalToWorld, surfaceData);
// have to do explicit test since compiler behavior is not defined for RW resources and discard instructions

正在加载...
取消
保存