Пример #1
0
        /// <summary>
        /// Updates the bounding shape of the proxy node.
        /// </summary>
        /// <remarks>
        /// The bounding shape needs to be large enough to contain all referenced nodes.
        /// </remarks>
        private void UpdateBoundingShape()
        {
            if (_node == null)
            {
                Shape = Shape.Empty;
                return;
            }

            // Traverse subtree and calculate AABB.
            Aabb?aabb = _node.GetSubtreeAabb();

            if (aabb.HasValue)
            {
                Vector3F extent = aabb.Value.Extent;
                if (float.IsInfinity(extent.X) || float.IsInfinity(extent.Y) || float.IsInfinity(extent.Z))
                {
                    // The extent of the subtree is infinite in one or more dimensions.
                    Shape = Shape.Infinite;
                }
                else
                {
                    // The subtree has finite size.
                    Shape = GetBoundingShape(aabb.Value);
                }
            }
            else
            {
                // The subtree is empty.
                Shape = Shape.Empty;
            }
        }
Пример #2
0
        /// <summary>
        /// Gets the AABB of the current subtree.
        /// </summary>
        /// <param name="sceneNode">The scene node (= root of subtree).</param>
        /// <param name="aabb">
        /// The AABB of the subtree rooted at <paramref name="sceneNode"/>, or <see langword="null"/> if
        /// the subtree is empty. If the input parameter is non-null, the method grows the specified
        /// AABB to include the subtree.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the extent of the current subtree is infinite in one or more
        /// dimensions; otherwise, <see langword="false"/> if the subtree is empty or has finite size.
        /// </returns>
        internal static bool GetSubtreeAabbInternal(SceneNode sceneNode, ref Aabb?aabb)
        {
            Debug.Assert(sceneNode != null, "sceneNode must not be null.");

            if (sceneNode.Shape is InfiniteShape)
            {
                return(true);
            }

            if (!(sceneNode.Shape is EmptyShape))
            {
                if (aabb.HasValue)
                {
                    aabb.Value.Grow(sceneNode.Aabb);
                }
                else
                {
                    aabb = sceneNode.Aabb;
                }
            }

            if (sceneNode.Children != null)
            {
                foreach (var childNode in sceneNode.Children)
                {
                    if (GetSubtreeAabbInternal(childNode, ref aabb))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #3
0
        public static Aabb?GetSubtreeAabb(this SceneNode sceneNode)
        {
            if (sceneNode == null)
            {
                return(null);
            }

            Aabb?aabb = null;

            if (GetSubtreeAabbInternal(sceneNode, ref aabb))
            {
                // The extent of subtree is infinite in one or more dimensions.
                aabb = new Aabb(new Vector3F(float.NegativeInfinity), new Vector3F(float.PositiveInfinity));
            }

            return(aabb);
        }
Пример #4
0
        /// <inheritdoc/>
        protected override void CloneCore(Shadow source)
        {
            // Clone Shadow properties.
            base.CloneCore(source);

            // Clone CascadedShadow properties.
            var sourceTyped = (VarianceShadow)source;

            MinLightDistance       = sourceTyped.MinLightDistance;
            MaxDistance            = sourceTyped.MaxDistance;
            FadeOutRange           = sourceTyped.FadeOutRange;
            ShadowFog              = sourceTyped.ShadowFog;
            Filter                 = sourceTyped.Filter;
            IsLocked               = sourceTyped.IsLocked;
            MinVariance            = sourceTyped.MinVariance;
            LightBleedingReduction = sourceTyped.LightBleedingReduction;
            TargetArea             = sourceTyped.TargetArea;

            // ShadowMap is not cloned!
        }
Пример #5
0
        /// <inheritdoc/>
        protected override void CloneCore(Light source)
        {
            // Clone Light properties.
            base.CloneCore(source);

            // Clone ImageBasedLight properties.
            var sourceTyped = (ImageBasedLight)source;

            Color                     = sourceTyped.Color;
            DiffuseIntensity          = sourceTyped.DiffuseIntensity;
            SpecularIntensity         = sourceTyped.SpecularIntensity;
            HdrScale                  = sourceTyped.HdrScale;
            Shape                     = sourceTyped.Shape.Clone();
            Texture                   = sourceTyped.Texture;
            Encoding                  = sourceTyped.Encoding;
            BlendMode                 = sourceTyped.BlendMode;
            FalloffRange              = sourceTyped.FalloffRange;
            EnableLocalizedReflection = sourceTyped.EnableLocalizedReflection;
            LocalizedReflectionBox    = sourceTyped.LocalizedReflectionBox;
        }
Пример #6
0
        /// <summary>
        /// Updates the bounding shape of the <see cref="LodGroupNode"/>. (Called automatically by the
        /// <see cref="LodCollection"/>.)
        /// </summary>
        /// <remarks>
        /// This method sets a <see cref="Shape"/> that is large enough to contain all LODs.
        /// </remarks>
        internal void UpdateBoundingShape()
        {
            if (_suppressUpdates)
            {
                return;
            }

            // Traverse LODs and calculate AABB.
            Aabb?aabb       = null;
            bool isInfinite = false;

            Levels.SetPose(Pose.Identity); // AABB has to be relative to local space!
            Levels.SetScale(Vector3.One);  // AABB has to be relative to local space!
            foreach (var lod in Levels)
            {
                isInfinite |= SceneHelper.GetSubtreeAabbInternal(lod.Node, ref aabb);
            }
            Levels.SetPose(PoseWorld);
            Levels.SetScale(ScaleWorld);

            if (isInfinite)
            {
                // The extent of the subtree is infinite in one or more dimensions.
                Shape = Shape.Infinite;
            }
            else if (aabb.HasValue)
            {
                // The subtree has finite size.
                Shape = GetBoundingShape(aabb.Value);
            }
            else
            {
                // No LODs or LODs are empty.
                Shape = Shape.Empty;
            }
        }
Пример #7
0
    /// <inheritdoc/>
    protected override void CloneCore(Shadow source)
    {
      // Clone Shadow properties.
      base.CloneCore(source);

      // Clone CascadedShadow properties.
      var sourceTyped = (VarianceShadow)source;
      MinLightDistance = sourceTyped.MinLightDistance;
      MaxDistance = sourceTyped.MaxDistance;
      FadeOutRange = sourceTyped.FadeOutRange;
      ShadowFog = sourceTyped.ShadowFog;
      Filter = sourceTyped.Filter;
      IsLocked = sourceTyped.IsLocked;
      MinVariance = sourceTyped.MinVariance;
      LightBleedingReduction = sourceTyped.LightBleedingReduction;
      TargetArea = sourceTyped.TargetArea;

      // ShadowMap is not cloned!
    }
        private Ragdoll CreateRagdoll(MeshNode meshNode)
        {
            var mesh     = meshNode.Mesh;
            var skeleton = mesh.Skeleton;

            // Extract the vertices from the mesh sorted per bone.
            var verticesPerBone = new List <Vector3F> [skeleton.NumberOfBones];
            // Also get the AABB of the model.
            Aabb?aabb = null;

            foreach (var submesh in mesh.Submeshes)
            {
                // Get vertex element info.
                var vertexDeclaration = submesh.VertexBuffer.VertexDeclaration;
                var vertexElements    = vertexDeclaration.GetVertexElements();

                // Get the vertex positions.
                var positionElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.Position);
                if (positionElement.VertexElementFormat != VertexElementFormat.Vector3)
                {
                    throw new NotSupportedException("For vertex positions only VertexElementFormat.Vector3 is supported.");
                }
                var positions = new Vector3[submesh.VertexCount];
                submesh.VertexBuffer.GetData(
                    submesh.StartVertex * vertexDeclaration.VertexStride + positionElement.Offset,
                    positions,
                    0,
                    submesh.VertexCount,
                    vertexDeclaration.VertexStride);

                // Get the bone indices.
                var boneIndexElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.BlendIndices);
                if (boneIndexElement.VertexElementFormat != VertexElementFormat.Byte4)
                {
                    throw new NotSupportedException();
                }
                var boneIndicesArray = new Byte4[submesh.VertexCount];
                submesh.VertexBuffer.GetData(
                    submesh.StartVertex * vertexDeclaration.VertexStride + boneIndexElement.Offset,
                    boneIndicesArray,
                    0,
                    submesh.VertexCount,
                    vertexDeclaration.VertexStride);

                // Get the bone weights.
                var boneWeightElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.BlendWeight);
                if (boneWeightElement.VertexElementFormat != VertexElementFormat.Vector4)
                {
                    throw new NotSupportedException();
                }
                var boneWeightsArray = new Vector4[submesh.VertexCount];
                submesh.VertexBuffer.GetData(
                    submesh.StartVertex * vertexDeclaration.VertexStride + boneWeightElement.Offset,
                    boneWeightsArray,
                    0,
                    submesh.VertexCount,
                    vertexDeclaration.VertexStride);

                // Sort the vertices per bone.
                for (int i = 0; i < submesh.VertexCount; i++)
                {
                    var vertex = (Vector3F)positions[i];

                    // Here, we only check the first bone index. We could also check the
                    // bone weights to add the vertex to all bone vertex lists where the
                    // weight is high...
                    Vector4 boneIndices = boneIndicesArray[i].ToVector4();
                    //Vector4 boneWeights = boneWeightsArray[i];
                    int boneIndex = (int)boneIndices.X;
                    if (verticesPerBone[boneIndex] == null)
                    {
                        verticesPerBone[boneIndex] = new List <Vector3F>();
                    }
                    verticesPerBone[boneIndex].Add(vertex);

                    // Add vertex to AABB.
                    if (aabb == null)
                    {
                        aabb = new Aabb(vertex, vertex);
                    }
                    else
                    {
                        aabb.Value.Grow(vertex);
                    }
                }
            }

            // We create a body for each bone with vertices.
            int numberOfBodies = verticesPerBone.Count(vertices => vertices != null);

            // We use the same mass properties for all bodies. This is not realistic but more stable
            // because large mass differences or thin bodies (arms!) are less stable.
            // We use the mass properties of sphere proportional to the size of the model.
            const float totalMass = 80; // The total mass of the ragdoll.
            var         massFrame = MassFrame.FromShapeAndMass(new SphereShape(aabb.Value.Extent.Y / 8), Vector3F.One, totalMass / numberOfBodies, 0.1f, 1);

            var material = new UniformMaterial();

            Ragdoll ragdoll = new Ragdoll();

            for (int boneIndex = 0; boneIndex < skeleton.NumberOfBones; boneIndex++)
            {
                var boneVertices = verticesPerBone[boneIndex];
                if (boneVertices != null)
                {
                    var bindPoseInverse = (Pose)skeleton.GetBindPoseAbsoluteInverse(boneIndex);

                    // Compute bounding capsule.
                    //float radius;
                    //float height;
                    //Pose pose;
                    //GeometryHelper.ComputeBoundingCapsule(boneVertices, out radius, out height, out pose);
                    //Shape shape = new TransformedShape(new GeometricObject(new CapsuleShape(radius, height), pose));

                    // Compute convex hull.
                    var   points = GeometryHelper.CreateConvexHull(boneVertices, 32, 0).ToTriangleMesh().Vertices;
                    Shape shape  = new ConvexHullOfPoints(points.Count > 0 ? points : boneVertices);

                    ragdoll.Bodies.Add(new RigidBody(shape, massFrame, material));
                    ragdoll.BodyOffsets.Add(bindPoseInverse);
                }
                else
                {
                    ragdoll.Bodies.Add(null);
                    ragdoll.BodyOffsets.Add(Pose.Identity);
                }
            }

            return(ragdoll);
        }
Пример #9
0
 public bool Equals(Aabb?other)
 {
     return(other != null && Min.Equals(other.Min) && Max.Equals(other.Max));
 }