|
|
|
|
/******************************************************************************/
|
|
|
|
|
/*
|
|
|
|
|
Project - MudBun
|
|
|
|
|
Publisher - Long Bunny Labs
|
|
|
|
|
http://LongBunnyLabs.com
|
|
|
|
|
Author - Ming-Lun "Allen" Chou
|
|
|
|
|
http://AllenChou.net
|
|
|
|
|
*/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.Rendering;
|
|
|
|
|
|
|
|
|
|
namespace MudBun
|
|
|
|
|
{
|
|
|
|
|
[ExecuteInEditMode]
|
|
|
|
|
public class MudLockedMeshRenderer : MonoBehaviour, ISerializationCallbackReceiver
|
|
|
|
|
{
|
|
|
|
|
private class ComputeBufferCache
|
|
|
|
|
{
|
|
|
|
|
public int RefCount;
|
|
|
|
|
|
|
|
|
|
public int [] IndirectDrawArgsData;
|
|
|
|
|
public GenPoint [] GenPointsData;
|
|
|
|
|
|
|
|
|
|
public ComputeBuffer IndirectDrawArgsBuffer;
|
|
|
|
|
public ComputeBuffer GenPointsBuffer;
|
|
|
|
|
|
|
|
|
|
public void Release()
|
|
|
|
|
{
|
|
|
|
|
IndirectDrawArgsData = null;
|
|
|
|
|
GenPointsData = null;
|
|
|
|
|
|
|
|
|
|
IndirectDrawArgsBuffer.Release();
|
|
|
|
|
GenPointsBuffer.Release();
|
|
|
|
|
IndirectDrawArgsBuffer = null;
|
|
|
|
|
GenPointsBuffer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Dictionary<int, ComputeBufferCache> s_bufferCachePool = new Dictionary<int, ComputeBufferCache>();
|
|
|
|
|
|
|
|
|
|
[SerializeField] [HideInInspector] private int m_numVerts = 0;
|
|
|
|
|
[SerializeField] [HideInInspector] private int [] m_indirectDrawArgsData;
|
|
|
|
|
[SerializeField] [HideInInspector] private GenPoint [] m_aGenPointData;
|
|
|
|
|
[SerializeField] [HideInInspector] private Aabb m_renderBoundsRs;
|
|
|
|
|
public Material RenderMaterial;
|
|
|
|
|
private Material m_materialCloned;
|
|
|
|
|
private Material m_materialUsed;
|
|
|
|
|
|
|
|
|
|
public Color MasterColor;
|
|
|
|
|
public Color MasterEmission;
|
|
|
|
|
public float MasterMetallic;
|
|
|
|
|
public float MasterSmoothness;
|
|
|
|
|
|
|
|
|
|
[SerializeField] [HideInInspector] private MudRendererBase.RenderModeEnum m_renderMode = MudRendererBase.RenderModeEnum.SmoothMesh;
|
|
|
|
|
[SerializeField] [HideInInspector] private float m_voxelDensity = 1.0f;
|
|
|
|
|
[ConditionalField("m_renderMode",
|
|
|
|
|
MudRendererBase.RenderModeEnum.CircleSplats,
|
|
|
|
|
MudRendererBase.RenderModeEnum.QuadSplats,
|
|
|
|
|
Min = 0.0f, Max = 5.0f)]
|
|
|
|
|
public float SplatSize = 1.0f;
|
|
|
|
|
[ConditionalField("m_renderMode",
|
|
|
|
|
MudRendererBase.RenderModeEnum.CircleSplats,
|
|
|
|
|
MudRendererBase.RenderModeEnum.QuadSplats,
|
|
|
|
|
Min = 0.0f, Max = 360.0f)]
|
|
|
|
|
public float SplatRotation = 0.0f;
|
|
|
|
|
[ConditionalField("m_renderMode",
|
|
|
|
|
MudRendererBase.RenderModeEnum.CircleSplats,
|
|
|
|
|
MudRendererBase.RenderModeEnum.QuadSplats,
|
|
|
|
|
Min = 0.1f, Max = 10.0f)]
|
|
|
|
|
public float SplatRotationNoisiness = 1.0f;
|
|
|
|
|
[ConditionalField("m_renderMode",
|
|
|
|
|
MudRendererBase.RenderModeEnum.CircleSplats,
|
|
|
|
|
MudRendererBase.RenderModeEnum.QuadSplats,
|
|
|
|
|
Min = 0.0f, Max = 1.0f)]
|
|
|
|
|
public float SplatCameraFacing = 1.0f;
|
|
|
|
|
|
|
|
|
|
public ShadowCastingMode CastShadows = ShadowCastingMode.On;
|
|
|
|
|
public bool ReceiveShadows = true;
|
|
|
|
|
|
|
|
|
|
private ComputeBuffer m_indirectDrawArgsBuffer;
|
|
|
|
|
private ComputeBuffer m_genPointsBuffer;
|
|
|
|
|
private MaterialPropertyBlock m_renderMaterialProps;
|
|
|
|
|
|
|
|
|
|
[SerializeField] [HideInInspector] private int m_hash;
|
|
|
|
|
|
|
|
|
|
public void Config
|
|
|
|
|
(
|
|
|
|
|
ComputeBuffer drawArgsBuffer,
|
|
|
|
|
ComputeBuffer getPointsBuffer,
|
|
|
|
|
MudRendererBase renderer
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
m_indirectDrawArgsData = new int[5];
|
|
|
|
|
drawArgsBuffer.GetData(m_indirectDrawArgsData);
|
|
|
|
|
|
|
|
|
|
m_numVerts = m_indirectDrawArgsData[0];
|
|
|
|
|
m_aGenPointData = new GenPoint[m_numVerts];
|
|
|
|
|
getPointsBuffer.GetData(m_aGenPointData);
|
|
|
|
|
|
|
|
|
|
RenderMaterial = renderer.RenderMaterial;
|
|
|
|
|
MasterColor = renderer.MasterColor;
|
|
|
|
|
MasterEmission = renderer.MasterEmission;
|
|
|
|
|
MasterMetallic = renderer.MasterMetallic;
|
|
|
|
|
MasterSmoothness = renderer.MasterSmoothness;
|
|
|
|
|
m_renderBoundsRs = renderer.RenderBoundsRs;
|
|
|
|
|
m_renderMode = renderer.RenderMode;
|
|
|
|
|
m_voxelDensity = renderer.VoxelDensity;
|
|
|
|
|
SplatSize = renderer.SplatSize;
|
|
|
|
|
SplatRotation = renderer.SplatRotationJitter;
|
|
|
|
|
SplatCameraFacing = renderer.SplatCameraFacing;
|
|
|
|
|
|
|
|
|
|
CastShadows = renderer.CastShadows;
|
|
|
|
|
ReceiveShadows = renderer.ReceiveShadows;
|
|
|
|
|
|
|
|
|
|
m_hash = Codec.Hash(GetHashCode());
|
|
|
|
|
m_hash = Codec.HashConcat(m_hash, DateTime.Now.Ticks);
|
|
|
|
|
|
|
|
|
|
Validate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void OnBeforeSerialize()
|
|
|
|
|
{
|
|
|
|
|
ComputeBufferCache bufferCache;
|
|
|
|
|
if (s_bufferCachePool.TryGetValue(m_hash, out bufferCache))
|
|
|
|
|
{
|
|
|
|
|
m_indirectDrawArgsData = bufferCache.IndirectDrawArgsData;
|
|
|
|
|
m_aGenPointData = bufferCache.GenPointsData;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void OnAfterDeserialize() { }
|
|
|
|
|
|
|
|
|
|
private void OnEnable()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnDisable()
|
|
|
|
|
{
|
|
|
|
|
m_indirectDrawArgsBuffer = null;
|
|
|
|
|
m_genPointsBuffer = null;
|
|
|
|
|
|
|
|
|
|
ComputeBufferCache bufferCache = null;
|
|
|
|
|
if (s_bufferCachePool.TryGetValue(m_hash, out bufferCache))
|
|
|
|
|
{
|
|
|
|
|
--bufferCache.RefCount;
|
|
|
|
|
if (bufferCache.RefCount == 0)
|
|
|
|
|
{
|
|
|
|
|
bufferCache.Release();
|
|
|
|
|
s_bufferCachePool.Remove(m_hash);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Validate()
|
|
|
|
|
{
|
|
|
|
|
if (m_indirectDrawArgsBuffer == null
|
|
|
|
|
|| m_genPointsBuffer == null)
|
|
|
|
|
{
|
|
|
|
|
ComputeBufferCache bufferCache = null;
|
|
|
|
|
if (s_bufferCachePool.TryGetValue(m_hash, out bufferCache))
|
|
|
|
|
{
|
|
|
|
|
m_indirectDrawArgsBuffer = bufferCache.IndirectDrawArgsBuffer;
|
|
|
|
|
m_genPointsBuffer = bufferCache.GenPointsBuffer;
|
|
|
|
|
|
|
|
|
|
m_indirectDrawArgsData = null;
|
|
|
|
|
m_aGenPointData = null;
|
|
|
|
|
|
|
|
|
|
++bufferCache.RefCount;
|
|
|
|
|
}
|
|
|
|
|
else if (m_indirectDrawArgsData != null
|
|
|
|
|
&& m_aGenPointData != null)
|
|
|
|
|
{
|
|
|
|
|
m_indirectDrawArgsBuffer = new ComputeBuffer(5, sizeof(int), ComputeBufferType.IndirectArguments);
|
|
|
|
|
m_indirectDrawArgsBuffer.SetData(m_indirectDrawArgsData);
|
|
|
|
|
|
|
|
|
|
m_genPointsBuffer = new ComputeBuffer(m_numVerts, GenPoint.Stride);
|
|
|
|
|
m_genPointsBuffer.SetData(m_aGenPointData);
|
|
|
|
|
|
|
|
|
|
s_bufferCachePool.Add
|
|
|
|
|
(
|
|
|
|
|
m_hash,
|
|
|
|
|
new ComputeBufferCache()
|
|
|
|
|
{
|
|
|
|
|
RefCount = 1,
|
|
|
|
|
IndirectDrawArgsData = m_indirectDrawArgsData,
|
|
|
|
|
GenPointsData = m_aGenPointData,
|
|
|
|
|
IndirectDrawArgsBuffer = m_indirectDrawArgsBuffer,
|
|
|
|
|
GenPointsBuffer = m_genPointsBuffer
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
m_indirectDrawArgsData = null;
|
|
|
|
|
m_aGenPointData = null;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Assert.Warn("Null constant buffers and no data to initialize from.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_renderMaterialProps == null)
|
|
|
|
|
{
|
|
|
|
|
m_renderMaterialProps = new MaterialPropertyBlock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LateUpdate()
|
|
|
|
|
{
|
|
|
|
|
Validate();
|
|
|
|
|
Render();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void BindRenderResources()
|
|
|
|
|
{
|
|
|
|
|
MudRendererBase.ValidateShaderConstantId();
|
|
|
|
|
|
|
|
|
|
m_renderMaterialProps.SetBuffer(MudRendererBase.Const.GenPoints, m_genPointsBuffer);
|
|
|
|
|
|
|
|
|
|
m_renderMaterialProps.SetColor(MudRendererBase.Const.MasterColor, MasterColor);
|
|
|
|
|
m_renderMaterialProps.SetColor(MudRendererBase.Const.MasterEmission, MasterEmission);
|
|
|
|
|
m_renderMaterialProps.SetFloat(MudRendererBase.Const.MasterMetallic, MasterMetallic);
|
|
|
|
|
m_renderMaterialProps.SetFloat(MudRendererBase.Const.MasterSmoothness, MasterSmoothness);
|
|
|
|
|
|
|
|
|
|
m_renderMaterialProps.SetFloat(MudRendererBase.Const.SplatSize, SplatSize * (1.5f / m_voxelDensity));
|
|
|
|
|
m_renderMaterialProps.SetFloat(MudRendererBase.Const.SplatRotationJitter, SplatRotation * MathUtil.Deg2Rad);
|
|
|
|
|
m_renderMaterialProps.SetFloat(MudRendererBase.Const.SplatJitterNoisiness, SplatRotationNoisiness);
|
|
|
|
|
m_renderMaterialProps.SetFloat(MudRendererBase.Const.SplatCameraFacing, SplatCameraFacing);
|
|
|
|
|
m_renderMaterialProps.SetMatrix(MudRendererBase.Const.LocalToWorld, transform.localToWorldMatrix);
|
|
|
|
|
m_renderMaterialProps.SetMatrix(MudRendererBase.Const.LocalToWorldIt, transform.localToWorldMatrix.inverse.transpose);
|
|
|
|
|
m_renderMaterialProps.SetVector(MudRendererBase.Const.LocalToWorldScale, transform.localScale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Render()
|
|
|
|
|
{
|
|
|
|
|
if (m_indirectDrawArgsBuffer == null
|
|
|
|
|
|| m_genPointsBuffer == null
|
|
|
|
|
|| RenderMaterial == null
|
|
|
|
|
|| m_renderBoundsRs.IsEmpty
|
|
|
|
|
|| RenderMaterial == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
BindRenderResources();
|
|
|
|
|
|
|
|
|
|
var renderBounds = m_renderBoundsRs;
|
|
|
|
|
renderBounds.Transform(transform);
|
|
|
|
|
|
|
|
|
|
if (m_materialCloned != RenderMaterial)
|
|
|
|
|
{
|
|
|
|
|
m_materialUsed = new Material(RenderMaterial);
|
|
|
|
|
m_materialCloned = RenderMaterial;
|
|
|
|
|
}
|
|
|
|
|
m_materialUsed.CopyPropertiesFromMaterial(m_materialCloned);
|
|
|
|
|
|
|
|
|
|
if (ReceiveShadows)
|
|
|
|
|
RenderMaterial.EnableKeyword("MUDBUN_RECEIVE_SHADOWS");
|
|
|
|
|
else
|
|
|
|
|
RenderMaterial.DisableKeyword("MUDBUN_RECEIVE_SHADOWS");
|
|
|
|
|
|
|
|
|
|
Graphics.DrawProceduralIndirect
|
|
|
|
|
(
|
|
|
|
|
RenderMaterial,
|
|
|
|
|
new Bounds(renderBounds.Center, renderBounds.Size),
|
|
|
|
|
MeshTopology.Triangles,
|
|
|
|
|
m_indirectDrawArgsBuffer,
|
|
|
|
|
0,
|
|
|
|
|
null,
|
|
|
|
|
m_renderMaterialProps,
|
|
|
|
|
CastShadows,
|
|
|
|
|
ReceiveShadows,
|
|
|
|
|
gameObject.layer
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|