using System; using System.Collections.Generic; using UnityEngine; namespace Assets.ThoMagic.Renderer { public class DrawCall { public readonly Mesh Mesh; public readonly Material[] Materials; public readonly RenderParams[] RenderParams; private readonly Matrix4x4 _localToWorldMatrix; private readonly uint baseIndirectArgsIndex; private readonly int lodNr; public DrawCall( int lodNr, Mesh mesh, Material[] materials, Matrix4x4 localToWorldMatrix, uint baseIndirectArgsIndex, List indirectDrawIndexedArgs, in RenderParams renderParams) { if (mesh == null) throw new ArgumentNullException(nameof(mesh)); if (materials == null) throw new ArgumentNullException(nameof(materials)); if (materials.Length != mesh.subMeshCount) throw new IndexOutOfRangeException(nameof(materials)); this.baseIndirectArgsIndex = baseIndirectArgsIndex; _localToWorldMatrix = localToWorldMatrix; Mesh = mesh; Materials = materials; RenderParams = new RenderParams[mesh.subMeshCount]; this.lodNr = lodNr; for (int index = 0; index < mesh.subMeshCount; ++index) { RenderParams[index] = renderParams; RenderParams[index].material = materials[index]; RenderParams[index].matProps = new MaterialPropertyBlock(); RenderParams[index].matProps.SetMatrix("trInstanceMatrix", _localToWorldMatrix); RenderParams[index].matProps.SetInteger("trLodNr", lodNr + 1); RenderParams[index].worldBounds = new Bounds(Vector3.zero, 1000f * Vector3.one); indirectDrawIndexedArgs.Add(new GraphicsBuffer.IndirectDrawIndexedArgs { indexCountPerInstance = mesh.GetIndexCount(index), baseVertexIndex = mesh.GetBaseVertex(index), startIndex = mesh.GetIndexStart(index), startInstance = 0, instanceCount = 0 }); } } public virtual void SetInstances(ComputeBuffer instances, ComputeBuffer visibleIndexBuffer, ComputeBuffer metaBuffer) { for (int index = 0; index < this.RenderParams.Length; ++index) { RenderParams[index].matProps.SetBuffer("trInstances", instances); RenderParams[index].matProps.SetBuffer("trPerCamVisibleIndexesBuffer", visibleIndexBuffer); RenderParams[index].matProps.SetBuffer("trPerCamMeta", metaBuffer); } } public virtual void Draw(Camera camera, ObjectData obj, GraphicsBuffer indirectDrawIndexedArgs) { if (Materials == null) throw new ObjectDisposedException("Materials"); if (Mesh == null) throw new ObjectDisposedException("Mesh"); var bounds = new Bounds(camera.transform.position, Vector3.one * 1000f); for (int index = 0; index < RenderParams.Length; ++index) { var renderParam = RenderParams[index]; if (renderParam.material != null) { renderParam.camera = camera; renderParam.worldBounds = bounds; Graphics.RenderMeshIndirect(in renderParam, Mesh, indirectDrawIndexedArgs, 1, obj.indirectArgsPerSubmeshOffsets[(int)baseIndirectArgsIndex + index]); } } } internal virtual void Dispose() { } } }