using UnityEngine; using System.Collections.Generic; using UnityEngine.Rendering; using Unity.Profiling; using System.Runtime.InteropServices; namespace Obi { [StructLayout(LayoutKind.Sequential)] public struct ParticleVertex { public Vector4 pos; public Vector3 offset; public Vector4 color; public Vector4 b1; public Vector4 b2; public Vector4 b3; } public abstract class ObiParticleRenderSystem : RenderSystem { public Oni.RenderingSystemType typeEnum { get => Oni.RenderingSystemType.Particles; } public RendererSet renderers { get; } = new RendererSet(); public bool isSetup => activeParticles != null; protected VertexAttributeDescriptor[] layout = { new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 4), new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3), new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.Float32, 4), new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 4), new VertexAttributeDescriptor(VertexAttribute.TexCoord1, VertexAttributeFormat.Float32, 4), new VertexAttributeDescriptor(VertexAttribute.TexCoord2, VertexAttributeFormat.Float32, 4) }; static protected ProfilerMarker m_SetupRenderMarker = new ProfilerMarker("SetupParticleRendering"); static protected ProfilerMarker m_RenderMarker = new ProfilerMarker("ParticleRendering"); protected ObiSolver m_Solver; protected List> batchList = new List>(); protected ObiNativeList activeParticles; protected ObiNativeList rendererIndex; protected ObiNativeList rendererData; public ObiParticleRenderSystem(ObiSolver solver) { m_Solver = solver; activeParticles = new ObiNativeList(); rendererIndex = new ObiNativeList(); rendererData = new ObiNativeList(); } public virtual void Dispose() { for (int i = 0; i < batchList.Count; ++i) batchList[i].Dispose(); batchList.Clear(); if (activeParticles != null) activeParticles.Dispose(); if (rendererData != null) rendererData.Dispose(); if (rendererIndex != null) rendererIndex.Dispose(); } protected virtual void Clear() { for (int i = 0; i < batchList.Count; ++i) batchList[i].Dispose(); batchList.Clear(); activeParticles.Clear(); rendererData.Clear(); rendererIndex.Clear(); } protected virtual void CreateBatches() { // generate batches: for (int i = 0; i < renderers.Count; ++i) { renderers[i].renderParameters.layer = renderers[i].gameObject.layer; batchList.Add(new ProceduralRenderBatch(i, renderers[i].material, renderers[i].renderParameters)); } // sort batches: batchList.Sort(); int particleCount = 0; for (int i = 0; i < batchList.Count; ++i) { var batch = batchList[i]; var renderer = renderers[batch.firstRenderer]; int actorParticleCount = renderer.actor.particleCount; batch.vertexCount += actorParticleCount * 4; batch.triangleCount += actorParticleCount * 2; batch.firstParticle = particleCount; particleCount += actorParticleCount; // add particles here, respecting batch order: activeParticles.AddRange(renderer.actor.solverIndices, actorParticleCount); rendererData.Add(new ParticleRendererData(renderer.particleColor, renderer.radiusScale)); rendererIndex.AddReplicate(i, actorParticleCount); } } protected virtual void CloseBatches() { // Initialize each batch: for (int i = 0; i < batchList.Count; ++i) batchList[i].Initialize(layout); } public virtual void Setup() { using (m_SetupRenderMarker.Auto()) { Clear(); CreateBatches(); ObiUtils.MergeBatches(batchList); CloseBatches(); } } public virtual void Step() { } public virtual void Render() { } } }