public static void InitEmitterBoxSource(EntityManager mgr, Entity emitter, NativeArray <Entity> particles) { var source = mgr.GetComponentData <EmitterBoxSource>(emitter); foreach (var particle in particles) { var pos = ParticlesUtil.RandomPointInRect(source.rect); // center the box at the origin. // TODO: we could precompute the proper source rect (basically move the origin x/y by half) and // stash it somewhere to avoid division here pos.x -= source.rect.width / 2.0f; pos.y -= source.rect.height / 2.0f; var Translation = mgr.GetComponentData <Translation>(particle); Translation.Value += new float3(pos.x, pos.y, 0.0f); mgr.SetComponentData(particle, Translation); } }
static void InitTime(EntityManager mgr, float deltaTime, Range lifetime, NativeArray <Entity> newParticles) { // The time is evenly distributted from 0.0 to deltaTime. // The time of each subsequent particle will be increased by this value. // particle.time[0..n] = (0 * timeStep, 1 * timeStep, 2 * timeStep, ..., n * timeStep). float timeStep = newParticles.Length > 1 ? (deltaTime / (float)(newParticles.Length - 1)) : 0.0f; // We need to subtract deltaTime from the particle's relative time, because later in // the same frame we are adding deltaTime to the particle's relative time when we process // them. This ensures that the first, newly created particle will start at a relative time 0.0. float time = -deltaTime; foreach (var particle in newParticles) { var cParticle = mgr.GetComponentData <Particle>(particle); cParticle.lifetime = ParticlesUtil.RandomRange(lifetime); cParticle.time = time; time += timeStep; mgr.SetComponentData(particle, cParticle); } }
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); } }