浏览代码

Merge pull request #808 from Unity-Technologies/prototype/decals_drawinstance

Prototype/decals drawinstance
/main
GitHub 7 年前
当前提交
1d07f3a6
共有 9 个文件被更改,包括 286 次插入139 次删除
  1. 54
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalProjectorComponent.cs
  2. 299
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs
  3. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Decal/DecalUI.cs
  4. 7
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.shader
  5. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalData.hlsl
  6. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/ShaderPass/DecalSharePass.hlsl
  7. 50
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPassDBuffer.hlsl
  8. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/VertMesh.hlsl
  9. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderVariables.hlsl

54
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalProjectorComponent.cs


private static readonly int m_WorldToDecal = Shader.PropertyToID("_WorldToDecal");
private static readonly int m_DecalToWorldR = Shader.PropertyToID("_DecalToWorldR");
public Material m_Material;
private MaterialPropertyBlock m_PropertyBlock;
public Material m_Material = null;
private Material m_OldMaterial = null;
// normal space __x to decal space __x
// |\ |\
// y z z y
//
private static Matrix4x4 m_NormalToDecal = Matrix4x4.Scale(new Vector3(1.0f, 1.0f, -1.0f)) * Matrix4x4.Rotate(Quaternion.AngleAxis(-90.0f, new Vector3(1, 0, 0)));
public int CullIndex
{
get

public void Start()
{
m_PropertyBlock = new MaterialPropertyBlock();
DecalSystem.instance.AddDecal(this);
}

public void OnValidate()
{
BoundingSphere sphere = DecalSystem.instance.GetDecalProjectBoundingSphere(transform.localToWorldMatrix);
// handle material changes
if (m_OldMaterial != m_Material)
{
Material tempMaterial = m_Material;
m_Material = m_OldMaterial;
if(m_Material != null)
DecalSystem.instance.RemoveDecal(this);
m_Material = tempMaterial;
DecalSystem.instance.AddDecal(this);
m_OldMaterial = m_Material;
}
if (m_Material != null)
{
Shader shader = m_Material.shader;

DecalSystem.instance.UpdateBoundingSphere(this);
}
public void UpdatePropertyBlock(Vector3 cameraPos)
public bool IsValid()
Matrix4x4 CRWStoAWS = new Matrix4x4();
if (ShaderConfig.s_CameraRelativeRendering == 1)
{
CRWStoAWS = Matrix4x4.Translate(cameraPos);
}
else
{
CRWStoAWS = Matrix4x4.identity;
}
if (m_Material == null)
return false;
Matrix4x4 final = transform.localToWorldMatrix;
Matrix4x4 decalToWorldR = Matrix4x4.Rotate(transform.rotation) * m_NormalToDecal;
Matrix4x4 worldToDecal = Matrix4x4.Translate(new Vector3(0.5f, 0.0f, 0.5f)) * Matrix4x4.Scale(new Vector3(1.0f, -1.0f, 1.0f)) * final.inverse;
if (m_PropertyBlock == null)
{
m_PropertyBlock = new MaterialPropertyBlock();
}
m_PropertyBlock.SetMatrix(m_DecalToWorldR, decalToWorldR);
m_PropertyBlock.SetMatrix(m_WorldToDecal, worldToDecal * CRWStoAWS);
}
if (!m_Material.GetTexture("_BaseColorMap") && !m_Material.GetTexture("_NormalMap") &&
!m_Material.GetTexture("_MaskMap"))
return false;
public MaterialPropertyBlock GetPropertyBlock()
{
return m_PropertyBlock;
return true;
}
}
}

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


}
}
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;
private const int kDecalBlockSize = 128;
// to work on Vulkan Mobile?
// Core\CoreRP\ShaderLibrary\UnityInstancing.hlsl
// #if defined(SHADER_API_VULKAN) && defined(SHADER_API_MOBILE)
// #define UNITY_INSTANCED_ARRAY_SIZE 250
private const int kDrawIndexedBatchSize = 250;
public DecalSystem()
// cube mesh bounds for decal
static Vector4 kMin = new Vector4(-0.5f, -1.0f, -0.5f, 1.0f);
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];
private Dictionary<int, DecalSet> m_DecalSets = new Dictionary<int, DecalSet>();
private class DecalSet
}
private BoundingSphere GetDecalProjectBoundingSphere(Matrix4x4 decalToWorld)
{
Vector4 min = new Vector4();
Vector4 max = new Vector4();
min = decalToWorld * kMin;
max = decalToWorld * kMax;
BoundingSphere res = new BoundingSphere();
res.position = (max + min) / 2;
res.radius = ((Vector3)(max - min)).magnitude / 2;
return res;
}
public void UpdateBoundingSphere(DecalProjectorComponent decal)
{
m_CachedTransforms[decal.CullIndex] = decal.transform.localToWorldMatrix;
m_BoundingSpheres[decal.CullIndex] = GetDecalProjectBoundingSphere(m_CachedTransforms[decal.CullIndex]);
}
public void AddDecal(DecalProjectorComponent decal)
{
// 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];
Matrix4x4[] newCachedTransforms = new Matrix4x4[m_DecalsCount + kDecalBlockSize];
m_ResultIndices = new int[m_DecalsCount + kDecalBlockSize];
m_Decals.CopyTo(newDecals, 0);
m_BoundingSpheres.CopyTo(newSpheres, 0);
m_CachedTransforms.CopyTo(newCachedTransforms, 0);
m_Decals = newDecals;
m_BoundingSpheres = newSpheres;
m_CachedTransforms = newCachedTransforms;
}
m_Decals[m_DecalsCount] = decal;
m_Decals[m_DecalsCount].CullIndex = m_DecalsCount;
UpdateBoundingSphere(m_Decals[m_DecalsCount]);
m_DecalsCount++;
}
public void RemoveDecal(DecalProjectorComponent decal)
{
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_CachedTransforms[removeAtIndex] = m_CachedTransforms[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 EndCull()
{
if (m_CullingGroup == null)
{
Debug.LogError("Begin/EndCull() called out of sequence for decal projectors.");
}
else
{
m_CullingGroup.Dispose();
m_CullingGroup = null;
}
}
public void Render(ScriptableRenderContext renderContext, HDCamera camera, CommandBuffer cmd)
{
int instanceCount = 0;
for (int resultIndex = 0; resultIndex < m_NumResults; resultIndex++)
{
int decalIndex = m_ResultIndices[resultIndex];
m_InstanceMatrices[instanceCount] = m_CachedTransforms[decalIndex];
instanceCount++;
if (instanceCount == kDrawIndexedBatchSize)
{
cmd.DrawMeshInstanced(m_DecalMesh, 0, m_Decals[0].m_Material, 0, m_InstanceMatrices, kDrawIndexedBatchSize);
instanceCount = 0;
}
}
if (instanceCount > 0)
{
cmd.DrawMeshInstanced(m_DecalMesh, 0, m_Decals[0].m_Material, 0, m_InstanceMatrices, instanceCount);
}
}
public Material KeyMaterial
{
get
{
return this.m_Material;
}
set
{
this.m_Material = value;
}
}
public int Count
{
get
{
return this.m_DecalsCount;
}
}
// update bounding sphere for a single decal
public void UpdateBoundingSphere(DecalProjectorComponent decal)
{
m_BoundingSpheres[decal.CullIndex] = GetDecalProjectBoundingSphere(decal.transform.localToWorldMatrix);
private CullingGroup m_CullingGroup = null;
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;
private Matrix4x4[] m_CachedTransforms = new Matrix4x4[kDecalBlockSize];
private Material m_Material;
// increase array size if no space left
if(m_DecalsCount == m_Decals.Length)
if(!decal.IsValid())
return;
DecalSet decalSet = null;
int key = decal.m_Material.GetInstanceID();
if (!m_DecalSets.TryGetValue(key, out decalSet))
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++;
decalSet = new DecalSet();
decalSet.KeyMaterial = decal.m_Material;
m_DecalSets.Add(key, decalSet);
}
decalSet.AddDecal(decal);
if (decal.CullIndex == DecalProjectorComponent.kInvalidIndex) //do not remove decal that has not been added
if (decal.CullIndex == DecalProjectorComponent.kInvalidIndex) // check if we have this decal
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;
DecalSet decalSet = null;
int key = decal.m_Material.GetInstanceID();
if (m_DecalSets.TryGetValue(key, out decalSet))
{
decalSet.RemoveDecal(decal);
if (decalSet.Count == 0)
{
m_DecalSets.Remove(key);
}
}
}
// update the bounding spheres array
m_BoundingSpheres[removeAtIndex] = m_BoundingSpheres[m_DecalsCount - 1];
m_DecalsCount--;
decal.CullIndex = DecalProjectorComponent.kInvalidIndex;
public void UpdateBoundingSphere(DecalProjectorComponent decal)
{
if (decal.CullIndex == DecalProjectorComponent.kInvalidIndex) // check if we have this decal
return;
DecalSet decalSet = null;
int key = decal.m_Material.GetInstanceID();
if (m_DecalSets.TryGetValue(key, out decalSet))
{
decalSet.UpdateBoundingSphere(decal);
}
if (m_CullingGroup != null)
foreach (var pair in m_DecalSets)
Debug.LogError("Begin/EndCull() called out of sequence for decal projectors.");
pair.Value.BeginCull(camera);
m_NumResults = 0;
m_CullingGroup = new CullingGroup();
m_CullingGroup.targetCamera = camera;
m_CullingGroup.SetBoundingSpheres(m_BoundingSpheres);
m_CullingGroup.SetBoundingSphereCount(m_DecalsCount);
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 totalVisibleDecals = 0;
foreach (var pair in m_DecalSets)
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());
totalVisibleDecals += pair.Value.QueryCullResults();
}
return totalVisibleDecals;
}
if (m_CullingGroup == null)
foreach (var pair in m_DecalSets)
Debug.LogError("Begin/EndCull() called out of sequence for decal projectors.");
}
else
{
m_CullingGroup.Dispose();
m_CullingGroup = null;
pair.Value.EndCull();
// 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)
public void Render(ScriptableRenderContext renderContext, HDCamera camera, CommandBuffer cmd)
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;
if (m_DecalMesh == null)
m_DecalMesh = CoreUtils.CreateCubeMesh(kMin, kMax);
foreach (var pair in m_DecalSets)
{
pair.Value.Render(renderContext, camera, cmd);
}
}
}
}

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Decal/DecalUI.cs


normalMap = FindProperty(kNormalMap, props);
maskMap = FindProperty(kMaskMap, props);
decalBlend = FindProperty(kDecalBlend, props);
// always instanced
SerializedProperty instancing = m_MaterialEditor.serializedObject.FindProperty("m_EnableInstancingVariants");
instancing.boolValue = true;
}

m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, normalMap);
m_MaterialEditor.TexturePropertySingleLine(Styles.maskMapText, maskMap);
m_MaterialEditor.ShaderProperty(decalBlend, Styles.decalBlendText);
EditorGUI.indentLevel--;
}

7
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.shader


#pragma shader_feature _NORMALMAP
#pragma shader_feature _MASKMAP
#pragma multi_compile_instancing
#define UNITY_MATERIAL_DECAL // do we need this now that Material.hlsl is not getting included?
#define UNITY_MATERIAL_DECAL
//-------------------------------------------------------------------------------------
// Include
//-------------------------------------------------------------------------------------

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalData.hlsl


#include "CoreRP/ShaderLibrary/Packing.hlsl"
#include "CoreRP/ShaderLibrary/Sampling/SampleUVMapping.hlsl"
void GetSurfaceData(float2 texCoordDS, out DecalSurfaceData surfaceData)
void GetSurfaceData(float2 texCoordDS, float3x3 decalToWorld, out DecalSurfaceData surfaceData)
{
surfaceData.baseColor = float4(0,0,0,0);
surfaceData.normalWS = float4(0,0,0,0);

ZERO_INITIALIZE(UVMapping, texCoord);
texCoord.uv = texCoordDS.xy;
#if _NORMALMAP
surfaceData.normalWS.xyz = mul((float3x3)_DecalToWorldR, SAMPLE_UVMAPPING_NORMALMAP(_NormalMap, sampler_NormalMap, texCoord, 1)) * 0.5f + 0.5f;
surfaceData.normalWS.xyz = mul(decalToWorld, SAMPLE_UVMAPPING_NORMALMAP(_NormalMap, sampler_NormalMap, texCoord, 1)) * 0.5f + 0.5f;
surfaceData.normalWS.w = totalBlend;
#endif
#if _MASKMAP

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/ShaderPass/DecalSharePass.hlsl


#error Undefine_SHADERPASS
#endif
// need 3 x float3 interpolators...
#define VARYINGS_NEED_POSITION_WS
#define VARYINGS_NEED_TANGENT_TO_WORLD
// This include will define the various Attributes/Varyings structure
#include "../../ShaderPass/VaryingMesh.hlsl"

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


#include "VertMesh.hlsl"
float3 RemoveScale(float3 val)
{
return normalize(val / length(val));
}
VaryingsMeshType Transform(AttributesMesh input)
{
VaryingsMeshType output;
UNITY_SETUP_INSTANCE_ID(input)
UNITY_TRANSFER_INSTANCE_ID(input, output);
float3 positionWS = TransformObjectToWorld(input.positionOS);
positionWS = GetCameraRelativePositionWS(positionWS);
output.positionCS = TransformWorldToHClip(positionWS);
float3x3 decalRotation;
decalRotation[0] = RemoveScale(float3(UNITY_MATRIX_M[0][0], UNITY_MATRIX_M[0][1], UNITY_MATRIX_M[0][2]));
decalRotation[2] = RemoveScale(float3(UNITY_MATRIX_M[1][0], UNITY_MATRIX_M[1][1], UNITY_MATRIX_M[1][2]));
decalRotation[1] = RemoveScale(float3(UNITY_MATRIX_M[2][0], UNITY_MATRIX_M[2][1], UNITY_MATRIX_M[2][2]));
decalRotation = transpose(decalRotation);
output.positionWS = decalRotation[0];
output.normalWS = decalRotation[1];
output.tangentWS = float4(decalRotation[2], 0);
return output;
}
varyingsType.vmesh = VertMesh(inputMesh);
varyingsType.vmesh = Transform(inputMesh);
PositionInputs posInput = GetPositionInput(packedInput.vmesh.positionCS, _ScreenSize.zw);
FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
PositionInputs posInput = GetPositionInput(input.positionSS.xy, _ScreenSize.zw);
float3 positionWS = posInput.positionWS;
float3 positionDS = mul(_WorldToDecal, float4(positionWS, 1.0f)).xyz;
float3 positionWS = GetAbsolutePositionWS(posInput.positionWS);
float3 positionDS = mul(UNITY_MATRIX_I_M, float4(positionWS, 1.0f)).xyz;
positionDS = positionDS * float3(1.0f, -1.0f, 1.0f) + float3(0.5f, 0.0f, 0.5f);
GetSurfaceData(positionDS.xz, surfaceData);
float3x3 decalToWorld;
// using the interpolators directly, because UnpackVaryingsMeshToFragInputs does some tangent space manipulations
decalToWorld[0] = packedInput.vmesh.interpolators0;
decalToWorld[1] = packedInput.vmesh.interpolators1;
decalToWorld[2] = packedInput.vmesh.interpolators2.xyz;
GetSurfaceData(positionDS.xz, decalToWorld, surfaceData);
ENCODE_INTO_DBUFFER(surfaceData, outDBuffer);
}

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/VertMesh.hlsl


float3 normalWS = float3(0.0, 0.0, 0.0); // We need this case to be able to compile ApplyVertexModification that doesn't use normal.
#endif
float4 tangentWS = float4(0.0, 0.0, 0.0, 0.0);
float4 tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
#endif
// TODO: deal with camera center rendering and instancing (This is the reason why we always perform two steps transform to clip space + instancing matrix)

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderVariables.hlsl


#endif
#include "CoreRP/ShaderLibrary/UnityInstancing.hlsl"
#include "ShaderVariablesFunctions.hlsl"
#endif // UNITY_SHADER_VARIABLES_INCLUDED
正在加载...
取消
保存