/// <summary> /// Initializes a new instance of the TerrainShape class. /// </summary> /// <param name="heights">An array containing the heights of the terrain surface.</param> /// <param name="scaleX">The x-scale factor. (The x-space between neighbour heights)</param> /// <param name="scaleZ">The y-scale factor. (The y-space between neighbour heights)</param> public TerrainShape(float[,] heights, float scaleX, float scaleZ) { heightsLength0 = heights.GetLength(0); heightsLength1 = heights.GetLength(1); #region Bounding Box boundings = JBBox.SmallBox; for (int i = 0; i < heightsLength0; i++) { for (int e = 0; e < heightsLength1; e++) { if (heights[i, e] > boundings.Max.Y) boundings.Max.Y = heights[i, e]; else if (heights[i, e] < boundings.Min.Y) boundings.Min.Y = heights[i, e]; } } boundings.Min.X = 0.0f; boundings.Min.Z = 0.0f; boundings.Max.X = checked(heightsLength0 * scaleX); boundings.Max.Z = checked(heightsLength1 * scaleZ); #endregion this.heights = heights; this.scaleX = scaleX; this.scaleZ = scaleZ; UpdateShape(); }
/// <summary> /// Calculates the bounding box of the sphere. /// </summary> /// <param name="orientation">The orientation of the shape.</param> /// <param name="box">The resulting axis aligned bounding box.</param> public override void GetBoundingBox(ref JMatrix orientation, out JBBox box) { box.Min.X = -radius; box.Min.Y = -radius; box.Min.Z = -radius; box.Max.X = radius; box.Max.Y = radius; box.Max.Z = radius; }
/// <summary> /// Gets the axis aligned bounding box of the orientated shape. This includes /// the whole shape. /// </summary> /// <param name="orientation">The orientation of the shape.</param> /// <param name="box">The axis aligned bounding box of the shape.</param> public override void GetBoundingBox(ref JMatrix orientation, out JBBox box) { JBBox helpBox = JBBox.LargeBox; int length = this.Prepare(ref helpBox); box = JBBox.SmallBox; for (int i = 0; i < length; i++) { this.SetCurrentShape(i); base.GetBoundingBox(ref orientation, out helpBox); JBBox.CreateMerged(ref box, ref helpBox, out box); } }
/// <summary> /// Passes a axis aligned bounding box to the shape where collision /// could occour. /// </summary> /// <param name="box">The bounding box where collision could occur.</param> /// <returns>The upper index with which <see cref="SetCurrentShape"/> can be /// called.</returns> public override int Prepare(ref JBBox box) { potentialTriangles.Clear(); #region Expand Spherical JBBox exp = box; exp.Min.X -= sphericalExpansion; exp.Min.Y -= sphericalExpansion; exp.Min.Z -= sphericalExpansion; exp.Max.X += sphericalExpansion; exp.Max.Y += sphericalExpansion; exp.Max.Z += sphericalExpansion; #endregion octree.GetTrianglesIntersectingtAABox(potentialTriangles, ref exp); return potentialTriangles.Count; }
/// <summary> /// Passes a axis aligned bounding box to the shape where collision /// could occour. /// </summary> /// <param name="box">The bounding box where collision could occur.</param> /// <returns>The upper index with which <see cref="SetCurrentShape"/> can be /// called.</returns> public abstract int Prepare(ref JBBox box);
/// <summary> /// Uses the supportMapping to calculate the bounding box. Should be overidden /// to make this faster. /// </summary> /// <param name="orientation">The orientation of the shape.</param> /// <param name="box">The resulting axis aligned bounding box.</param> public virtual void GetBoundingBox(ref JMatrix orientation, out JBBox box) { // I don't think that this can be done faster. // 6 is the minimum number of SupportMap calls. JVector vec = JVector.Zero; vec.Set(orientation.M11, orientation.M21, orientation.M31); SupportMapping(ref vec, out vec); box.Max.X = orientation.M11 * vec.X + orientation.M21 * vec.Y + orientation.M31 * vec.Z; vec.Set(orientation.M12, orientation.M22, orientation.M32); SupportMapping(ref vec, out vec); box.Max.Y = orientation.M12 * vec.X + orientation.M22 * vec.Y + orientation.M32 * vec.Z; vec.Set(orientation.M13, orientation.M23, orientation.M33); SupportMapping(ref vec, out vec); box.Max.Z = orientation.M13 * vec.X + orientation.M23 * vec.Y + orientation.M33 * vec.Z; vec.Set(-orientation.M11, -orientation.M21, -orientation.M31); SupportMapping(ref vec, out vec); box.Min.X = orientation.M11 * vec.X + orientation.M21 * vec.Y + orientation.M31 * vec.Z; vec.Set(-orientation.M12, -orientation.M22, -orientation.M32); SupportMapping(ref vec, out vec); box.Min.Y = orientation.M12 * vec.X + orientation.M22 * vec.Y + orientation.M32 * vec.Z; vec.Set(-orientation.M13, -orientation.M23, -orientation.M33); SupportMapping(ref vec, out vec); box.Min.Z = orientation.M13 * vec.X + orientation.M23 * vec.Y + orientation.M33 * vec.Z; }
/// <summary> /// Gets the axis aligned bounding box of the orientated shape. This includes /// the whole shape. /// </summary> /// <param name="orientation">The orientation of the shape.</param> /// <param name="box">The axis aligned bounding box of the shape.</param> public override void GetBoundingBox(ref JMatrix orientation, out JBBox box) { box = octree.rootNodeBox; #region Expand Spherical box.Min.X -= sphericalExpansion; box.Min.Y -= sphericalExpansion; box.Min.Z -= sphericalExpansion; box.Max.X += sphericalExpansion; box.Max.Y += sphericalExpansion; box.Max.Z += sphericalExpansion; #endregion box.Transform(ref orientation); }
/// <summary> /// Passes a axis aligned bounding box to the shape where collision /// could occour. /// </summary> /// <param name="box">The bounding box where collision could occur.</param> /// <returns>The upper index with which <see cref="SetCurrentShape"/> can be /// called.</returns> public override int Prepare(ref JBBox box) { // simple idea: the terrain is a grid. x and z is the position in the grid. // y the height. we know compute the min and max grid-points. All quads // between these points have to be checked. // including overflow exception prevention if (box.Min.X < boundings.Min.X) minX = 0; else { minX = (int)Math.Floor((float)((box.Min.X - sphericalExpansion) / scaleX)); minX = Math.Max(minX, 0); } if (box.Max.X > boundings.Max.X) maxX = heightsLength0 - 1; else { maxX = (int)Math.Ceiling((float)((box.Max.X + sphericalExpansion) / scaleX)); maxX = Math.Min(maxX, heightsLength0 - 1); } if (box.Min.Z < boundings.Min.Z) minZ = 0; else { minZ = (int)Math.Floor((float)((box.Min.Z - sphericalExpansion) / scaleZ)); minZ = Math.Max(minZ, 0); } if (box.Max.Z > boundings.Max.Z) maxZ = heightsLength1 - 1; else { maxZ = (int)Math.Ceiling((float)((box.Max.Z + sphericalExpansion) / scaleZ)); maxZ = Math.Min(maxZ, heightsLength1 - 1); } numX = maxX - minX; numZ = maxZ - minZ; // since every quad contains two triangles we multiply by 2. return numX * numZ * 2; }
/// <summary> /// Creates a new instance of the TransformedShape struct. /// </summary> /// <param name="shape">The shape.</param> /// <param name="orientation">The orientation this shape should have.</param> /// <param name="position">The position this shape should have.</param> public TransformedShape(Shape shape, JMatrix orientation, JVector position) { this.position = position; this.orientation = orientation; JMatrix.Transpose(ref orientation, out invOrientation); this.shape = shape; this.boundingBox = new JBBox(); UpdateBoundingBox(); }
/// <summary> /// Create a bounding box appropriate for a child, based on a parents AABox /// </summary> /// <param name="aabb"></param> /// <param name="child"></param> /// <param name="result"></param> #region private void CreateAABox(ref JBBox aabb, EChild child,out JBBox result) private void CreateAABox(ref JBBox aabb, EChild child,out JBBox result) { JVector dims; JVector.Subtract(ref aabb.Max, ref aabb.Min, out dims); JVector.Multiply(ref dims, 0.5f, out dims); JVector offset = JVector.Zero; switch (child) { case EChild.PPP: offset = new JVector(1, 1, 1); break; case EChild.PPM: offset = new JVector(1, 1, 0); break; case EChild.PMP: offset = new JVector(1, 0, 1); break; case EChild.PMM: offset = new JVector(1, 0, 0); break; case EChild.MPP: offset = new JVector(0, 1, 1); break; case EChild.MPM: offset = new JVector(0, 1, 0); break; case EChild.MMP: offset = new JVector(0, 0, 1); break; case EChild.MMM: offset = new JVector(0, 0, 0); break; default: System.Diagnostics.Debug.WriteLine("Octree.CreateAABox got impossible child"); break; } result = new JBBox(); result.Min = new JVector(offset.X * dims.X, offset.Y * dims.Y, offset.Z * dims.Z); JVector.Add(ref result.Min, ref aabb.Min, out result.Min); JVector.Add(ref result.Min, ref dims, out result.Max); // expand it just a tiny bit just to be safe! float extra = 0.00001f; JVector temp; JVector.Multiply(ref dims, extra, out temp); JVector.Subtract(ref result.Min, ref temp, out result.Min); JVector.Add(ref result.Max, ref temp, out result.Max); }
/// <summary> /// Returns all triangles which intersect the given axis aligned bounding box. /// </summary> /// <param name="triangles">The list to add the triangles to.</param> /// <param name="testBox">The axis alignes bounding box.</param> /// <returns></returns> #region public int GetTrianglesIntersectingtAABox(List<int> triangles, ref JBBox testBox) public int GetTrianglesIntersectingtAABox(List<int> triangles, ref JBBox testBox) { if (nodes.Length == 0) return 0; int curStackIndex = 0; int endStackIndex = 1; UInt16[] nodeStack = nodeStackPool.GetNew(); nodeStack[0] = 0; int triCount = 0; while (curStackIndex < endStackIndex) { UInt16 nodeIndex = nodeStack[curStackIndex]; curStackIndex++; if (nodes[nodeIndex].box.Contains(ref testBox) != JBBox.ContainmentType.Disjoint) { for (int i = 0; i < nodes[nodeIndex].triIndices.Length; ++i) { if (triBoxes[nodes[nodeIndex].triIndices[i]].Contains(ref testBox) != JBBox.ContainmentType.Disjoint) { triangles.Add(nodes[nodeIndex].triIndices[i]); triCount++; } } int numChildren = nodes[nodeIndex].nodeIndices.Length; for (int i = 0; i < numChildren; ++i) { nodeStack[endStackIndex++] = nodes[nodeIndex].nodeIndices[i]; } } } nodeStackPool.GiveBack(nodeStack); return triCount; }
/// <summary> /// Passes a axis aligned bounding box to the shape where collision /// could occour. /// </summary> /// <param name="box">The bounding box where collision could occur.</param> /// <returns>The upper index with which <see cref="SetCurrentShape"/> can be /// called.</returns> public override int Prepare(ref JBBox box) { currentSubShapes.Clear(); for (int i = 0; i < shapes.Length; i++) { if (shapes[i].boundingBox.Contains(ref box) != JBBox.ContainmentType.Disjoint) currentSubShapes.Add(i); } return currentSubShapes.Count; }
/// <summary> /// Builds the octree. /// </summary> #region public void BuildOctree() public void BuildOctree() { // create tri and tri bounding box arrays triBoxes = new JBBox[tris.Length]; // create an infinite size root box rootNodeBox = new JBBox(new JVector(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity), new JVector(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity)); for (int i = 0; i < tris.Length; i++) { JVector.Min(ref positions[tris[i].I1], ref positions[tris[i].I2], out triBoxes[i].Min); JVector.Min(ref positions[tris[i].I0], ref triBoxes[i].Min, out triBoxes[i].Min); JVector.Max(ref positions[tris[i].I1], ref positions[tris[i].I2], out triBoxes[i].Max); JVector.Max(ref positions[tris[i].I0], ref triBoxes[i].Max, out triBoxes[i].Max); // get size of the root box JVector.Min(ref rootNodeBox.Min, ref triBoxes[i].Min, out rootNodeBox.Min); JVector.Max(ref rootNodeBox.Max, ref triBoxes[i].Max, out rootNodeBox.Max); } List<BuildNode> buildNodes = new List<BuildNode>(); buildNodes.Add(new BuildNode()); buildNodes[0].box = rootNodeBox; JBBox[] children = new JBBox[8]; for (int triNum = 0; triNum < tris.Length; triNum++) { int nodeIndex = 0; JBBox box = rootNodeBox; while (box.Contains(ref triBoxes[triNum]) == JBBox.ContainmentType.Contains) { int childCon = -1; for (int i = 0; i < 8; ++i) { CreateAABox(ref box, (EChild)i,out children[i]); if (children[i].Contains(ref triBoxes[triNum]) == JBBox.ContainmentType.Contains) { // this box contains the tri, it can be the only one that does, // so we can stop our child search now and recurse into it childCon = i; break; } } // no child contains this tri completely, so it belong in this node if (childCon == -1) { buildNodes[nodeIndex].triIndices.Add(triNum); break; } else { // do we already have this child int childIndex = -1; for (int index = 0; index < buildNodes[nodeIndex].nodeIndices.Count; ++index) { if (buildNodes[buildNodes[nodeIndex].nodeIndices[index]].childType == childCon) { childIndex = index; break; } } if (childIndex == -1) { // nope create child BuildNode parentNode = buildNodes[nodeIndex]; BuildNode newNode = new BuildNode(); newNode.childType = childCon; newNode.box = children[childCon]; buildNodes.Add(newNode); nodeIndex = buildNodes.Count - 1; box = children[childCon]; parentNode.nodeIndices.Add(nodeIndex); } else { nodeIndex = buildNodes[nodeIndex].nodeIndices[childIndex]; box = children[childCon]; } } } } // now convert to the tighter Node from BuildNodes nodes = new Node[buildNodes.Count]; nodeStackPool = new ArrayResourcePool<ushort>(buildNodes.Count); //nodeStack = new UInt16[buildNodes.Count]; for (int i = 0; i < nodes.Length; i++) { nodes[i].nodeIndices = new UInt16[buildNodes[i].nodeIndices.Count]; for (int index = 0; index < nodes[i].nodeIndices.Length; ++index) { nodes[i].nodeIndices[index] = (UInt16)buildNodes[i].nodeIndices[index]; } nodes[i].triIndices = new int[buildNodes[i].triIndices.Count]; buildNodes[i].triIndices.CopyTo(nodes[i].triIndices); nodes[i].box = buildNodes[i].box; } buildNodes.Clear(); buildNodes = null; }
/// <summary> /// Gets the axis aligned bounding box of the orientated shape. (Inlcuding all /// 'sub' shapes) /// </summary> /// <param name="orientation">The orientation of the shape.</param> /// <param name="box">The axis aligned bounding box of the shape.</param> public override void GetBoundingBox(ref JMatrix orientation, out JBBox box) { box.Min = mInternalBBox.Min; box.Max = mInternalBBox.Max; JVector localHalfExtents = 0.5f * (box.Max - box.Min); JVector localCenter = 0.5f * (box.Max + box.Min); JVector center; JVector.Transform(ref localCenter, ref orientation, out center); JMatrix abs; JMath.Absolute(ref orientation, out abs); JVector temp; JVector.Transform(ref localHalfExtents, ref abs, out temp); box.Max = center + temp; box.Min = center - temp; }
public void UpdateBoundingBox() { boundingBox = JBBox.SmallBox; boundingBox.AddPoint(ref owner.points[indices.I0].position); boundingBox.AddPoint(ref owner.points[indices.I1].position); boundingBox.AddPoint(ref owner.points[indices.I2].position); boundingBox.Min -= new JVector(owner.triangleExpansion); boundingBox.Max += new JVector(owner.triangleExpansion); }
/// <summary> /// Passes a axis aligned bounding box to the shape where collision /// could occour. /// </summary> /// <param name="box">The bounding box where collision could occur.</param> /// <returns>The upper index with which <see cref="SetCurrentShape"/> can be /// called.</returns> public override int Prepare(ref JBBox box) { return shapes.Length; }
/// <summary> /// Creates a new box containing the two given ones. /// </summary> /// <param name="original">First box.</param> /// <param name="additional">Second box.</param> /// <param name="result">A JBBox containing the two given boxes.</param> public static void CreateMerged(ref JBBox original, ref JBBox additional, out JBBox result) { JVector vector; JVector vector2; JVector.Min(ref original.Min, ref additional.Min, out vector2); JVector.Max(ref original.Max, ref additional.Max, out vector); result.Min = vector2; result.Max = vector; }
/// <summary> /// Creates a new box containing the two given ones. /// </summary> /// <param name="original">First box.</param> /// <param name="additional">Second box.</param> /// <returns>A JBBox containing the two given boxes.</returns> #region public static JBBox CreateMerged(JBBox original, JBBox additional) public static JBBox CreateMerged(JBBox original, JBBox additional) { JBBox result; JBBox.CreateMerged(ref original, ref additional, out result); return result; }
/// <summary> /// Checks whether another bounding box is inside, outside or intersecting /// this box. /// </summary> /// <param name="box">The other bounding box to check.</param> /// <returns>The ContainmentType of the box.</returns> public ContainmentType Contains(ref JBBox box) { ContainmentType result = ContainmentType.Disjoint; if ((((this.Max.X >= box.Min.X) && (this.Min.X <= box.Max.X)) && ((this.Max.Y >= box.Min.Y) && (this.Min.Y <= box.Max.Y))) && ((this.Max.Z >= box.Min.Z) && (this.Min.Z <= box.Max.Z))) { result = ((((this.Min.X <= box.Min.X) && (box.Max.X <= this.Max.X)) && ((this.Min.Y <= box.Min.Y) && (box.Max.Y <= this.Max.Y))) && ((this.Min.Z <= box.Min.Z) && (box.Max.Z <= this.Max.Z))) ? ContainmentType.Contains : ContainmentType.Intersects; } return result; }
/// <summary> /// Checks whether another bounding box is inside, outside or intersecting /// this box. /// </summary> /// <param name="box">The other bounding box to check.</param> /// <returns>The ContainmentType of the box.</returns> #region public ContainmentType Contains(JBBox box) public ContainmentType Contains(JBBox box) { return this.Contains(ref box); }
public virtual void Update(float timestep) { active = false; foreach (MassPoint point in points) { if (point.isActive && !point.isStatic) { active = true; break; } } if(!active) return; box = JBBox.SmallBox; volume = 0.0f; mass = 0.0f; foreach (MassPoint point in points) { mass += point.Mass; box.AddPoint(point.position); } box.Min -= new JVector(TriangleExpansion); box.Max += new JVector(TriangleExpansion); foreach (Triangle t in triangles) { // Update bounding box and move proxy in dynamic tree. JVector prevCenter = t.boundingBox.Center; t.UpdateBoundingBox(); JVector linVel = t.VertexBody1.linearVelocity + t.VertexBody2.linearVelocity + t.VertexBody3.linearVelocity; linVel *= 1.0f / 3.0f; dynamicTree.MoveProxy(t.dynamicTreeID, ref t.boundingBox, linVel * timestep); JVector v1 = points[t.indices.I0].position; JVector v2 = points[t.indices.I1].position; JVector v3 = points[t.indices.I2].position; volume -= ((v2.Y - v1.Y) * (v3.Z - v1.Z) - (v2.Z - v1.Z) * (v3.Y - v1.Y)) * (v1.X + v2.X + v3.X); } volume /= 6.0f; AddPressureForces(timestep); }
/// <summary> /// Gets the axis aligned bounding box of the orientated shape. /// </summary> /// <param name="orientation">The orientation of the shape.</param> /// <param name="box">The axis aligned bounding box of the shape.</param> public override void GetBoundingBox(ref JMatrix orientation, out JBBox box) { JMatrix abs; JMath.Absolute(ref orientation, out abs); JVector temp; JVector.Transform(ref halfSize, ref abs, out temp); box.Max = temp; JVector.Negate(ref temp, out box.Min); }