예제 #1
0
        private void GetOctreeBounding(List <OctreeBounding> boundings, PolygonOctree octree, Vector3 cubePosition, float cubeSize)
        {
            OctreeBounding bounding = new OctreeBounding();

            bounding.Position = cubePosition;
            bounding.Size     = cubeSize;
            bounding.Octree   = octree;
            boundings.Add(bounding);

            if (octree.Children != null)
            {
                float childCubeSize = cubeSize / 2f;
                int   i             = 0;
                for (int z = 0; z < 2; z++)
                {
                    for (int y = 0; y < 2; y++)
                    {
                        for (int x = 0; x < 2; x++)
                        {
                            Vector3 childCubePosition = cubePosition + childCubeSize * new Vector3(x, y, z);
                            GetOctreeBounding(boundings, octree.Children[i++], childCubePosition, childCubeSize);
                        }
                    }
                }
            }
        }
예제 #2
0
 private int GetPolygonOctreeDepth(PolygonOctree octree, Vector3 cubePosition, float cubeSize, int depth = 0)
 {
     if (octree.Children != null)
     {
         float childCubeSize = cubeSize / 2f;
         int   i             = 0;
         for (int z = 0; z < 2; z++)
         {
             for (int y = 0; y < 2; y++)
             {
                 for (int x = 0; x < 2; x++)
                 {
                     Vector3 childCubePosition = cubePosition + childCubeSize * new Vector3(x, y, z);
                     return(GetPolygonOctreeDepth(octree.Children[i++], childCubePosition, childCubeSize, depth + 1));
                 }
             }
         }
     }
     return(depth);
 }
예제 #3
0
        // ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------

        internal void Read(BinaryDataReader reader, FileVersion version)
        {
            Version = version;

            long modelPosition       = reader.Position;
            int  positionArrayOffset = reader.ReadInt32();
            int  normalArrayOffset   = reader.ReadInt32();
            int  prismArrayOffset    = reader.ReadInt32();
            int  octreeOffset        = reader.ReadInt32();

            if (version == FileVersion.VersionDS)
            {
                PrismThickness    = reader.ReadFx32();
                MinCoordinate     = reader.ReadVector3Fx32();
                CoordinateMask    = reader.ReadVector3U();
                CoordinateShift   = reader.ReadVector3U();
                SphereRadius      = reader.ReadFx32();
                prismArrayOffset += 0x10;

                // Read the positions.
                reader.Position = modelPosition + positionArrayOffset; // Mostly unrequired, data is successive.
                int positionCount = (normalArrayOffset - positionArrayOffset) / 12;
                Positions = new List <Vector3>(reader.ReadVector3Fx32s(positionCount));

                // Read the normals.
                reader.Position = modelPosition + normalArrayOffset; // Mostly unrequired, data is successive.
                int normalCount = (prismArrayOffset - normalArrayOffset) / 6;
                Normals = new List <Vector3>(reader.ReadVector3Fx16s(normalCount));

                // Read the Prisms.
                reader.Position = modelPosition + prismArrayOffset; // Mostly unrequired, data is successive.
                int PrismCount = (octreeOffset - prismArrayOffset) / (version >= FileVersion.Version2 ? 20 : 16);
                Prisms = reader.ReadPrisms(PrismCount, version);
            }
            else
            {
                PrismThickness  = reader.ReadSingle();
                MinCoordinate   = reader.ReadVector3F();
                CoordinateMask  = reader.ReadVector3U();
                CoordinateShift = reader.ReadVector3U();
                if (positionArrayOffset > 56) //Older versions don't have the sphere radius property
                {
                    SphereRadius = reader.ReadSingle();
                }

                if (version < FileVersion.Version2) //octree triangle indices are -1 indexed. Shift the offset value.
                {
                    prismArrayOffset += 0x10;
                }

                // Read the positions.
                reader.Position = modelPosition + positionArrayOffset; // Mostly unrequired, data is successive.
                int positionCount = (normalArrayOffset - positionArrayOffset) / 12;
                Positions = new List <Vector3>(reader.ReadVector3Fs(positionCount));

                // Read the normals.
                reader.Position = modelPosition + normalArrayOffset; // Mostly unrequired, data is successive.
                int normalCount = (prismArrayOffset - normalArrayOffset) / 12;
                Normals = new List <Vector3>(reader.ReadVector3Fs(normalCount));

                // Read the prisms.
                reader.Position = modelPosition + prismArrayOffset; // Mostly unrequired, data is successive.
                int PrismCount = (octreeOffset - prismArrayOffset) / (version >= FileVersion.Version2 ? 20 : 16);
                Prisms = reader.ReadPrisms(PrismCount, version);
            }

            reader.Position = modelPosition + octreeOffset; // Mostly unrequired, data is successive.
            int nodeCount
                = ((~(int)CoordinateMask.X >> (int)CoordinateShift.X) + 1)
                  * ((~(int)CoordinateMask.Y >> (int)CoordinateShift.X) + 1)
                  * ((~(int)CoordinateMask.Z >> (int)CoordinateShift.X) + 1);

            PolygonOctreeRoots = new PolygonOctree[nodeCount];
            for (int i = 0; i < nodeCount; i++)
            {
                PolygonOctreeRoots[i] = new PolygonOctree(reader, modelPosition + octreeOffset, version);
            }
        }
예제 #4
0
        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");
        }