示例#1
0
        public static IEnumerable <BigMesh> Split(BigMesh bigMesh)
        {
            var stripIndex = 0;
            var maxStrip   = bigMesh.triangleStripList.Count;

            while (stripIndex < maxStrip)
            {
                var smallMesh = new BigMesh
                {
                    textureIndex = bigMesh.textureIndex,
                    matDef       = bigMesh.matDef,
                };

                var localIndexMap = new Dictionary <int, int>();
                var countStocked  = 0;
                for (; stripIndex < maxStrip; stripIndex++)
                {
                    var triStrip = bigMesh.triangleStripList[stripIndex];

                    if (countStocked + triStrip.vertexIndices.Count > MaxVertCount)
                    {
                        break;
                    }

                    var newTriStrip = new BigMesh.TriangleStrip
                    {
                        uvList          = triStrip.uvList.ToList(),
                        vertexColorList = triStrip.vertexColorList.ToList(),
                        vertexIndices   = triStrip.vertexIndices
                                          .Select(gi => MapToLocal(localIndexMap, gi))
                                          .ToList(),
                    };

                    smallMesh.triangleStripList.Add(newTriStrip);

                    countStocked += newTriStrip.vertexIndices.Count;
                }

                var globalIndexMap = localIndexMap
                                     .ToDictionary(pair => pair.Value, pair => pair.Key);

                smallMesh.textureIndex = bigMesh.textureIndex;

                for (int loop = 0; loop < localIndexMap.Count; loop++)
                {
                    var globalIndex = globalIndexMap[loop];
                    smallMesh.vertexList.Add(bigMesh.vertexList[globalIndex]);
                }

                yield return(smallMesh);
            }
        }
示例#2
0
        private void ConvertModelIntoMapModel(string modelFile, MapGenConfig config)
        {
            logger.Debug($"Loading 3D model file \"{modelFile}\" using Assimp.");

            var assimp = new Assimp.AssimpContext();
            var scene  = assimp.ImportFile(modelFile, Assimp.PostProcessSteps.PreTransformVertices);

            bigMeshContainer = new BigMeshContainer();

            var scale = config.scale;

            Matrix4x4 matrix = Matrix4x4.Identity;

            if (config.applyMatrix != null)
            {
                var m = config.applyMatrix;

                if (m.Length == 16)
                {
                    matrix = new Matrix4x4(
                        m[0], m[1], m[2], m[3],
                        m[4], m[5], m[6], m[7],
                        m[8], m[9], m[10], m[11],
                        m[12], m[13], m[14], m[15]
                        );

                    logger.Debug($"Apply matrix: {matrix}");
                }
            }
            else
            {
                matrix *= scale;
            }

            logger.Debug($"Starting triangle strip conversion for {scene.Meshes.Count} meshes.");

            foreach (var inputMesh in scene.Meshes)
            {
                logger.Debug($"Mesh: {inputMesh.Name} ({inputMesh.FaceCount:#,##0} faces, {inputMesh.VertexCount:#,##0} vertices)");

                var modelMat = scene.Materials[inputMesh.MaterialIndex];

                var matDef = config.FindMaterial(modelMat.Name ?? "default") ?? MaterialDef.CreateFallbackFor(modelMat.Name);
                if (matDef.ignore)
                {
                    logger.Info($"This mesh \"{inputMesh.Name}\" is not rendered due to ignore flag of material \"{modelMat.Name}\".");
                    continue;
                }

                var kh2Mesh = bigMeshContainer.AllocateBigMeshForMaterial(matDef);

                var diffuseTextureFile = modelMat.TextureDiffuse.FilePath;
                if (!string.IsNullOrEmpty(diffuseTextureFile))
                {
                    if (config.reuseImd)
                    {
                        logger.Debug($"The mesh \"{inputMesh.Name}\" material \"{matDef.name}\" has filepath \"{diffuseTextureFile}\" for diffuse texture. It will be associated with material's fromFile3. Setting preferable imd file to fromFile2 due to reuseImd flag.");

                        matDef.fromFile2 = Path.ChangeExtension(diffuseTextureFile, ".imd");
                        matDef.fromFile3 = diffuseTextureFile;
                    }
                    else
                    {
                        logger.Debug($"The mesh \"{inputMesh.Name}\" material \"{matDef.name}\" has filepath \"{diffuseTextureFile}\" for diffuse texture. It will be associated with material's fromFile2.");

                        matDef.fromFile3 = diffuseTextureFile;
                    }
                }

                var kh2BaseVert = kh2Mesh.vertexList.Count;

                List <int> vertexToLocal = new List <int>();

                foreach (var inputVertex in inputMesh.Vertices)
                {
                    var vertex = Vector3.Transform(
                        new Vector3(inputVertex.X, inputVertex.Y, inputVertex.Z),
                        matrix
                        );

                    var index = kh2Mesh.vertexList.IndexOf(vertex);
                    if (index < 0)
                    {
                        index = kh2Mesh.vertexList.Count;
                        kh2Mesh.vertexList.Add(vertex);
                    }

                    vertexToLocal.Add(index);
                }

                var localFaces = inputMesh.Faces
                                 .Select(
                    set => set.Indices
                    .Select(index => new VertPair {
                    uvColorIndex = index, vertexIndex = vertexToLocal[index]
                })
                    .ToArray()
                    )
                                 .ToArray();

                var inputTexCoords       = inputMesh.TextureCoordinateChannels.First();
                var inputVertexColorList = inputMesh.VertexColorChannels.First();

                var hasVertexColor = inputMesh.VertexColorChannelCount >= 1;

                var maxIntensity = matDef.maxColorIntensity
                                   ?? config.maxColorIntensity
                                   ?? 128;
                var maxAlpha = matDef.maxAlpha
                               ?? config.maxAlpha
                               ?? 128;

                var triConverter =
                    config.disableTriangleStripsOptimization
                    ? (TriangleFansToTriangleStripsConverter)TriangleFansToTriangleStripsNoOpts
                    : (TriangleFansToTriangleStripsConverter)TriangleFansToTriangleStripsOptimized;

                foreach (var triStripInput in triConverter(localFaces))
                {
                    var triStripOut = new BigMesh.TriangleStrip();

                    foreach (var vertPair in triStripInput)
                    {
                        triStripOut.vertexIndices.Add(kh2BaseVert + vertPair.vertexIndex);

                        triStripOut.uvList.Add(Get2DCoord(inputTexCoords[vertPair.uvColorIndex]));

                        if (hasVertexColor)
                        {
                            triStripOut.vertexColorList.Add(ConvertVertexColor(inputVertexColorList[vertPair.uvColorIndex], maxIntensity, maxAlpha));
                        }
                        else
                        {
                            triStripOut.vertexColorList.Add(new Color(maxIntensity, maxIntensity, maxIntensity, maxAlpha));
                        }
                    }

                    kh2Mesh.triangleStripList.Add(triStripOut);
                }

                logger.Debug($"Output: {kh2Mesh.vertexList.Count:#,##0} vertices, {kh2Mesh.triangleStripList.Count:#,##0} triangle strips.");
            }

            logger.Debug($"The conversion has done.");

            logger.Debug($"Starting mesh splitter and vif packets builder.");

            mapModel = new Mdlx.M4
            {
                VifPackets = new List <Mdlx.VifPacketDescriptor>(),
            };

            foreach (var bigMesh in bigMeshContainer.MeshList
                     .Where(it => it.textureIndex != -1)
                     )
            {
                foreach (var smallMesh in BigMeshSplitter.Split(bigMesh))
                {
                    var dmaPack = new MapVifPacketBuilder(smallMesh);

                    smallMeshList.Add(smallMesh);

                    bigMesh.vifPacketIndices.Add(Convert.ToUInt16(mapModel.VifPackets.Count));
                    smallMesh.vifPacketIndices.Add(Convert.ToUInt16(mapModel.VifPackets.Count));

                    mapModel.VifPackets.Add(
                        new Mdlx.VifPacketDescriptor
                    {
                        VifPacket = dmaPack.vifPacket.ToArray(),
                        TextureId = smallMesh.textureIndex,
                        DmaPerVif = new ushort[] {
                            dmaPack.firstVifPacketQwc,
                            0,
                        },
                        IsTransparentFlag = smallMesh.matDef.transparentFlag ?? 0,
                    }
                        );
                }
            }

            logger.Debug($"Output: {mapModel.VifPackets.Count:#,##0} vif packets.");

            logger.Debug($"The builder has done.");

            logger.Debug($"Starting vifPacketRenderingGroup builder.");

            // first group: render all

            mapModel.vifPacketRenderingGroup = new List <ushort[]>(
                new ushort[][] {
                Enumerable.Range(0, mapModel.VifPackets.Count)
                .Select(it => Convert.ToUInt16(it))
                .ToArray()
            }
                );

            logger.Debug($"Output: {mapModel.vifPacketRenderingGroup.Count:#,##0} groups.");

            mapModel.DmaChainIndexRemapTable = new List <ushort>(
                Enumerable.Range(0, mapModel.VifPackets.Count)
                .Select(it => Convert.ToUInt16(it))
                .ToArray()
                );
        }