Exemplo n.º 1
0
        /// <inheritdoc/>
        public void DrawRibbon(ref RibbonArgs p0, ref RibbonArgs p1, PackedTexture texture)
        {
            int index, dummy;

            _renderBatch.Submit(PrimitiveType.TriangleList, 4, 6, out index, out dummy);

            OnDrawRibbon(ref p0, ref p1, texture, _renderBatch.Vertices, index);
        }
Exemplo n.º 2
0
        protected override void OnDrawRibbon(ref RibbonArgs p0, ref RibbonArgs p1, PackedTexture texture, BillboardVertex[] vertices, int index)
        {
            // p0 and p1 specify a segment of a particle ribbon.
            //   --+--------------+--
            //    p0             p1
            //   --+--------------+--

            // Bottom left vertex
            var v = new BillboardVertex();

            v.Position          = p0.Position;
            v.Axis              = p0.Axis;
            v.Color3F           = p0.Color;
            v.Alpha             = p0.Alpha;
            v.TextureCoordinate = new Vector2F(p0.TextureCoordinateU, 1);
            v.Size              = new Vector2F(p0.Size);
            v.Softness          = p0.Softness;
            v.ReferenceAlpha    = p0.ReferenceAlpha;
            v.AnimationTime     = p0.AnimationTime;
            v.BlendMode         = p0.BlendMode;
            v.Texture           = texture;
            vertices[index]     = v;
            index++;

            // Top left vertex
            v.TextureCoordinate.Y = 0;
            vertices[index]       = v;
            index++;

            // Top right vertex
            v.Position          = p1.Position;
            v.Axis              = p1.Axis;
            v.Color3F           = p1.Color;
            v.Alpha             = p1.Alpha;
            v.TextureCoordinate = new Vector2F(p1.TextureCoordinateU, 0);
            v.Size              = new Vector2F(p1.Size);
            v.Softness          = p1.Softness;
            v.ReferenceAlpha    = p1.ReferenceAlpha;
            v.AnimationTime     = p1.AnimationTime;
            v.BlendMode         = p1.BlendMode;
            vertices[index]     = v;
            index++;

            // Bottom right vertex
            v.TextureCoordinate.Y = 1;
            vertices[index]       = v;
        }
Exemplo n.º 3
0
        protected override void OnDrawRibbon(ref RibbonArgs p0, ref RibbonArgs p1, PackedTexture texture, VertexPositionColorTexture[] vertices, int index)
        {
            // p0 and p1 specify a segment of a particle ribbon.
            //   --+--------------+--
            //    p0             p1
            //   --+--------------+--

            #region ----- Handle texture information and size -----

            float    animationTime       = p0.AnimationTime;
            Vector2F texCoordTopLeft     = texture.GetTextureCoordinates(new Vector2F(p0.TextureCoordinateU, 0), animationTime);
            Vector2F texCoordBottomRight = texture.GetTextureCoordinates(new Vector2F(p1.TextureCoordinateU, 1), animationTime);

            // Negative sizes (mirroring) is not supported because this conflicts with the
            // texture tiling on ribbons.
            float size0 = Math.Abs(p0.Size) / 2;
            float size1 = Math.Abs(p1.Size) / 2;

            // Offset from particle center to upper edge.
            Vector3F up0;
            up0.X = p0.Axis.X * size0;
            up0.Y = p0.Axis.Y * size0;
            up0.Z = p0.Axis.Z * size0;

            Vector3F up1;
            up1.X = p1.Axis.X * size1;
            up1.Y = p1.Axis.Y * size1;
            up1.Z = p1.Axis.Z * size1;
            #endregion

            #region ----- Get Color -----

            // Premultiply alpha.
            Vector4 color4 = new Vector4
            {
                X = p0.Color.X * p0.Alpha,
                Y = p0.Color.Y * p0.Alpha,
                Z = p0.Color.Z * p0.Alpha,

                // Apply blend mode (0 = additive, 1 = alpha blend).
                W = p0.Alpha * p0.BlendMode
            };
            var color0 = new Color(color4);

            color4 = new Vector4
            {
                X = p1.Color.X * p1.Alpha,
                Y = p1.Color.Y * p1.Alpha,
                Z = p1.Color.Z * p1.Alpha,
                W = p1.Alpha * p1.BlendMode
            };

            var color1 = new Color(color4);
            #endregion

            #region ----- Initializes vertices in vertex array -----

            // Bottom left vertex
            vertices[index].Position.X          = p0.Position.X - up0.X;
            vertices[index].Position.Y          = p0.Position.Y - up0.Y;
            vertices[index].Position.Z          = p0.Position.Z - up0.Z;
            vertices[index].Color               = color0;
            vertices[index].TextureCoordinate.X = texCoordTopLeft.X;
            vertices[index].TextureCoordinate.Y = texCoordBottomRight.Y;
            index++;

            // Top left vertex
            vertices[index].Position.X          = p0.Position.X + up0.X;
            vertices[index].Position.Y          = p0.Position.Y + up0.Y;
            vertices[index].Position.Z          = p0.Position.Z + up0.Z;
            vertices[index].Color               = color0;
            vertices[index].TextureCoordinate.X = texCoordTopLeft.X;
            vertices[index].TextureCoordinate.Y = texCoordTopLeft.Y;
            index++;

            // Top right vertex
            vertices[index].Position.X          = p1.Position.X + up1.X;
            vertices[index].Position.Y          = p1.Position.Y + up1.Y;
            vertices[index].Position.Z          = p1.Position.Z + up1.Z;
            vertices[index].Color               = color1;
            vertices[index].TextureCoordinate.X = texCoordBottomRight.X;
            vertices[index].TextureCoordinate.Y = texCoordTopLeft.Y;
            index++;

            // Bottom right vertex
            vertices[index].Position.X          = p1.Position.X - up1.X;
            vertices[index].Position.Y          = p1.Position.Y - up1.Y;
            vertices[index].Position.Z          = p1.Position.Z - up1.Z;
            vertices[index].Color               = color1;
            vertices[index].TextureCoordinate.X = texCoordBottomRight.X;
            vertices[index].TextureCoordinate.Y = texCoordBottomRight.Y;
            #endregion
        }
Exemplo n.º 4
0
        private void DrawParticleRibbonsAuto(ParticleSystemData particleSystemData, bool requiresTransformation, ref Vector3F scale, ref Pose pose, ref Vector3F color, float alpha)
        {
            // At least two particles are required to create a ribbon.
            int numberOfParticles = particleSystemData.Particles.Count;

            if (numberOfParticles < 2)
            {
                return;
            }

            // The up axis is not defined and needs to be derived automatically:
            // - Compute tangents along the ribbon curve.
            // - Build cross-products of normal and tangent vectors.

            // Is normal uniform across all particles?
            Vector3F?uniformNormal;

            switch (particleSystemData.BillboardOrientation.Normal)
            {
            case BillboardNormal.ViewPlaneAligned:
                uniformNormal = _defaultNormal;
                break;

            case BillboardNormal.ViewpointOriented:
                uniformNormal = _cameraPose.Position - pose.Position;
                if (!uniformNormal.Value.TryNormalize())
                {
                    uniformNormal = _defaultNormal;
                }
                break;

            default:
                var normalParameter = particleSystemData.NormalParameter;
                if (normalParameter == null)
                {
                    uniformNormal = _defaultNormal;
                }
                else if (normalParameter.IsUniform)
                {
                    uniformNormal = normalParameter.DefaultValue;
                    if (requiresTransformation)
                    {
                        uniformNormal = pose.ToWorldDirection(uniformNormal.Value);
                    }
                }
                else
                {
                    // Normal is set in particle data.
                    uniformNormal = null;
                }
                break;
            }

            var texture   = particleSystemData.Texture ?? _debugTexture;
            var particles = particleSystemData.Particles.Array;
            int index     = 0;

            do
            {
                // ----- Skip dead particles.
                while (index < numberOfParticles && !particles[index].IsAlive)
                {
                    index++;
                }

                // ----- Start of new ribbon.
                int endIndex = index + 1;
                while (endIndex < numberOfParticles && particles[endIndex].IsAlive)
                {
                    endIndex++;
                }

                int numberOfSegments = endIndex - index - 1;

                var p0 = new RibbonArgs
                {
                    // Uniform parameters
                    Softness       = particleSystemData.Softness,
                    ReferenceAlpha = particleSystemData.AlphaTest
                };

                var p1 = new RibbonArgs
                {
                    // Uniform parameters
                    Softness       = particleSystemData.Softness,
                    ReferenceAlpha = particleSystemData.AlphaTest
                };

                // Compute axes and render ribbon.
                // First particle.
                if (requiresTransformation)
                {
                    p0.Position = pose.ToWorldPosition(particles[index].Position * scale);
                    p0.Size     = particles[index].Size.Y * scale.Y;
                }
                else
                {
                    p0.Position = particles[index].Position;
                    p0.Size     = particles[index].Size.Y;
                }

                p0.Color              = particles[index].Color * color;
                p0.Alpha              = particles[index].Alpha * alpha;
                p0.AnimationTime      = particles[index].AnimationTime;
                p0.BlendMode          = particles[index].BlendMode;
                p0.TextureCoordinateU = 0;

                index++;
                Vector3F nextPosition;
                if (requiresTransformation)
                {
                    nextPosition = pose.ToWorldPosition(particles[index].Position * scale);
                }
                else
                {
                    nextPosition = particles[index].Position;
                }

                Vector3F normal;
                if (uniformNormal.HasValue)
                {
                    // Uniform normal.
                    normal = uniformNormal.Value;
                }
                else
                {
                    // Varying normal.
                    normal = particles[index].Normal;
                    if (requiresTransformation)
                    {
                        normal = pose.ToWorldDirection(normal);
                    }
                }

                Vector3F previousDelta = nextPosition - p0.Position;
                p0.Axis = Vector3F.Cross(normal, previousDelta);
                p0.Axis.TryNormalize();

                // Intermediate particles.
                while (index < endIndex - 1)
                {
                    p1.Position = nextPosition;

                    if (requiresTransformation)
                    {
                        nextPosition = pose.ToWorldPosition(particles[index + 1].Position * scale);
                        p1.Size      = particles[index].Size.Y * scale.Y;
                    }
                    else
                    {
                        nextPosition = particles[index + 1].Position;
                        p1.Size      = particles[index].Size.Y;
                    }

                    if (uniformNormal.HasValue)
                    {
                        // Uniform normal.
                        normal = uniformNormal.Value;
                    }
                    else
                    {
                        // Varying normal.
                        normal = particles[index].Normal;
                        if (requiresTransformation)
                        {
                            normal = pose.ToWorldDirection(normal);
                        }
                    }

                    Vector3F delta   = nextPosition - p1.Position;
                    Vector3F tangent = delta + previousDelta; // Note: Should we normalize vectors for better average?
                    p1.Axis = Vector3F.Cross(normal, tangent);
                    p1.Axis.TryNormalize();

                    p1.Color              = particles[index].Color * color;
                    p1.Alpha              = particles[index].Alpha * alpha;
                    p1.AnimationTime      = particles[index].AnimationTime;
                    p1.BlendMode          = particles[index].BlendMode;
                    p1.TextureCoordinateU = GetTextureCoordinateU1(index - 1, numberOfSegments, particleSystemData.TextureTiling);

                    // Draw ribbon segment.
                    _billboardBatch.DrawRibbon(ref p0, ref p1, texture);

                    p0 = p1;
                    p0.TextureCoordinateU = GetTextureCoordinateU0(index, numberOfSegments, particleSystemData.TextureTiling);
                    previousDelta         = delta;
                    index++;
                }

                // Last particle.
                p1.Position = nextPosition;

                if (uniformNormal.HasValue)
                {
                    // Uniform normal.
                    normal = uniformNormal.Value;
                }
                else
                {
                    // Varying normal.
                    normal = particles[index].Normal;
                    if (requiresTransformation)
                    {
                        normal = pose.ToWorldDirection(normal);
                    }
                }

                p1.Axis = Vector3F.Cross(normal, previousDelta);
                p1.Axis.TryNormalize();

                if (requiresTransformation)
                {
                    p1.Size = particles[index].Size.Y * scale.Y;
                }
                else
                {
                    p1.Size = particles[index].Size.Y;
                }

                p1.Color              = particles[index].Color * color;
                p1.Alpha              = particles[index].Alpha * alpha;
                p1.AnimationTime      = particles[index].AnimationTime;
                p1.BlendMode          = particles[index].BlendMode;
                p1.TextureCoordinateU = GetTextureCoordinateU1(index - 1, numberOfSegments, particleSystemData.TextureTiling);

                // Draw last ribbon segment.
                _billboardBatch.DrawRibbon(ref p0, ref p1, texture);
                index++;
            } while (index < numberOfParticles);
        }
Exemplo n.º 5
0
        // Particle ribbons:
        // Particles can be rendered as ribbons (a.k.a. trails, lines). Subsequent living
        // particles are connected using rectangles.
        //   +--------------+--------------+
        //   |              |              |
        //   p0             p1             p2
        //   |              |              |
        //   +--------------+--------------+
        // At least two living particles are required to create a ribbon. Dead particles
        // ("NormalizedAge" ≥ 1) can be used as delimiters to terminate one ribbon and
        // start the next ribbon.
        //
        // p0 and p1 can have different colors and alpha values to create color gradients
        // or a ribbon that fades in/out.

        private void DrawParticleRibbonsFixed(ParticleSystemData particleSystemData, bool requiresTransformation, ref Vector3F scale, ref Pose pose, ref Vector3F color, float alpha)
        {
            // At least two particles are required to create a ribbon.
            int numberOfParticles = particleSystemData.Particles.Count;

            if (numberOfParticles < 2)
            {
                return;
            }

            var  particles         = particleSystemData.Particles.Array;
            bool isAxisInViewSpace = particleSystemData.BillboardOrientation.IsAxisInViewSpace;
            int  index             = 0;

            do
            {
                // ----- Skip dead particles.
                while (index < numberOfParticles && !particles[index].IsAlive)
                {
                    index++;
                }

                // ----- Start of new ribbon.
                int endIndex = index + 1;
                while (endIndex < numberOfParticles && particles[endIndex].IsAlive)
                {
                    endIndex++;
                }

                int numberOfSegments = endIndex - index - 1;

                var p0 = new RibbonArgs
                {
                    // Uniform parameters
                    Softness       = particleSystemData.Softness,
                    ReferenceAlpha = particleSystemData.AlphaTest
                };

                var p1 = new RibbonArgs
                {
                    // Uniform parameters
                    Softness       = particleSystemData.Softness,
                    ReferenceAlpha = particleSystemData.AlphaTest
                };

                p0.Axis = particles[index].Axis;
                if (requiresTransformation)
                {
                    p0.Position = pose.ToWorldPosition(particles[index].Position * scale);
                    if (!isAxisInViewSpace)
                    {
                        p0.Axis = pose.ToWorldDirection(p0.Axis);
                    }

                    p0.Size = particles[index].Size.Y * scale.Y;
                }
                else
                {
                    p0.Position = particles[index].Position;
                    p0.Size     = particles[index].Size.Y;
                }

                p0.Color              = particles[index].Color * color;
                p0.Alpha              = particles[index].Alpha * alpha;
                p0.AnimationTime      = particles[index].AnimationTime;
                p0.BlendMode          = particles[index].BlendMode;
                p0.TextureCoordinateU = 0;

                index++;
                while (index < endIndex)
                {
                    p1.Axis = particles[index].Axis;
                    if (requiresTransformation)
                    {
                        p1.Position = pose.ToWorldPosition(particles[index].Position * scale);
                        if (!isAxisInViewSpace)
                        {
                            p1.Axis = pose.ToWorldDirection(p1.Axis);
                        }

                        p1.Size = particles[index].Size.Y * scale.Y;
                    }
                    else
                    {
                        p1.Position = particles[index].Position;
                        p1.Size     = particles[index].Size.Y;
                    }

                    p1.Color              = particles[index].Color * color;
                    p1.Alpha              = particles[index].Alpha * alpha;
                    p1.AnimationTime      = particles[index].AnimationTime;
                    p1.BlendMode          = particles[index].BlendMode;
                    p1.TextureCoordinateU = GetTextureCoordinateU1(index - 1, numberOfSegments, particleSystemData.TextureTiling);

                    // Draw ribbon segment.
                    var texture = particleSystemData.Texture ?? _debugTexture;
                    _billboardBatch.DrawRibbon(ref p0, ref p1, texture);

                    p0 = p1;
                    p0.TextureCoordinateU = GetTextureCoordinateU0(index, numberOfSegments, particleSystemData.TextureTiling);
                    index++;
                }
            } while (index < numberOfParticles);
        }
Exemplo n.º 6
0
 /// <summary>
 /// Adds a segment of a particle ribbon (4 vertices) to the vertex buffer.
 /// </summary>
 /// <param name="p0">The segment start.</param>
 /// <param name="p1">The segment end.</param>
 /// <param name="texture">The packed texture.</param>
 /// <param name="vertices">The vertex buffer.</param>
 /// <param name="index">The index of the next free slot in the vertex buffer.</param>
 protected abstract void OnDrawRibbon(ref RibbonArgs p0, ref RibbonArgs p1, PackedTexture texture, T[] vertices, int index);