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);
            }
        }
Example #2
0
        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);
                    }
                }