示例#1
0
        public static void ExportSkelMeshSections(int index, CSkelMeshLod lod, CMeshSection sect, List <MaterialExporter>?materialExports, MeshBuilder <VERTEX, VertexColorXTextureX, VertexJoints4> mesh)
        {
            string materialName;

            if (sect.Material?.Load <UMaterialInterface>() is { } tex)
            {
                materialName = tex.Name;
                var materialExporter = new MaterialExporter(tex, true);
                materialExports?.Add(materialExporter);
            }
示例#2
0
        public static bool TryConvert(this UStaticMesh originalMesh, out CStaticMesh convertedMesh)
        {
            convertedMesh = new CStaticMesh();
            if (originalMesh.RenderData == null)
            {
                return(false);
            }

            convertedMesh.BoundingSphere = new FSphere(0f, 0f, 0f, originalMesh.RenderData.Bounds.SphereRadius / 2);
            convertedMesh.BoundingBox    = new FBox(
                originalMesh.RenderData.Bounds.Origin - originalMesh.RenderData.Bounds.BoxExtent,
                originalMesh.RenderData.Bounds.Origin + originalMesh.RenderData.Bounds.BoxExtent);

            foreach (var srcLod in originalMesh.RenderData.LODs)
            {
                if (srcLod.SkipLod)
                {
                    continue;
                }

                var numTexCoords = srcLod.VertexBuffer !.NumTexCoords;
                var numVerts     = srcLod.PositionVertexBuffer !.Verts.Length;
                if (numVerts == 0 && numTexCoords == 0)
                {
                    continue;
                }

                if (numTexCoords > Constants.MAX_MESH_UV_SETS)
                {
                    throw new ParserException($"Static mesh has too many UV sets ({numTexCoords})");
                }

                var staticMeshLod = new CStaticMeshLod
                {
                    NumTexCoords = numTexCoords,
                    HasNormals   = true,
                    HasTangents  = true,
                    Indices      = new Lazy <FRawStaticIndexBuffer>(srcLod.IndexBuffer !),
                    Sections     = new Lazy <CMeshSection[]>(() =>
                    {
                        var sections = new CMeshSection[srcLod.Sections.Length];
                        for (var j = 0; j < sections.Length; j++)
                        {
                            sections[j] = new CMeshSection(srcLod.Sections[j].MaterialIndex,
                                                           originalMesh.StaticMaterials?[srcLod.Sections[j].MaterialIndex].MaterialSlotName.Text, // materialName
                                                           originalMesh.Materials?[srcLod.Sections[j].MaterialIndex],                             // material
                                                           srcLod.Sections[j].FirstIndex,                                                         // firstIndex
                                                           srcLod.Sections[j].NumTriangles);                                                      // numFaces
                        }

                        return(sections);
                    })
                };

                staticMeshLod.AllocateVerts(numVerts);
                if (srcLod.ColorVertexBuffer !.NumVertices != 0)
                {
                    staticMeshLod.AllocateVertexColorBuffer();
                }

                for (var j = 0; j < numVerts; j++)
                {
                    var suv = srcLod.VertexBuffer.UV[j];
                    if (suv.Normal[1].Data != 0)
                    {
                        throw new ParserException("Not implemented: should only be used in UE3");
                    }

                    staticMeshLod.Verts[j].Position = srcLod.PositionVertexBuffer.Verts[j];
                    UnpackNormals(suv.Normal, staticMeshLod.Verts[j]);
                    staticMeshLod.Verts[j].UV.U = suv.UV[0].U;
                    staticMeshLod.Verts[j].UV.V = suv.UV[0].V;

                    for (var k = 1; k < numTexCoords; k++)
                    {
                        staticMeshLod.ExtraUV.Value[k - 1][j].U = suv.UV[k].U;
                        staticMeshLod.ExtraUV.Value[k - 1][j].V = suv.UV[k].V;
                    }

                    if (srcLod.ColorVertexBuffer.NumVertices != 0)
                    {
                        staticMeshLod.VertexColors ![j] = srcLod.ColorVertexBuffer.Data[j];
示例#3
0
        public static bool TryConvert(this UStaticMesh originalMesh, out CStaticMesh convertedMesh)
        {
            convertedMesh = new CStaticMesh();
            if (originalMesh.RenderData == null)
            {
                return(false);
            }

            convertedMesh.BoundingShere = new FSphere(0f, 0f, 0f, originalMesh.RenderData.Bounds.SphereRadius / 2);
            convertedMesh.BoundingBox   = new FBox(
                originalMesh.RenderData.Bounds.Origin - originalMesh.RenderData.Bounds.BoxExtent,
                originalMesh.RenderData.Bounds.Origin + originalMesh.RenderData.Bounds.BoxExtent);

            var numLods = originalMesh.RenderData.LODs.Length;

            convertedMesh.LODs = new CStaticMeshLod[numLods];
            for (var i = 0; i < convertedMesh.LODs.Length; i++)
            {
                if (originalMesh.RenderData.LODs[i] is not
                {
                    VertexBuffer: not null,
                    PositionVertexBuffer: not null,
                    ColorVertexBuffer: not null,
                    IndexBuffer: not null
                } srcLod)
                {
                    continue;
                }

                var numTexCoords = srcLod.VertexBuffer.NumTexCoords;
                var numVerts     = srcLod.PositionVertexBuffer.Verts.Length;
                if (numVerts == 0 && numTexCoords == 0 && i < numLods - 1)
                {
                    Log.Logger.Debug($"LOD {i} is stripped, skipping...");
                    continue;
                }

                if (numTexCoords > _MAX_MESH_UV_SETS)
                {
                    throw new ParserException($"Static mesh has too many UV sets ({numTexCoords})");
                }

                convertedMesh.LODs[i] = new CStaticMeshLod
                {
                    NumTexCoords = numTexCoords,
                    HasNormals   = true,
                    HasTangents  = true,
                    Indices      = new Lazy <FRawStaticIndexBuffer>(srcLod.IndexBuffer),
                    Sections     = new Lazy <CMeshSection[]>(() =>
                    {
                        var sections = new CMeshSection[srcLod.Sections.Length];
                        for (var j = 0; j < sections.Length; j++)
                        {
                            sections[j] = new CMeshSection(originalMesh.Materials?[srcLod.Sections[j].MaterialIndex],
                                                           srcLod.Sections[j].FirstIndex, srcLod.Sections[j].NumTriangles);
                        }
                        return(sections);
                    })
                };

                convertedMesh.LODs[i].AllocateVerts(numVerts);
                if (srcLod.ColorVertexBuffer.NumVertices != 0)
                {
                    convertedMesh.LODs[i].AllocateVertexColorBuffer();
                }

                for (var j = 0; j < numVerts; j++)
                {
                    var suv = srcLod.VertexBuffer.UV[j];
                    if (suv.Normal[1].Data != 0)
                    {
                        throw new ParserException("Not implemented: should only be used in UE3");
                    }

                    convertedMesh.LODs[i].Verts[j].Position = srcLod.PositionVertexBuffer.Verts[j];
                    UnpackNormals(suv.Normal, convertedMesh.LODs[i].Verts[j]);
                    convertedMesh.LODs[i].Verts[j].UV.U = suv.UV[0].U;
                    convertedMesh.LODs[i].Verts[j].UV.V = suv.UV[0].V;

                    for (var k = 1; k < numTexCoords; k++)
                    {
                        convertedMesh.LODs[i].ExtraUV.Value[k - 1][j].U = suv.UV[k].U;
                        convertedMesh.LODs[i].ExtraUV.Value[k - 1][j].V = suv.UV[k].V;
                    }

                    if (srcLod.ColorVertexBuffer.NumVertices != 0)
                        convertedMesh.LODs[i].VertexColors[j] = srcLod.ColorVertexBuffer.Data[j];
                }
            }

            convertedMesh.FinalizeMesh();
            return(true);
        }
示例#4
0
        public static bool TryConvert(this USkeletalMesh originalMesh, out CSkeletalMesh convertedMesh)
        {
            convertedMesh = new CSkeletalMesh();
            if (originalMesh.LODModels == null)
            {
                return(false);
            }

            convertedMesh.BoundingShere = new FSphere(0f, 0f, 0f, originalMesh.ImportedBounds.SphereRadius / 2);
            convertedMesh.BoundingBox   = new FBox(
                originalMesh.ImportedBounds.Origin - originalMesh.ImportedBounds.BoxExtent,
                originalMesh.ImportedBounds.Origin + originalMesh.ImportedBounds.BoxExtent);

            var numLods = originalMesh.LODModels.Length;

            convertedMesh.LODs = new CSkelMeshLod[numLods];
            for (var i = 0; i < convertedMesh.LODs.Length; i++)
            {
                if (originalMesh.LODModels[i] is not
                {
                    Indices: not null
                } srcLod)
                {
                    continue;
                }

                if (srcLod.Indices.Indices16.Length == 0 && srcLod.Indices.Indices32.Length == 0)
                {
                    Log.Logger.Debug($"LOD {i} has no indices, skipping...");
                    continue;
                }

                var numTexCoords = srcLod.NumTexCoords;
                if (numTexCoords > _MAX_MESH_UV_SETS)
                {
                    throw new ParserException($"Skeletal mesh has too many UV sets ({numTexCoords})");
                }

                convertedMesh.LODs[i] = new CSkelMeshLod
                {
                    NumTexCoords = numTexCoords,
                    HasNormals   = true,
                    HasTangents  = true,
                    Indices      = new Lazy <FRawStaticIndexBuffer>(() => new FRawStaticIndexBuffer
                    {
                        Indices16 = srcLod.Indices.Indices16, Indices32 = srcLod.Indices.Indices32
                    }),
                    Sections = new Lazy <CMeshSection[]>(() =>
                    {
                        var sections = new CMeshSection[srcLod.Sections.Length];
                        for (var j = 0; j < sections.Length; j++)
                        {
                            int materialIndex = srcLod.Sections[j].MaterialIndex;
                            if (materialIndex < 0)      // UE4 using Clamp(0, Materials.Num()), not Materials.Num()-1
                            {
                                materialIndex = 0;
                            }

                            var m       = materialIndex < originalMesh.Materials?.Length ? originalMesh.Materials[materialIndex].Material : null;
                            sections[j] = new CMeshSection(m, srcLod.Sections[j].BaseIndex, srcLod.Sections[j].NumTriangles);
                        }
                        return(sections);
                    })
                };

                var bUseVerticesFromSections = false;
                var vertexCount = srcLod.VertexBufferGPUSkin.GetVertexCount();
                if (vertexCount == 0 && srcLod.Sections.Length > 0 && srcLod.Sections[0].SoftVertices.Length > 0)
                {
                    bUseVerticesFromSections = true;
                    for (var j = 0; j < srcLod.Sections.Length; j++)
                    {
                        vertexCount += srcLod.Sections[i].SoftVertices.Length;
                    }
                }

                convertedMesh.LODs[i].AllocateVerts(vertexCount);

                var  chunkIndex       = -1;
                var  chunkVertexIndex = 0;
                long lastChunkVertex  = -1;
                ushort[]? boneMap = null;
                var vertBuffer = srcLod.VertexBufferGPUSkin;

                if (srcLod.ColorVertexBuffer.Data.Length == vertexCount)
                {
                    convertedMesh.LODs[i].AllocateVertexColorBuffer();
                }

                for (var vert = 0; vert < vertexCount; vert++)
                {
                    while (vert >= lastChunkVertex) // this will fix any issues with empty chunks or sections
                    {
                        // proceed to next chunk or section
                        if (srcLod.Chunks.Length > 0)
                        {
                            // pre-UE4.13 code: chunks
                            var c = srcLod.Chunks[++chunkIndex];
                            lastChunkVertex = c.BaseVertexIndex + c.NumRigidVertices + c.NumSoftVertices;
                            boneMap         = c.BoneMap;
                        }
                        else
                        {
                            // UE4.13+ code: chunk information migrated to sections
                            var s = srcLod.Sections[++chunkIndex];
                            lastChunkVertex = s.BaseVertexIndex + s.NumVertices;
                            boneMap         = s.BoneMap;
                        }
                        chunkVertexIndex = 0;
                    }

                    FSkelMeshVertexBase v; // has everything but UV[]
                    if (bUseVerticesFromSections)
                    {
                        var v0 = srcLod.Sections[chunkIndex].SoftVertices[chunkVertexIndex++];
                        v = v0;

                        // UV: simply copy float data
                        convertedMesh.LODs[i].Verts[vert].UV = v0.UV[0];
                        for (var texCoordIndex = 1; texCoordIndex < numTexCoords; texCoordIndex++)
                        {
                            convertedMesh.LODs[i].ExtraUV.Value[texCoordIndex - 1][vert] = v0.UV[texCoordIndex];
                        }
                    }
                    else if (!vertBuffer.bUseFullPrecisionUVs)
                    {
                        var v0 = vertBuffer.VertsHalf[vert];
                        v = v0;

                        // UV: convert half -> float
                        convertedMesh.LODs[i].Verts[vert].UV = (FMeshUVFloat)v0.UV[0];
                        for (var texCoordIndex = 1; texCoordIndex < numTexCoords; texCoordIndex++)
                        {
                            convertedMesh.LODs[i].ExtraUV.Value[texCoordIndex - 1][vert] = (FMeshUVFloat)v0.UV[texCoordIndex];
                        }
                    }
                    else
                    {
                        var v0 = vertBuffer.VertsFloat[vert];
                        v = v0;

                        // UV: simply copy float data
                        convertedMesh.LODs[i].Verts[vert].UV = v0.UV[0];
                        for (var texCoordIndex = 1; texCoordIndex < numTexCoords; texCoordIndex++)
                        {
                            convertedMesh.LODs[i].ExtraUV.Value[texCoordIndex - 1][vert] = v0.UV[texCoordIndex];
                        }
                    }

                    convertedMesh.LODs[i].Verts[vert].Position = v.Pos;
                    UnpackNormals(v.Normal, convertedMesh.LODs[i].Verts[vert]);
                    if (convertedMesh.LODs[i].VertexColors != null)
                    {
                        convertedMesh.LODs[i].VertexColors[vert] = srcLod.ColorVertexBuffer.Data[vert];
                    }

                    var  i2            = 0;
                    uint packedWeights = 0;
                    for (var j = 0; j < 4; j++)
                    {
                        uint boneWeight = v.Infs.BoneWeight[j];
                        if (boneWeight == 0)
                        {
                            continue;                  // skip this influence (but do not stop the loop!)
                        }
                        packedWeights |= boneWeight << (i2 * 8);
                        convertedMesh.LODs[i].Verts[vert].Bone[i2] = (short)boneMap[v.Infs.BoneIndex[j]];
                        i2++;
                    }
                    convertedMesh.LODs[i].Verts[vert].PackedWeights = packedWeights;
                    if (i2 < 4)
                    {
                        convertedMesh.LODs[i].Verts[vert].Bone[i2] = -1;         // mark end of list
                    }
                }
            }

            var numBones = originalMesh.ReferenceSkeleton.FinalRefBoneInfo.Length;

            convertedMesh.RefSkeleton = new CSkelMeshBone[numBones];
            for (var i = 0; i < convertedMesh.RefSkeleton.Length; i++)
            {
                convertedMesh.RefSkeleton[i] = new CSkelMeshBone
                {
                    Name        = originalMesh.ReferenceSkeleton.FinalRefBoneInfo[i].Name,
                    ParentIndex = originalMesh.ReferenceSkeleton.FinalRefBoneInfo[i].ParentIndex,
                    Position    = originalMesh.ReferenceSkeleton.FinalRefBonePose[i].Translation,
                    Orientation = originalMesh.ReferenceSkeleton.FinalRefBonePose[i].Rotation,
                };

                // fix skeleton; all bones but 0
                if (i >= 1)
                {
                    convertedMesh.RefSkeleton[i].Orientation.Conjugate();
                }
            }

            convertedMesh.FinalizeMesh();
            return(true);
        }