// ---- METHODS (PUBLIC) ------------------------------------------------------------------------------------- /// <summary> /// Creates a triangle with 3 positions from the given collision prism. /// </summary> /// <returns></returns> public Triangle GetTriangle(KclPrism prism) { Vector3 A = Positions[prism.PositionIndex]; Vector3 CrossA = Vector3.Cross(Normals[prism.Normal1Index], Normals[prism.DirectionIndex]); Vector3 CrossB = Vector3.Cross(Normals[prism.Normal2Index], Normals[prism.DirectionIndex]); Vector3 B = A + CrossB * (prism.Length / Vector3.Dot(CrossB, Normals[prism.Normal3Index])); Vector3 C = A + CrossA * (prism.Length / Vector3.Dot(CrossA, Normals[prism.Normal3Index])); return(new Triangle(A, B, C) { Attribute = prism.CollisionFlags }); }
// ---- METHODS (INTERNAL) ------------------------------------------------------------------------------------- /// <summary> /// Reads <see cref="KclFace"/> instances from the current stream and returns them. /// </summary> /// <param name="self">The extended <see cref="BinaryDataReader"/>.</param> /// <param name="count">The number of instances to read.</param> /// <returns>The <see cref="KclFace"/> instances.</returns> internal static KclPrism[] ReadPrisms(this BinaryDataReader self, int count, FileVersion version) { KclPrism[] values = new KclPrism[count]; for (int i = 0; i < count; i++) { values[i] = new KclPrism(); values[i].Read(self, version); if (version != FileVersion.Version2) //Manually set the global index for older versions { values[i].GlobalIndex = (ushort)i; } } return(values); }
public KCLModel(List <Triangle> triangleList, uint baseTriCount, FileVersion version, CollisionImportSettings settings) { // Transfer the faces to collision faces and find the smallest and biggest coordinates. Vector3 minCoordinate = new Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue); Vector3 maxCoordinate = new Vector3(Single.MinValue, Single.MinValue, Single.MinValue); List <KclPrism> prismList = new List <KclPrism>(); Dictionary <ushort, Triangle> triangles = new Dictionary <ushort, Triangle>(); Positions = new List <Vector3>(); Normals = new List <Vector3>(); Prisms = new KclPrism[0]; Version = version; PrismThickness = settings.PrismThickness; SphereRadius = settings.SphereRadius; Dictionary <string, int> positionTable = new Dictionary <string, int>(); Dictionary <string, int> normalTable = new Dictionary <string, int>(); ushort triindex = 0; for (int i = 0; i < triangleList.Count; i++) { var triangle = triangleList[i]; Vector3 direction = Vector3.Cross( triangle.Vertices[1] - triangle.Vertices[0], triangle.Vertices[2] - triangle.Vertices[0]); if ((direction.X * direction.X + direction.Y * direction.Y + direction.Z * direction.Z) < 0.01) { continue; } direction = Vector3.Normalize(direction); // Get the position vectors and find the smallest and biggest coordinates. for (int j = 0; j < 3; j++) { Vector3 position = triangle.Vertices[j]; minCoordinate.X = Math.Min(position.X, minCoordinate.X); minCoordinate.Y = Math.Min(position.Y, minCoordinate.Y); minCoordinate.Z = Math.Min(position.Z, minCoordinate.Z); maxCoordinate.X = Math.Max(position.X, maxCoordinate.X); maxCoordinate.Y = Math.Max(position.Y, maxCoordinate.Y); maxCoordinate.Z = Math.Max(position.Z, maxCoordinate.Z); } //Calculate the ABC normal values. Vector3 normalA = Vector3.Cross(direction, triangle.Vertices[2] - triangle.Vertices[0]); Vector3 normalB = (-(Vector3.Cross(direction, triangle.Vertices[1] - triangle.Vertices[0]))); Vector3 normalC = Vector3.Cross(direction, triangle.Vertices[1] - triangle.Vertices[2]); //Normalize the ABC normal values. normalA = Vector3.Normalize(normalA); normalB = Vector3.Normalize(normalB); normalC = Vector3.Normalize(normalC); //Create a KCL Prism KclPrism face = new KclPrism() { PositionIndex = (ushort)IndexOfVertex(triangle.Vertices[0], Positions, positionTable), DirectionIndex = (ushort)IndexOfVertex(direction, Normals, normalTable), Normal1Index = (ushort)IndexOfVertex(normalA, Normals, normalTable), Normal2Index = (ushort)IndexOfVertex(normalB, Normals, normalTable), Normal3Index = (ushort)IndexOfVertex(normalC, Normals, normalTable), GlobalIndex = baseTriCount + (uint)prismList.Count, CollisionFlags = triangle.Attribute, }; // Compute the face direction (normal) and add it to the normal list. triangles.Add((ushort)triindex++, triangle); //Compute the length float length = Vector3.Dot(triangle.Vertices[1] - triangle.Vertices[0], normalC); face.Length = length; prismList.Add(face); } positionTable.Clear(); normalTable.Clear(); //No triangles found to intersect the current box, return. if (prismList.Count == 0) { return; } //Padd the coordinates minCoordinate += settings.PaddingMin; maxCoordinate += settings.PaddingMax; MinCoordinate = minCoordinate; Prisms = prismList.ToArray(); // Compute the octree. Vector3 size = maxCoordinate - minCoordinate; Vector3U exponents = new Vector3U( (uint)Maths.GetNext2Exponent(size.X), (uint)Maths.GetNext2Exponent(size.Y), (uint)Maths.GetNext2Exponent(size.Z)); int cubeSizePower = Maths.GetNext2Exponent(Math.Min(Math.Min(size.X, size.Y), size.Z)); if (cubeSizePower > Maths.GetNext2Exponent(settings.MaxRootSize)) { cubeSizePower = Maths.GetNext2Exponent(settings.MaxRootSize); } int cubeSize = 1 << cubeSizePower; CoordinateShift = new Vector3U( (uint)cubeSizePower, (uint)(exponents.X - cubeSizePower), (uint)(exponents.X - cubeSizePower + exponents.Y - cubeSizePower)); CoordinateMask = new Vector3U( (uint)(0xFFFFFFFF << (int)exponents.X), (uint)(0xFFFFFFFF << (int)exponents.Y), (uint)(0xFFFFFFFF << (int)exponents.Z)); Vector3U cubeCounts = new Vector3U( (uint)Math.Max(1, (1 << (int)exponents.X) / cubeSize), (uint)Math.Max(1, (1 << (int)exponents.Y) / cubeSize), (uint)Math.Max(1, (1 << (int)exponents.Z) / cubeSize)); // Generate the root nodes, which are square cubes required to cover all of the model. PolygonOctreeRoots = new PolygonOctree[cubeCounts.X * cubeCounts.Y * cubeCounts.Z]; int cubeBlow = SphereRadius > 0 ? (int)(SphereRadius * 2) : 50; DebugLogger.WriteLine($"Octree Distance Bias {cubeBlow}"); DebugLogger.WriteLine($"Creating Octrees {cubeCounts}"); int index = 0; for (int z = 0; z < cubeCounts.Z; z++) { for (int y = 0; y < cubeCounts.Y; y++) { for (int x = 0; x < cubeCounts.X; x++) { Vector3 cubePosition = minCoordinate + ((float)cubeSize) * new Vector3(x, y, z); PolygonOctreeRoots[index++] = new PolygonOctree(triangles, cubePosition, cubeSize, settings.MaxTrianglesInCube, settings.MaxCubeSize, settings.MinCubeSize, cubeBlow, settings.MaxOctreeDepth); } } } DebugLogger.WriteLine($"Finished Octree"); }