Example #1
0
 /// <summary>
 /// Reads <see cref="Vector3"/> 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="Vector3"/> instances.</returns>
 internal static Vector3U[] ReadVector3s(this BinaryDataReader self, int count)
 {
     Vector3U[] values = new Vector3U[count];
     for (int i = 0; i < count; i++)
     {
         values[i] = ReadVector3U(self);
     }
     return(values);
 }
        /// <summary>
        /// Replaces the current collision model from the given
        /// <paramref name="objModel"/>.
        /// </summary>
        /// <param name="objModel">The <see cref="ObjModel"/> to create the collision data from.</param>
        public void Replace(List <Triangle> triangles, CollisionImportSettings settings)
        {
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            // Find the smallest and biggest coordinate (and add padding).
            Vector3 minCoordinate = new Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue);
            Vector3 maxCoordinate = new Vector3(Single.MinValue, Single.MinValue, Single.MinValue);

            DebugLogger.WriteLine($"Replacing Collision...");

            DebugLogger.WriteLine($"Settings:");
            DebugLogger.WriteLine($"-MaxRootSize {settings.MaxRootSize}");
            DebugLogger.WriteLine($"-MaxTrianglesInCube {settings.MaxTrianglesInCube}");
            DebugLogger.WriteLine($"-MinCubeSize {settings.MinCubeSize}");
            DebugLogger.WriteLine($"-PaddingMax {settings.PaddingMax}");
            DebugLogger.WriteLine($"-PaddingMin {settings.PaddingMin}");
            DebugLogger.WriteLine($"-PrismThickness {settings.PrismThickness}");
            DebugLogger.WriteLine($"-SphereRadius {settings.SphereRadius}");

            DebugLogger.WriteLine($"Calculating bounding sizes...");

            for (int i = 0; i < triangles.Count; i++)
            {
                for (int v = 0; v < triangles[i].Vertices.Length; v++)
                {
                    Vector3 position = triangles[i].Vertices[v];
                    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);
                }
            }

            MinCoordinate = minCoordinate + settings.PaddingMin;
            MaxCoordinate = maxCoordinate + settings.PaddingMax;

            DebugLogger.WriteLine($"MinCoordinate: {MinCoordinate}");
            DebugLogger.WriteLine($"MaxCoordinate: {MaxCoordinate}");

            // Compute square cube size of the world, and with it the coordinate shift for use with the model octree.
            Vector3 size           = MaxCoordinate - MinCoordinate;
            int     worldLengthExp = Maths.GetNext2Exponent(Math.Min(Math.Min(size.X, size.Y), size.Z));
            int     cubeSize       = 1 << worldLengthExp;
            Vector3 exponents      = new Vector3(
                Maths.GetNext2Exponent(size.X),
                Maths.GetNext2Exponent(size.Y),
                Maths.GetNext2Exponent(size.Z));

            CoordinateShift = new Vector3U(
                (uint)(exponents.X),
                (uint)(exponents.Y),
                (uint)(exponents.Z));

            Models = new List <KCLModel>();
            Vector3 boxSize = new Vector3(
                1 << (int)CoordinateShift.X,
                    1 << (int)CoordinateShift.Y,
                    1 << (int)CoordinateShift.Z);

            DebugLogger.WriteLine($"Model Octree Bounds: {boxSize}");

            //Create subdivied triangle models
            var modelRoots = CreateModelDivision(MinCoordinate, triangles, boxSize / 2f);

            //For a model octree, we need 8 octrees per division
            ModelOctreeRoot          = new ModelOctreeNode();
            ModelOctreeRoot.Children = new ModelOctreeNode[ModelOctreeNode.ChildCount];
            for (int i = 0; i < ModelOctreeNode.ChildCount; i++)
            {
                ModelOctreeRoot.Children[i] = new ModelOctreeNode();
            }
            Models.Clear();

            //Load all the model data
            CreateModelOctree(modelRoots, ModelOctreeRoot.Children, settings, 0);
            PrismCount = Models.Sum(x => x.Prisms.Length);

            stopWatch.Stop();

            DebugLogger.WriteLine($"Model Octree:");
            PrintModelOctree(ModelOctreeRoot.Children);

            DebugLogger.WriteLine($"Finished Collsion Generation {stopWatch.Elapsed}");
        }
Example #3
0
 /// <summary>
 /// Writes a <see cref="Vector3"/> instance into the current stream.
 /// </summary>
 /// <param name="self">The extended <see cref="BinaryDataWriter"/>.</param>
 /// <param name="value">The <see cref="Vector3"/> instance.</param>
 internal static void Write(this BinaryDataWriter self, Vector3U value)
 {
     self.Write(value.X);
     self.Write(value.Y);
     self.Write(value.Z);
 }
        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");
        }