/// <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; } }
/// <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); }
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); }
/// <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! }
/// <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; }
/// <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; } }
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); }
public bool Equals(Aabb?other) { return(other != null && Min.Equals(other.Min) && Max.Equals(other.Max)); }