ThomagicRenderer/Runtime/ObjectData.cs

267 lines
12 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace Assets.ThoMagic.Renderer
{
public class ObjectData
{
public readonly GameObject GameObject;
public readonly HashSet<int> Owners = new HashSet<int>();
public readonly uint prefabId;
public float[] LodSizes;
public float[] LodTransitions;
public LOD[] LODs;
public Vector4[] lods = new Vector4[8];
public uint[] indirectArgsPerLodOffsets = new uint[8];
public uint[] indirectArgsPerLodCounts = new uint[8];
public uint[] indirectArgsPerLodWithShadowsCounts = new uint[8];
public List<int> indirectArgsPerSubmeshOffsets = new List<int>();
public uint lodCount = 1;
public uint fadeLods = 0;
public uint indirectArgsCount = 1;
public uint count = 0;
public IInstanceRenderSettings Settings;
public List<GraphicsBuffer.IndirectDrawIndexedArgs> indirectDrawIndexedArgs = new List<GraphicsBuffer.IndirectDrawIndexedArgs>();
public DrawGroup[] drawGroups;
public DrawGroup[] drawShadowGroups;
public int contentHashCache;
private bool _isDisposed;
public ObjectData(GameObject gameObject, IInstanceRenderSettings settings)
{
GameObject = gameObject;
Settings = settings;
var lodGroup = GameObject.GetComponent<LODGroup>();
LOD[] lodArray;
if (lodGroup == null)
lodArray = new LOD[1]
{
new LOD(0.0001f, GameObject.GetComponentsInChildren<MeshRenderer>())
};
else
lodArray = lodGroup.GetLODs();
LODs = lodArray;
LodSizes = new float[lodArray.Length];
LodTransitions = new float[lodArray.Length];
lodCount = (uint)lodArray.Length;
if (lodGroup != null && lodGroup.fadeMode == LODFadeMode.CrossFade)
fadeLods = 1;
for (int index = 0; index < lodArray.Length; ++index)
{
LodSizes[index] = CalculateBoundsForRenderers(lodArray[index].renderers);
LodTransitions[index] = lodArray[index].screenRelativeTransitionHeight;
}
if (RendererPool.prefabDataFreeSlot.Count > 0)
{
prefabId = RendererPool.prefabDataFreeSlot.Dequeue();
RendererPool.prefabData[(int)prefabId] = new PrefabData();
}
else
{
prefabId = (uint)RendererPool.prefabData.Count;
RendererPool.prefabData.Add(new PrefabData());
}
RendererPool.rebuildPrefabs = true;
indirectArgsCount = BuildRenderer(indirectDrawIndexedArgs);
}
public void Dispose()
{
if (this._isDisposed)
return;
foreach (var drawGroup in drawGroups)
{
drawGroup?.Dispose();
}
foreach (var drawGroup in drawShadowGroups)
{
drawGroup?.Dispose();
}
this._isDisposed = true;
}
private uint BuildRenderer(List<GraphicsBuffer.IndirectDrawIndexedArgs> indirectDrawIndexedArgs)
{
uint indirectArgsCount = 0;
drawGroups = new DrawGroup[lodCount];
drawShadowGroups = new DrawGroup[lodCount];
for (int index = 0; index < lodCount; ++index)
{
uint indirectArgsPerLodCount = 0;
foreach (var renderer in LODs[index].renderers)
{
if (renderer != null)
{
if (renderer is MeshRenderer)
{
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter != null)
{
var sharedMesh = meshFilter.sharedMesh;
var sharedMaterials = renderer.sharedMaterials;
if (sharedMesh != null && sharedMaterials != null && sharedMaterials.Length == sharedMesh.subMeshCount)
{
if (drawGroups[index] == null)
drawGroups[index] = new DrawGroup(index);
RenderParams renderParams1 = new RenderParams();
renderParams1.layer = renderer.gameObject.layer;
renderParams1.receiveShadows = renderer.receiveShadows;
renderParams1.rendererPriority = renderer.rendererPriority;
renderParams1.renderingLayerMask = renderer.renderingLayerMask;
renderParams1.shadowCastingMode = ShadowCastingMode.Off;
renderParams1.reflectionProbeUsage = renderer.reflectionProbeUsage;
renderParams1.motionVectorMode = renderer.motionVectorGenerationMode;
var count = drawGroups[index].Add(sharedMesh, sharedMaterials, Matrix4x4.identity, //renderer.transform.localToWorldMatrix,
indirectArgsCount, indirectDrawIndexedArgs, in renderParams1);
indirectArgsPerLodCount += count;
}
}
}
else if (renderer is BillboardRenderer billboardRenderer)
{
if (billboardRenderer.billboard != null && billboardRenderer.billboard.material != null)
{
if (drawGroups[index] == null)
drawGroups[index] = new DrawGroup(index);
RenderParams renderParams1 = new RenderParams();
renderParams1.layer = renderer.gameObject.layer;
renderParams1.receiveShadows = renderer.receiveShadows;
renderParams1.rendererPriority = renderer.rendererPriority;
renderParams1.renderingLayerMask = renderer.renderingLayerMask;
renderParams1.shadowCastingMode = ShadowCastingMode.Off;
renderParams1.reflectionProbeUsage = renderer.reflectionProbeUsage;
renderParams1.motionVectorMode = renderer.motionVectorGenerationMode;
var count = drawGroups[index].Add(billboardRenderer.billboard, billboardRenderer.material, renderer.transform.localToWorldMatrix,
indirectArgsCount, indirectDrawIndexedArgs, in renderParams1);
indirectArgsPerLodCount += count;
}
}
}
}
indirectArgsPerLodCounts[index] = indirectArgsPerLodCount;
uint indirectArgsPerLodCountShadowOffset = indirectArgsPerLodCount;
foreach (var renderer in LODs[index].renderers)
{
if (renderer != null)
{
if (renderer is MeshRenderer)
{
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter != null)
{
var sharedMesh = meshFilter.sharedMesh;
var sharedMaterials = renderer.sharedMaterials;
if (sharedMesh != null && sharedMaterials != null && sharedMaterials.Length == sharedMesh.subMeshCount)
{
if (renderer.shadowCastingMode > 0)
{
if (drawShadowGroups[index] == null)
drawShadowGroups[index] = new DrawGroup(index);
var renderParams1 = new RenderParams();
renderParams1.layer = renderer.gameObject.layer;
renderParams1.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
renderParams1.renderingLayerMask = renderer.renderingLayerMask;
renderParams1.rendererPriority = renderer.rendererPriority;
indirectArgsPerLodCount += drawShadowGroups[index].Add(sharedMesh, sharedMaterials, Matrix4x4.identity, //renderer.transform.localToWorldMatrix,
indirectArgsPerLodCountShadowOffset + indirectArgsCount, indirectDrawIndexedArgs, in renderParams1);
}
else
{
//indirectArgsPerLodCount += (uint)sharedMesh.subMeshCount;
}
}
}
}
else if (renderer is BillboardRenderer billboardRenderer)
{
if (renderer.shadowCastingMode > 0)
{
if (billboardRenderer.billboard != null && billboardRenderer.billboard.material != null)
{
if (drawShadowGroups[index] == null)
drawShadowGroups[index] = new DrawGroup(index);
var renderParams1 = new RenderParams();
renderParams1.layer = renderer.gameObject.layer;
renderParams1.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
renderParams1.renderingLayerMask = renderer.renderingLayerMask;
renderParams1.rendererPriority = renderer.rendererPriority;
indirectArgsPerLodCount += drawShadowGroups[index].Add(billboardRenderer.billboard, billboardRenderer.material, renderer.transform.localToWorldMatrix,
indirectArgsPerLodCountShadowOffset + indirectArgsCount, indirectDrawIndexedArgs, in renderParams1);
}
else
{
//indirectArgsPerLodCount += 1;
}
}
}
}
}
indirectArgsPerLodWithShadowsCounts[index] = indirectArgsPerLodCount;
indirectArgsCount += indirectArgsPerLodCount;
}
return indirectArgsCount;
}
private static float CalculateBoundsForRenderers(UnityEngine.Renderer[] renderers)
{
Bounds bounds = new Bounds();
bool first = true;
foreach (var renderer in renderers)
{
if (renderer != null)
{
if (first)
{
bounds = renderer.bounds;
first = false;
}
else
bounds.Encapsulate(renderer.bounds);
}
}
return Mathf.Max(Mathf.Max(bounds.size.x, bounds.size.y), bounds.size.z);
}
public override int GetHashCode()
{
return GameObject.GetHashCode();
}
}
}