예제 #1
0
        /// <inheritdoc/>
        public void DrawBillboard(ref BillboardArgs billboard, PackedTexture texture)
        {
            int index, dummy;

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

            OnDrawBillboard(ref billboard, texture, _renderBatch.Vertices, index);
        }
예제 #2
0
        private void DrawParticlesOldToNew(ParticleSystemData particleSystemData, bool requiresTransformation, ref Vector3 scale, ref Pose pose, ref Vector3 color, float alpha, float angleOffset)
        {
            var b = new BillboardArgs
            {
                Orientation    = particleSystemData.BillboardOrientation,
                Softness       = particleSystemData.Softness,
                ReferenceAlpha = particleSystemData.AlphaTest,
            };

            int  numberOfParticles  = particleSystemData.Particles.Count;
            var  particles          = particleSystemData.Particles.Array;
            bool isViewPlaneAligned = (particleSystemData.BillboardOrientation.Normal == BillboardNormal.ViewPlaneAligned);
            bool isAxisInViewSpace  = particleSystemData.BillboardOrientation.IsAxisInViewSpace;

            for (int i = 0; i < numberOfParticles; i++)
            {
                if (particles[i].IsAlive) // Skip dead particles.
                {
                    if (requiresTransformation)
                    {
                        b.Position = pose.ToWorldPosition(particles[i].Position * scale);
                        b.Normal   = isViewPlaneAligned ? _defaultNormal : pose.ToWorldDirection(particles[i].Normal);
                        b.Axis     = isAxisInViewSpace ? particles[i].Axis : pose.ToWorldDirection(particles[i].Axis);
                        b.Size     = particles[i].Size * scale.Y; // Assume uniform scale for size.
                    }
                    else
                    {
                        b.Position = particles[i].Position;
                        b.Normal   = isViewPlaneAligned ? _defaultNormal : particles[i].Normal;
                        b.Axis     = particles[i].Axis;
                        b.Size     = particles[i].Size;
                    }

                    b.Angle         = particles[i].Angle + angleOffset;
                    b.Color         = particles[i].Color * color;
                    b.Alpha         = particles[i].Alpha * alpha;
                    b.AnimationTime = particles[i].AnimationTime;
                    b.BlendMode     = particles[i].BlendMode;

                    var texture = particleSystemData.Texture ?? _debugTexture;
                    _billboardBatch.DrawBillboard(ref b, texture);
                }
            }
        }
예제 #3
0
        private void Draw(BillboardNode node)
        {
            var billboard = (ImageBillboard)node.Billboard;
            var data      = new BillboardArgs
            {
                Position       = node.PoseWorld.Position,
                Normal         = (billboard.Orientation.Normal == BillboardNormal.ViewPlaneAligned) ? _defaultNormal : node.Normal,
                Axis           = node.Axis,
                Orientation    = billboard.Orientation,
                Size           = node.ScaleWorld.Y * billboard.Size, // Assume uniform scale for size.
                Softness       = Numeric.IsNaN(billboard.Softness) ? -1 : billboard.Softness,
                Color          = node.Color * billboard.Color,
                Alpha          = node.Alpha * billboard.Alpha,
                ReferenceAlpha = billboard.AlphaTest,
                AnimationTime  = (Numeric.IsNaN(node.AnimationTime)) ? billboard.AnimationTime : node.AnimationTime,
                BlendMode      = billboard.BlendMode,
            };

            var texture = billboard.Texture ?? _debugTexture;

            _billboardBatch.DrawBillboard(ref data, texture);
        }
예제 #4
0
        protected override void OnDrawBillboard(ref BillboardArgs b, PackedTexture texture, BillboardVertex[] vertices, int index)
        {
            // Bottom left vertex
            var v = new BillboardVertex();

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

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

            // Top right vertex
            v.TextureCoordinate.X = 1;
            vertices[index]       = v;
            index++;

            // Bottom right vertex
            v.TextureCoordinate.Y = 1;
            vertices[index]       = v;
        }
예제 #5
0
        private void DrawParticlesBackToFront(ParticleSystemData particleSystemData, bool requiresTransformation, ref Vector3 scale, ref Pose pose, ref Vector3 color, float alpha, float angleOffset)
        {
            var b = new BillboardArgs
            {
                Orientation    = particleSystemData.BillboardOrientation,
                Softness       = particleSystemData.Softness,
                ReferenceAlpha = particleSystemData.AlphaTest,
            };

            int numberOfParticles = particleSystemData.Particles.Count;
            var particles         = particleSystemData.Particles.Array;

            if (_particleIndices == null)
            {
                _particleIndices = new ArrayList <ParticleIndex>(numberOfParticles);
            }
            else
            {
                _particleIndices.Clear();
                _particleIndices.EnsureCapacity(numberOfParticles);
            }

            // Use linear distance for viewpoint-oriented and world-oriented billboards.
            bool useLinearDistance = (particleSystemData.BillboardOrientation.Normal != BillboardNormal.ViewPlaneAligned);

            // Compute positions and distance to camera.
            for (int i = 0; i < numberOfParticles; i++)
            {
                if (particles[i].IsAlive) // Skip dead particles.
                {
                    var particleIndex = new ParticleIndex();
                    particleIndex.Index = i;
                    if (requiresTransformation)
                    {
                        particleIndex.Position = pose.ToWorldPosition(particles[i].Position * scale);
                    }
                    else
                    {
                        particleIndex.Position = particles[i].Position;
                    }

                    // Planar distance: Project vector onto look direction.
                    Vector3 cameraToParticle = particleIndex.Position - _cameraPose.Position;
                    particleIndex.Distance = Vector3.Dot(cameraToParticle, _cameraForward);
                    if (useLinearDistance)
                    {
                        particleIndex.Distance = cameraToParticle.Length * Math.Sign(particleIndex.Distance);
                    }

                    _particleIndices.Add(ref particleIndex);
                }
            }

            // Sort particles back-to-front.
            _particleIndices.Sort(ParticleIndexComparer.Instance);

            bool isViewPlaneAligned = (particleSystemData.BillboardOrientation.Normal == BillboardNormal.ViewPlaneAligned);
            bool isAxisInViewSpace  = particleSystemData.BillboardOrientation.IsAxisInViewSpace;

            // Draw sorted particles.
            var indices = _particleIndices.Array;

            numberOfParticles = _particleIndices.Count; // Dead particles have been removed.
            for (int i = 0; i < numberOfParticles; i++)
            {
                int index = indices[i].Index;
                b.Position = indices[i].Position;
                if (requiresTransformation)
                {
                    b.Normal = isViewPlaneAligned ? _defaultNormal : pose.ToWorldDirection(particles[index].Normal);
                    b.Axis   = isAxisInViewSpace ? particles[index].Axis : pose.ToWorldDirection(particles[index].Axis);
                    b.Size   = particles[index].Size * scale.Y; // Assume uniform scale for size.
                }
                else
                {
                    b.Normal = isViewPlaneAligned ? _defaultNormal : particles[index].Normal;
                    b.Axis   = particles[index].Axis;
                    b.Size   = particles[index].Size;
                }

                b.Angle         = particles[index].Angle + angleOffset;
                b.Color         = particles[index].Color * color;
                b.Alpha         = particles[index].Alpha * alpha;
                b.AnimationTime = particles[index].AnimationTime;
                b.BlendMode     = particles[index].BlendMode;

                var texture = particleSystemData.Texture ?? _debugTexture;
                _billboardBatch.DrawBillboard(ref b, texture);
            }
        }
예제 #6
0
 /// <summary>
 /// Adds the specified billboard (4 vertices) to the vertex buffer.
 /// </summary>
 /// <param name="b">The billboard.</param>
 /// <param name="vertices">The vertex buffer.</param>
 /// <param name="texture">The packed texture.</param>
 /// <param name="index">The index of the next free slot in the vertex buffer.</param>
 protected abstract void OnDrawBillboard(ref BillboardArgs b, PackedTexture texture, T[] vertices, int index);
예제 #7
0
        protected override void OnDrawBillboard(ref BillboardArgs b, PackedTexture texture, VertexPositionColorTexture[] vertices, int index)
        {
            // The billboard orientation is defined by three vectors: normal (pointing to the camera),
            // up and right (both lying in the billboard plane).
            // normal and up are given. right is computed using the cross product up x normal.
            // normal and up should be perpendicular, but usually they are not. Therefore, one vector
            // must be corrected. For spherical billboards, the normal is fixed and the up vector
            // is corrected. For cylindrical billboards (= axial billboards), the up vector is fixed
            // and the b.Normal is corrected.

            // Normal
            if (b.Orientation.Normal == BillboardNormal.ViewpointOriented)
            {
                Vector3 normal = _cameraPose.Position - b.Position;
                if (normal.TryNormalize())
                {
                    b.Normal = normal;
                }
            }

            // Axis = up vector
            if (b.Orientation.IsAxisInViewSpace)
            {
                b.Axis = _cameraPose.ToWorldDirection(b.Axis);
            }

            if (1 - Vector3.Dot(b.Normal, b.Axis) < Numeric.EpsilonF)
            {
                // Normal and axis are parallel.
                // --> Bend normal by adding a fraction of the camera down vector.
                b.Normal += _cameraDown * 0.001f;
                b.Normal.Normalize();
            }

            // Compute right.
            //Vector3 right = Vector3.Cross(b.Axis, b.Normal);
            // Inlined:
            Vector3 right;

            right.X = b.Axis.Y * b.Normal.Z - b.Axis.Z * b.Normal.Y;
            right.Y = b.Axis.Z * b.Normal.X - b.Axis.X * b.Normal.Z;
            right.Z = b.Axis.X * b.Normal.Y - b.Axis.Y * b.Normal.X;
            if (!right.TryNormalize())
            {
                right = b.Normal.Orthonormal1; // Normal and axis are parallel --> Choose random perpendicular vector.
            }
            if (b.Orientation.IsAxisFixed)
            {
                // Make sure normal is perpendicular to right and up.
                //normal = Vector3.Cross(right, b.Axis);
                // Inlined:
                b.Normal.X = right.Y * b.Axis.Z - right.Z * b.Axis.Y;
                b.Normal.Y = right.Z * b.Axis.X - right.X * b.Axis.Z;
                b.Normal.Z = right.X * b.Axis.Y - right.Y * b.Axis.X;

                // No need to normalize because right and up are normalized and perpendicular.
            }
            else
            {
                // Make sure axis is perpendicular to normal and right.
                //b.Axis = Vector3.Cross(b.Normal, right);
                // Inlined:
                b.Axis.X = b.Normal.Y * right.Z - b.Normal.Z * right.Y;
                b.Axis.Y = b.Normal.Z * right.X - b.Normal.X * right.Z;
                b.Axis.Z = b.Normal.X * right.Y - b.Normal.Y * right.X;

                // No need to normalize because normal and right are normalized and perpendicular.
            }



            Vector3 upRotated;
            Vector3 rightRotated;

            if (b.Angle != 0.0f)
            {
                // Rotate up and right.
                // Here is the readable code.
                //Matrix rotation = Matrix.CreateRotation(b.Normal, b.Angle);
                //Vector3 upRotated = rotation * b.Axis;
                //Vector3 rightRotated = rotation * right;

                // Inlined code:
                float x           = b.Normal.X;
                float y           = b.Normal.Y;
                float z           = b.Normal.Z;
                float x2          = x * x;
                float y2          = y * y;
                float z2          = z * z;
                float xy          = x * y;
                float xz          = x * z;
                float yz          = y * z;
                float cos         = (float)Math.Cos(b.Angle);
                float sin         = (float)Math.Sin(b.Angle);
                float xsin        = x * sin;
                float ysin        = y * sin;
                float zsin        = z * sin;
                float oneMinusCos = 1.0f - cos;
                float m00         = x2 + cos * (1.0f - x2);
                float m01         = xy * oneMinusCos - zsin;
                float m02         = xz * oneMinusCos + ysin;
                float m10         = xy * oneMinusCos + zsin;
                float m11         = y2 + cos * (1.0f - y2);
                float m12         = yz * oneMinusCos - xsin;
                float m20         = xz * oneMinusCos - ysin;
                float m21         = yz * oneMinusCos + xsin;
                float m22         = z2 + cos * (1.0f - z2);

                upRotated.X = m00 * b.Axis.X + m01 * b.Axis.Y + m02 * b.Axis.Z;
                upRotated.Y = m10 * b.Axis.X + m11 * b.Axis.Y + m12 * b.Axis.Z;
                upRotated.Z = m20 * b.Axis.X + m21 * b.Axis.Y + m22 * b.Axis.Z;

                rightRotated.X = m00 * right.X + m01 * right.Y + m02 * right.Z;
                rightRotated.Y = m10 * right.X + m11 * right.Y + m12 * right.Z;
                rightRotated.Z = m20 * right.X + m21 * right.Y + m22 * right.Z;
            }
            else
            {
                // Angle is 0 - no rotation.
                upRotated    = b.Axis;
                rightRotated = right;
            }



            Vector2F texCoordTopLeft     = texture.GetTextureCoordinates(Vector2F.Zero, b.AnimationTime);
            Vector2F texCoordBottomRight = texture.GetTextureCoordinates(Vector2F.One, b.AnimationTime);

            // Handle mirroring.
            if (b.Size.X < 0)
            {
                b.Size.X = -b.Size.X;
                MathHelper.Swap(ref texCoordTopLeft.X, ref texCoordBottomRight.X);
            }
            if (b.Size.Y < 0)
            {
                b.Size.Y = -b.Size.Y;
                MathHelper.Swap(ref texCoordTopLeft.Y, ref texCoordBottomRight.Y);
            }

            b.Size.X /= 2.0f;
            b.Size.Y /= 2.0f;

            // Offset from billboard center to right edge.
            Vector3 hOffset;

            hOffset.X = rightRotated.X * b.Size.X;
            hOffset.Y = rightRotated.Y * b.Size.X;
            hOffset.Z = rightRotated.Z * b.Size.X;

            // Offset from reference point to top edge.
            Vector3 vOffset;

            vOffset.X = upRotated.X * b.Size.Y;
            vOffset.Y = upRotated.Y * b.Size.Y;
            vOffset.Z = upRotated.Z * b.Size.Y;



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

                // Apply blend mode (0 = additive, 1 = alpha blend).
                W = b.Alpha * b.BlendMode
            };

            var color = new Color(color4);



            // Bottom left vertex
            vertices[index].Position.X          = b.Position.X - hOffset.X - vOffset.X;
            vertices[index].Position.Y          = b.Position.Y - hOffset.Y - vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z - hOffset.Z - vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordTopLeft.X;
            vertices[index].TextureCoordinate.Y = texCoordBottomRight.Y;
            index++;

            // Top left vertex
            vertices[index].Position.X          = b.Position.X - hOffset.X + vOffset.X;
            vertices[index].Position.Y          = b.Position.Y - hOffset.Y + vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z - hOffset.Z + vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordTopLeft.X;
            vertices[index].TextureCoordinate.Y = texCoordTopLeft.Y;
            index++;

            // Top right vertex
            vertices[index].Position.X          = b.Position.X + hOffset.X + vOffset.X;
            vertices[index].Position.Y          = b.Position.Y + hOffset.Y + vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z + hOffset.Z + vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordBottomRight.X;
            vertices[index].TextureCoordinate.Y = texCoordTopLeft.Y;
            index++;

            // Bottom right vertex
            vertices[index].Position.X          = b.Position.X + hOffset.X - vOffset.X;
            vertices[index].Position.Y          = b.Position.Y + hOffset.Y - vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z + hOffset.Z - vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordBottomRight.X;
            vertices[index].TextureCoordinate.Y = texCoordBottomRight.Y;
        }