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

150 行
5.4 KiB

using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
public class DecalSystem
{
static DecalSystem m_Instance;
static public DecalSystem instance
{
get
{
if (m_Instance == null)
m_Instance = new DecalSystem();
return m_Instance;
}
}
private Mesh m_DecalMesh = null;
private CullingGroup m_CullingGroup = null;
private const int kDecalBlockSize = 128;
private BoundingSphere[] m_BoundingSpheres = new BoundingSphere[kDecalBlockSize];
private DecalProjectorComponent[] m_Decals = new DecalProjectorComponent[kDecalBlockSize];
private int[] m_ResultIndices = new int[kDecalBlockSize];
private int m_NumResults = 0;
private int m_DecalsCount = 0;
public DecalSystem()
{
}
// update bounding sphere for a single decal
public void UpdateBoundingSphere(DecalProjectorComponent decal)
{
m_BoundingSpheres[decal.CullIndex] = GetDecalProjectBoundingSphere(decal.transform.localToWorldMatrix);
}
public void AddDecal(DecalProjectorComponent decal)
{
if (decal.CullIndex != DecalProjectorComponent.kInvalidIndex) //do not add the same decal more than once
return;
// increase array size if no space left
if(m_DecalsCount == m_Decals.Length)
{
DecalProjectorComponent[] newDecals = new DecalProjectorComponent[m_DecalsCount + kDecalBlockSize];
BoundingSphere[] newSpheres = new BoundingSphere[m_DecalsCount + kDecalBlockSize];
m_ResultIndices = new int[m_DecalsCount + kDecalBlockSize];
m_Decals.CopyTo(newDecals, 0);
m_BoundingSpheres.CopyTo(newSpheres, 0);
m_Decals = newDecals;
m_BoundingSpheres = newSpheres;
}
m_Decals[m_DecalsCount] = decal;
m_Decals[m_DecalsCount].CullIndex = m_DecalsCount;
UpdateBoundingSphere(m_Decals[m_DecalsCount]);
m_DecalsCount++;
}
public void RemoveDecal(DecalProjectorComponent decal)
{
if (decal.CullIndex == DecalProjectorComponent.kInvalidIndex) //do not remove decal that has not been added
return;
int removeAtIndex = decal.CullIndex;
// replace with last decal in the list and update index
m_Decals[removeAtIndex] = m_Decals[m_DecalsCount - 1]; // move the last decal in list
m_Decals[removeAtIndex].CullIndex = removeAtIndex;
m_Decals[m_DecalsCount - 1] = null;
// update the bounding spheres array
m_BoundingSpheres[removeAtIndex] = m_BoundingSpheres[m_DecalsCount - 1];
m_DecalsCount--;
decal.CullIndex = DecalProjectorComponent.kInvalidIndex;
}
public void BeginCull(Camera camera)
{
if (m_CullingGroup != null)
{
Debug.LogError("Begin/EndCull() called out of sequence for decal projectors.");
}
m_NumResults = 0;
m_CullingGroup = new CullingGroup();
m_CullingGroup.targetCamera = camera;
m_CullingGroup.SetBoundingSpheres(m_BoundingSpheres);
m_CullingGroup.SetBoundingSphereCount(m_DecalsCount);
}
public int QueryCullResults()
{
m_NumResults = m_CullingGroup.QueryIndices(true, m_ResultIndices, 0);
return m_NumResults;
}
public void Render(ScriptableRenderContext renderContext, HDCamera camera, CommandBuffer cmd)
{
if (m_DecalMesh == null)
m_DecalMesh = CoreUtils.CreateCubeMesh(new Vector3(-0.5f, -1.0f, -0.5f), new Vector3(0.5f, 0.0f, 0.5f));
for (int resultIndex = 0; resultIndex < m_NumResults; resultIndex++)
{
int decalIndex = m_ResultIndices[resultIndex];
// If no decal material assigned, don't draw it
if (m_Decals[decalIndex].m_Material == null)
continue;
// don't draw decals that do not have textures assigned
if (!m_Decals[decalIndex].m_Material.GetTexture("_BaseColorMap") && !m_Decals[decalIndex].m_Material.GetTexture("_NormalMap") &&
!m_Decals[decalIndex].m_Material.GetTexture("_MaskMap"))
continue;
m_Decals[decalIndex].UpdatePropertyBlock(camera.cameraPos);
cmd.DrawMesh(m_DecalMesh, m_Decals[decalIndex].transform.localToWorldMatrix, m_Decals[decalIndex].m_Material, 0, 0,
m_Decals[decalIndex].GetPropertyBlock());
}
}
public void EndCull()
{
if (m_CullingGroup == null)
{
Debug.LogError("Begin/EndCull() called out of sequence for decal projectors.");
}
else
{
m_CullingGroup.Dispose();
m_CullingGroup = null;
}
}
// Decal are assume to use a CubeMesh with bounds min(-0.5f, -1.0f, -0.5f) max(0.5f, 0.0f, 0.5f)
public BoundingSphere GetDecalProjectBoundingSphere(Matrix4x4 decalToWorld)
{
Vector4 min = new Vector4(-0.5f, -1.0f, -0.5f, 1.0f);
Vector4 max = new Vector4(0.5f, 0.0f, 0.5f, 1.0f);
min = decalToWorld * min;
max = decalToWorld * max;
BoundingSphere res = new BoundingSphere();
res.position = (max + min) / 2;
res.radius = ((Vector3)(max - min)).magnitude / 2;
return res;
}
}
}