/// <inheritdoc />
        public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter)
        {
            // If you want, you can integrate the base builder here and not call it. It should result in slight speed up
            base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter);

            var colorField = sorter.GetField(ParticleFields.Color);

            if (!colorField.IsValid())
            {
                return;
            }

            var colAttribute = bufferState.GetAccessor(VertexAttributes.Color);

            if (colAttribute.Size <= 0)
            {
                return;
            }

            foreach (var particle in sorter)
            {
                // Set the vertex color attribute to the particle's color field
                var color = (uint)(*(Color4 *)particle[colorField]).ToRgba();
                bufferState.SetAttributePerSegment(colAttribute, (IntPtr)(&color));

                bufferState.NextSegment();
            }

            bufferState.StartOver();
        }
Example #2
0
        public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter)
        {
            // If you want, you can integrate the base builder here and not call it. It should result in slight speed up
            base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter);

            // Update the non-default coordinates first, because they update off the default ones
            if (UVBuilder1 != null)
            {
                UVBuilder1.BuildUVCoordinates(ref bufferState, ref sorter, texCoord1);
            }

            // Update the default coordinates last
            if (UVBuilder0 != null)
            {
                UVBuilder0.BuildUVCoordinates(ref bufferState, ref sorter, texCoord0);
            }

            // If the particles have color field, the base class should have already passed the information
            if (HasColorField)
            {
                return;
            }

            // If there is no color stream we don't need to fill anything
            var colAttribute = bufferState.GetAccessor(VertexAttributes.Color);

            if (colAttribute.Size <= 0)
            {
                return;
            }

            // Since the particles don't have their own color field, set the default color to white
            var color = 0xFFFFFFFF;

            bufferState.StartOver();
            foreach (var particle in sorter)
            {
                bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color));

                bufferState.NextParticle();
            }

            bufferState.StartOver();
        }
Example #3
0
        /// <inheritdoc />
        public unsafe override void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter)
        {
            // If you want, you can implement the base builder here and not call it. It should result in slight speed up
            base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter);

            //  The UV Builder, if present, animates the basic (0, 0, 1, 1) uv coordinates of each billboard
            UVBuilder?.BuildUVCoordinates(ref bufferState, ref sorter, bufferState.DefaultTexCoords);
            bufferState.StartOver();

            // If the particles have color field, the base class should have already passed the information
            if (HasColorField)
            {
                return;
            }

            // If the particles don't have color field but there is no color stream either we don't need to fill anything
            var colAttribute = bufferState.GetAccessor(VertexAttributes.Color);

            if (colAttribute.Size <= 0)
            {
                return;
            }

            // Since the particles don't have their own color field, set the default color to white
            var color = 0xFFFFFFFF;

            // TODO: for loop. Remove IEnumerable from sorter
            foreach (var particle in sorter)
            {
                bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color));

                bufferState.NextParticle();
            }

            bufferState.StartOver();
        }
Example #4
0
        /// <summary>
        /// Build the vertex buffer from particle data
        /// </summary>
        /// <param name="sharedBufferPtr">The shared vertex buffer position where the particle data should be output</param>
        /// <param name="invViewMatrix">The current camera's inverse view matrix</param>
        public void BuildVertexBuffer(IntPtr sharedBufferPtr, ref Matrix invViewMatrix, ref Matrix viewProj)
        {
            // Get camera-space X and Y axes for billboard expansion and sort the particles if needed
            var unitX = new Vector3(invViewMatrix.M11, invViewMatrix.M12, invViewMatrix.M13);
            var unitY = new Vector3(invViewMatrix.M21, invViewMatrix.M22, invViewMatrix.M23);

            // Not the best solution, might want to improve
            var depthVector = Vector3.Cross(unitX, unitY);

            if (simulationSpace == EmitterSimulationSpace.Local)
            {
                var inverseRotation = drawTransform.WorldRotation;
                inverseRotation.W *= -1;
                inverseRotation.Rotate(ref depthVector);
            }
            var sortedList = ParticleSorter.GetSortedList(depthVector);

            // If the particles are in world space they don't need to be fixed as their coordinates are already in world space
            // If the particles are in local space they need to be drawn in world space using the emitter's current location matrix
            var posIdentity   = new Vector3(0, 0, 0);
            var rotIdentity   = Quaternion.Identity;
            var scaleIdentity = 1f;

            if (simulationSpace == EmitterSimulationSpace.Local)
            {
                posIdentity   = drawTransform.WorldPosition;
                rotIdentity   = drawTransform.WorldRotation;
                scaleIdentity = drawTransform.WorldScale.X;
            }

            ParticleBufferState bufferState = new ParticleBufferState(sharedBufferPtr, VertexBuilder);

            ShapeBuilder.SetRequiredQuads(ShapeBuilder.QuadsPerParticle, pool.LivingParticles, pool.ParticleCapacity);
            ShapeBuilder.BuildVertexBuffer(ref bufferState, unitX, unitY, ref posIdentity, ref rotIdentity, scaleIdentity, ref sortedList, ref viewProj);

            bufferState.StartOver();
            Material.PatchVertexBuffer(ref bufferState, unitX, unitY, ref sortedList);

            ParticleSorter.FreeSortedList(ref sortedList);
        }
Example #5
0
        /// <inheritdoc />
        public override unsafe void BuildUVCoordinates(ref ParticleBufferState bufferState, ref ParticleList sorter, AttributeDescription texCoordsDescription)
        {
            var lifeField = sorter.GetField(ParticleFields.RemainingLife);

            if (!lifeField.IsValid())
            {
                return;
            }

            var texAttribute = bufferState.GetAccessor(texCoordsDescription);

            if (texAttribute.Size == 0 && texAttribute.Offset == 0)
            {
                return;
            }

            var texDefault = bufferState.GetAccessor(bufferState.DefaultTexCoords);

            if (texDefault.Size == 0 && texDefault.Offset == 0)
            {
                return;
            }


            foreach (var particle in sorter)
            {
                var normalizedTimeline = 1f - *(float *)(particle[lifeField]);

                var spriteId = startingFrame + (int)(normalizedTimeline * animationSpeedOverLife);

                Vector4 uvTransform = new Vector4((spriteId % xDivisions) * xStep, (spriteId / xDivisions) * yStep, xStep, yStep);

                bufferState.TransformAttributePerParticle(texDefault, texAttribute, this, ref uvTransform);

                bufferState.NextParticle();
            }


            bufferState.StartOver();
        }
Example #6
0
        /// <inheritdoc />
        public unsafe override void BuildUVCoordinates(ref ParticleBufferState bufferState, ref ParticleList sorter, AttributeDescription texCoordsDescription)
        {
            var lifeField = sorter.GetField(ParticleFields.RemainingLife);

            if (!lifeField.IsValid())
            {
                return;
            }

            var texAttribute = bufferState.GetAccessor(texCoordsDescription);

            if (texAttribute.Size == 0 && texAttribute.Offset == 0)
            {
                return;
            }

            var texDefault = bufferState.GetAccessor(bufferState.DefaultTexCoords);

            if (texDefault.Size == 0 && texDefault.Offset == 0)
            {
                return;
            }

            foreach (var particle in sorter)
            {
                var normalizedTimeline = 1f - *(float *)(particle[lifeField]);

                Vector4 uvTransform = Vector4.Lerp(StartFrame, EndFrame, normalizedTimeline);
                uvTransform.Z -= uvTransform.X;
                uvTransform.W -= uvTransform.Y;

                bufferState.TransformAttributePerSegment(texDefault, texAttribute, this, ref uvTransform);

                bufferState.NextSegment();
            }


            bufferState.StartOver();
        }
Example #7
0
        /// <inheritdoc />
        public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY,
                                                     ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter)
        {
            // Get all the required particle fields
            var positionField = sorter.GetField(ParticleFields.Position);

            if (!positionField.IsValid())
            {
                return(0);
            }
            var sizeField = sorter.GetField(ParticleFields.Size);

            var orderField = sorter.GetField(ParticleFields.Order);

            // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors
            // ReSharper disable once CompareOfFloatsByEqualityOperator
            var trsIdentity = (spaceScale == 1f);

            trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0)));
            trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity));

            var ribbonizer = new Ribbonizer(this, currentTotalParticles, currentQuadsPerParticle);

            var renderedParticles = 0;

            bufferState.StartOver();

            uint oldOrderValue = 0;

            foreach (var particle in sorter)
            {
                if (orderField.IsValid())
                {
                    var orderValue = (*((uint *)particle[orderField]));

                    if ((orderValue >> SpawnOrderConst.GroupBitOffset) != (oldOrderValue >> SpawnOrderConst.GroupBitOffset))
                    {
                        ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle);
                        ribbonizer.RibbonSplit();
                    }

                    oldOrderValue = orderValue;
                }

                var centralPos = particle.Get(positionField);

                var particleSize = sizeField.IsValid() ? particle.Get(sizeField) : 1f;

                if (!trsIdentity)
                {
                    spaceRotation.Rotate(ref centralPos);
                    centralPos    = centralPos * spaceScale + spaceTranslation;
                    particleSize *= spaceScale;
                }

                ribbonizer.AddParticle(ref centralPos, particleSize);
                renderedParticles++;
            }

            ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle);

            ribbonizer.Free();

            var vtxPerShape = 4 * QuadsPerParticle;

            return(renderedParticles * vtxPerShape);
        }
        /// <summary>
        /// Build the vertex buffer from particle data
        /// </summary>
        /// <param name="sharedBufferPtr">The shared vertex buffer position where the particle data should be output</param>
        /// <param name="invViewMatrix">The current camera's inverse view matrix</param>
        public void BuildVertexBuffer(IntPtr sharedBufferPtr, ref Matrix invViewMatrix)
        {
            // Get camera-space X and Y axes for billboard expansion and sort the particles if needed
            var unitX = new Vector3(invViewMatrix.M11, invViewMatrix.M12, invViewMatrix.M13);
            var unitY = new Vector3(invViewMatrix.M21, invViewMatrix.M22, invViewMatrix.M23);

            // Not the best solution, might want to improve
            var depthVector = Vector3.Cross(unitX, unitY);
            if (simulationSpace == EmitterSimulationSpace.Local)
            {
                var inverseRotation = drawTransform.WorldRotation;
                inverseRotation.W *= -1;
                inverseRotation.Rotate(ref depthVector);
            }
            var sortedList = ParticleSorter.GetSortedList(depthVector);

            // If the particles are in world space they don't need to be fixed as their coordinates are already in world space
            // If the particles are in local space they need to be drawn in world space using the emitter's current location matrix
            var posIdentity = new Vector3(0, 0, 0);
            var rotIdentity = Quaternion.Identity;
            var scaleIdentity = 1f;
            if (simulationSpace == EmitterSimulationSpace.Local)
            {
                posIdentity = drawTransform.WorldPosition;
                rotIdentity = drawTransform.WorldRotation;
                scaleIdentity = drawTransform.WorldScale.X;
            }

            ParticleBufferState bufferState = new ParticleBufferState(sharedBufferPtr, VertexBuilder);

            ShapeBuilder.SetRequiredQuads(ShapeBuilder.QuadsPerParticle, pool.LivingParticles, pool.ParticleCapacity);
            ShapeBuilder.BuildVertexBuffer(ref bufferState, unitX, unitY, ref posIdentity, ref rotIdentity, scaleIdentity, ref sortedList);

            bufferState.StartOver();
            Material.PatchVertexBuffer(ref bufferState, unitX, unitY, ref sortedList);

            ParticleSorter.FreeSortedList(ref sortedList);
        }
        /// <inheritdoc />
        public override unsafe int BuildVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY,
            ref Vector3 spaceTranslation, ref Quaternion spaceRotation, float spaceScale, ref ParticleList sorter)
        {
            // Get all the required particle fields
            var positionField = sorter.GetField(ParticleFields.Position);
            if (!positionField.IsValid())
                return 0;
            var sizeField = sorter.GetField(ParticleFields.Size);

            var orderField = sorter.GetField(ParticleFields.Order);

            // Check if the draw space is identity - in this case we don't need to transform the position, scale and rotation vectors
            // ReSharper disable once CompareOfFloatsByEqualityOperator
            var trsIdentity = (spaceScale == 1f);
            trsIdentity = trsIdentity && (spaceTranslation.Equals(new Vector3(0, 0, 0)));
            trsIdentity = trsIdentity && (spaceRotation.Equals(Quaternion.Identity));

            var ribbonizer = new Ribbonizer(this, currentTotalParticles, currentQuadsPerParticle);

            var renderedParticles = 0;
            bufferState.StartOver();

            uint oldOrderValue = 0;

            foreach (var particle in sorter)
            {
                if (orderField.IsValid())
                {
                    var orderValue = (*((uint*)particle[orderField]));

                    if ((orderValue >> SpawnOrderConst.GroupBitOffset) != (oldOrderValue >> SpawnOrderConst.GroupBitOffset)) 
                    {
                        ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle);
                        ribbonizer.RibbonSplit();
                    }

                    oldOrderValue = orderValue;
                }

                var centralPos = particle.Get(positionField);

                var particleSize = sizeField.IsValid() ? particle.Get(sizeField) : 1f;

                if (!trsIdentity)
                {
                    spaceRotation.Rotate(ref centralPos);
                    centralPos = centralPos * spaceScale + spaceTranslation;
                    particleSize *= spaceScale;
                }
                
                ribbonizer.AddParticle(ref centralPos, particleSize);
                renderedParticles++;
            }

            ribbonizer.Ribbonize(ref bufferState, invViewX, invViewY, QuadsPerParticle);

            ribbonizer.Free();

            var vtxPerShape = 4 * QuadsPerParticle;
            return renderedParticles * vtxPerShape;
        }
        public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter)
        {
            // If you want, you can integrate the base builder here and not call it. It should result in slight speed up
            base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter);

            // Update the non-default coordinates first, because they update off the default ones
            if (UVBuilder1 != null) UVBuilder1.BuildUVCoordinates(ref bufferState, ref sorter, texCoord1);

            // Update the default coordinates last
            if (UVBuilder0 != null) UVBuilder0.BuildUVCoordinates(ref bufferState, ref sorter, texCoord0);

            // If the particles have color field, the base class should have already passed the information
            if (HasColorField)
                return;

            // If there is no color stream we don't need to fill anything
            var colAttribute = bufferState.GetAccessor(VertexAttributes.Color);
            if (colAttribute.Size <= 0)
                return;

            // Since the particles don't have their own color field, set the default color to white
            var color = 0xFFFFFFFF;

            bufferState.StartOver();
            foreach (var particle in sorter)
            {
                bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color));

                bufferState.NextParticle();
            }

            bufferState.StartOver();
        }
        /// <inheritdoc />
        public unsafe override void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter)
        {
            // If you want, you can implement the base builder here and not call it. It should result in slight speed up
            base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter);

            //  The UV Builder, if present, animates the basic (0, 0, 1, 1) uv coordinates of each billboard
            UVBuilder?.BuildUVCoordinates(ref bufferState, ref sorter, bufferState.DefaultTexCoords);
            bufferState.StartOver();

            // If the particles have color field, the base class should have already passed the information
            if (HasColorField)
                return;

            // If the particles don't have color field but there is no color stream either we don't need to fill anything
            var colAttribute = bufferState.GetAccessor(VertexAttributes.Color);
            if (colAttribute.Size <= 0)
                return;

            // Since the particles don't have their own color field, set the default color to white
            var color = 0xFFFFFFFF;

            // TODO: for loop. Remove IEnumerable from sorter
            foreach (var particle in sorter)
            {
                bufferState.SetAttributePerParticle(colAttribute, (IntPtr)(&color));

                bufferState.NextParticle();
            }

            bufferState.StartOver();
        }
        /// <inheritdoc />
        public override unsafe void PatchVertexBuffer(ref ParticleBufferState bufferState, Vector3 invViewX, Vector3 invViewY, ref ParticleList sorter)
        {
            // If you want, you can integrate the base builder here and not call it. It should result in slight speed up
            base.PatchVertexBuffer(ref bufferState, invViewX, invViewY, ref sorter);

            var colorField = sorter.GetField(ParticleFields.Color);
            if (!colorField.IsValid())
                return;

            var colAttribute = bufferState.GetAccessor(VertexAttributes.Color);
            if (colAttribute.Size <= 0)
                return;

            foreach (var particle in sorter)
            {
                // Set the vertex color attribute to the particle's color field
                var color = (uint)(*(Color4*)particle[colorField]).ToRgba();
                bufferState.SetAttributePerSegment(colAttribute, (IntPtr)(&color));

                bufferState.NextSegment();
            }

            bufferState.StartOver();
        }