private static Entity CreateParticleRenderer(EntityManager mgr, Entity eEmitter) { Entity eParticleRenderer = mgr.CreateEntity(typeof(MeshRenderer), typeof(EmitterReferenceForRenderer), typeof(LocalToWorld), typeof(DynamicMeshData)); var material = mgr.GetComponentData <ParticleMaterial>(eEmitter).Material; Assert.IsTrue(material != Entity.Null); mgr.AddComponentData(eParticleRenderer, new MeshRenderer { mesh = eParticleRenderer, material = material, startIndex = 0, indexCount = 0 }); mgr.AddComponentData(eParticleRenderer, new EmitterReferenceForRenderer { emitter = eEmitter }); mgr.AddComponentData(eParticleRenderer, new LocalToWorld { Value = float4x4.identity }); bool isLit = mgr.HasComponent <LitMaterial>(material); if (isLit) { mgr.AddComponentData(eParticleRenderer, new LitParticleRenderer()); } else { Assert.IsTrue(mgr.HasComponent <SimpleMaterial>(material)); mgr.AddComponentData(eParticleRenderer, new SimpleParticleRenderer()); } // Particle mesh if (mgr.HasComponent <ParticleMesh>(eEmitter)) { ParticleMesh particleMesh = mgr.GetComponentData <ParticleMesh>(eEmitter); Assert.IsTrue(particleMesh.Mesh != Entity.Null); } else // Billboarded { // Add mesh for 1x1 quad Entity mesh; float3 org = new float3(-0.5f, -0.5f, 0); float3 du = new float3(1, 0, 0); float3 dv = new float3(0, 1, 0); var builder = new BlobBuilder(Allocator.Temp); if (isLit) { LitMeshRenderData lmrd; MeshBounds mb; ref var root = ref builder.ConstructRoot <LitMeshData>(); var vertices = builder.Allocate(ref root.Vertices, 4).AsNativeArray(); var indices = builder.Allocate(ref root.Indices, 6).AsNativeArray(); vertices[0] = new LitVertex { Position = org, TexCoord0 = new float2(0, 1) }; vertices[1] = new LitVertex { Position = org + du, TexCoord0 = new float2(1, 1) }; vertices[2] = new LitVertex { Position = org + du + dv, TexCoord0 = new float2(1, 0) }; vertices[3] = new LitVertex { Position = org + dv, TexCoord0 = new float2(0, 0) }; indices[0] = 0; indices[1] = 2; indices[2] = 1; indices[3] = 2; indices[4] = 0; indices[5] = 3; MeshHelper.ComputeNormals(vertices, indices); MeshHelper.ComputeTangentAndBinormal(vertices, indices); MeshHelper.SetAlbedoColor(vertices, new float4(1)); MeshHelper.SetMetalSmoothness(vertices, new float2(1)); mb.Bounds = MeshHelper.ComputeBounds(vertices); lmrd.Mesh = builder.CreateBlobAssetReference <LitMeshData>(Allocator.Persistent); mesh = mgr.CreateEntity(typeof(LitMeshRenderData), typeof(MeshBounds)); mgr.SetComponentData(mesh, lmrd); mgr.SetComponentData(mesh, mb); var litMaterial = mgr.GetComponentData <LitMaterial>(material); litMaterial.billboarded = true; mgr.SetComponentData(material, litMaterial); }
protected override void OnUpdate() { EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.TempJob); NativeArray <Entity> renderers = m_ParticleRenderersQuery.ToEntityArray(Allocator.TempJob); foreach (var renderer in renderers) { var emitterReference = EntityManager.GetComponentData <EmitterReferenceForRenderer>(renderer); var eEmitter = emitterReference.emitter; // In some cases it takes an extra frame for the particle entities that reference a destroyed emitter to be destroyed, most likely because of system state components if (!ParticlesUtil.EmitterIsValid(EntityManager, eEmitter)) { continue; } DynamicBuffer <Particle> particles = EntityManager.GetBuffer <DynamicParticle>(eEmitter).Reinterpret <Particle>(); if (!EntityManager.GetEnabled(eEmitter) || particles.Length == 0) { if (!EntityManager.HasComponent <Disabled>(renderer)) { ecb.AddComponent(renderer, new Disabled()); } continue; } if (EntityManager.HasComponent <Disabled>(renderer)) { ecb.RemoveComponent <Disabled>(renderer); } var particleMesh = EntityManager.GetComponentData <ParticleMesh>(eEmitter); var meshRenderer = EntityManager.GetComponentData <MeshRenderer>(renderer); Entity eMesh = meshRenderer.mesh; var particleEmitter = EntityManager.GetComponentData <ParticleEmitter>(eEmitter); var localToWorldEmitter = particleEmitter.AttachToEmitter ? EntityManager.GetComponentData <LocalToWorld>(eEmitter).Value : float4x4.identity; MinMaxAABB minMaxAABB = MinMaxAABB.Empty; int numVertices, numIndices; if (EntityManager.HasComponent <LitParticleRenderer>(renderer)) { ref LitMeshData lmd = ref EntityManager.GetComponentData <LitMeshRenderData>(particleMesh.Mesh).Mesh.Value; int numVertsPerParticle = lmd.Vertices.Length; int numIndicesPerParticle = lmd.Indices.Length; NativeArray <LitVertex> particleVertices = MeshHelper.AsNativeArray(ref lmd.Vertices); NativeArray <ushort> particleIndices = MeshHelper.AsNativeArray(ref lmd.Indices); var vBuffer = EntityManager.GetBuffer <DynamicLitVertex>(eMesh); var iBuffer = EntityManager.GetBuffer <DynamicIndex>(eMesh); numVertices = particles.Length * numVertsPerParticle; numIndices = particles.Length * numIndicesPerParticle; vBuffer.ResizeUninitialized(numVertices); // Grow buffers as needed iBuffer.ResizeUninitialized(numIndices); NativeArray <LitVertex> vertices = vBuffer.AsNativeArray().Reinterpret <DynamicLitVertex, LitVertex>(); NativeArray <ushort> indices = iBuffer.AsNativeArray().Reinterpret <DynamicIndex, ushort>(); bool billboarded = EntityManager.GetComponentData <LitMaterial>(meshRenderer.material).billboarded; for (int particleIndex = 0; particleIndex < particles.Length; particleIndex++) { float4x4 localToWorld = GetParticleLocalToWorld(particles[particleIndex], localToWorldEmitter); float3x3 localToWorldRS = new float3x3(localToWorld.c0.xyz, localToWorld.c1.xyz, localToWorld.c2.xyz); float3x3 modelInverseTransposeRS = math.transpose(math.inverse(localToWorldRS)); float4x4 modelInverseTranspose = new float4x4(modelInverseTransposeRS, float3.zero); // Postpone translate until after additional rotation for billboarding is applied in shader float4x4 model = billboarded ? new float4x4(localToWorldRS, float3.zero) : localToWorld; int vertexOffset = particleIndex * numVertsPerParticle; for (int i = 0; i < numVertsPerParticle; i++) { LitVertex vertex = particleVertices[i]; vertex.Position = math.transform(model, vertex.Position); vertex.Normal = math.transform(modelInverseTranspose, vertex.Normal); vertex.Tangent = math.transform(modelInverseTranspose, vertex.Tangent); vertex.BillboardPos = billboarded ? localToWorld.c3.xyz : float3.zero; vertex.Albedo_Opacity = particles[particleIndex].color; vertices[vertexOffset + i] = vertex; minMaxAABB.Encapsulate(vertex.Position + vertex.BillboardPos); } UpdateIndicesForParticle(indices, particleIndices, particleIndex, numIndicesPerParticle, vertexOffset); } }