首页 文章

镜像网格和错误的UV贴图运行时导出

提问于
浏览
24

编辑:所以在与Assimp dev进行短暂接触之后,我被指向了导入过程 . 当我从其他人手中接过代码时,我认为没有看到那部分:

using (var importer = new AssimpContext())
{
   scene = importer.ImportFile(file, PostProcessSteps.Triangulate | PostProcessSteps.FlipUVs | PostProcessSteps.JoinIdenticalVertices);
}

FlipUV完全按照它所说的做,它在y轴上翻转,因此原点现在是左上角 . 所以现在我能够获得具有适当UV但仍然是镜像网格的模型 . 设置具有缩放x = -1的父对象将其翻转回正常并使其看起来很好,但我想这并不意味着 . 所以我一直在寻找 .


看图,有两种起重机型号 . 左边的那个在运行时通过序列化和重建加载,而右边的那个是原始的,只是拖动到场景 . 序列化发生在Assimp库中 .

enter image description here

地板碰巧首先被创建,似乎得到了正确的紫外线 Map . 而其他项目出错了uv map . 虽然我正在打印uv Map 的值,但它们似乎与原始 Map 相匹配 .

这是序列化的方法,这是来自Assimp的Mesh类,而不是Unity Mesh类,应用程序序列化是在UWP中构建的Windows应用程序:

private static void SerializeMeshes(BinaryWriter writer, IEnumerable<Mesh> meshes)
    {
        foreach (Mesh mesh in meshes)
        {
            ICollection<int> triangles = MeshLoadTriangles(mesh);
            MeshSerializeHeader(writer, mesh.Name, mesh.VertexCount, triangles.Count, mesh.MaterialIndex);
            MeshSerializeVertices(writer, mesh.Vertices);
            MeshSerializeUVCoordinate(writer, mesh.TextureCoordinateChannels);
            MeshSerializeTriangleIndices(writer, triangles);                       
        }
    }

    private static void MeshSerializeUVCoordinate(BinaryWriter writer, List<Vector3D>[] textureCoordinateChannels)
    {
        // get first channel and serialize to writer. Discard z channel
        // This is Vector3D since happening outside Unity
        List<Vector3D> list = textureCoordinateChannels[0];
        foreach (Vector3D v in list)
        {
            float x = v.X;
            float y = v.Y;
            writer.Write(x);
            writer.Write(y);
        }
    }
    private static void MeshSerializeVertices(BinaryWriter writer, IEnumerable<Vector3D> vertices)
    {
        foreach (Vector3D vertex in vertices)
        {
            Vector3D temp = vertex;
            writer.Write(temp.X);
            writer.Write(temp.Y);
            writer.Write(temp.Z);
        }
    }
    private static void MeshSerializeTriangleIndices(BinaryWriter writer, IEnumerable<int> triangleIndices)
    {
          foreach (int index in triangleIndices)  { writer.Write(index); }
    }

这是反转过程:

private static void DeserializeMeshes(BinaryReader reader, SceneGraph scene)
    {           
        MeshData[] meshes = new MeshData[scene.meshCount];
        for (int i = 0; i < scene.meshCount; i++)
        {
             meshes[i] = new MeshData();
             MeshReadHeader(reader, meshes[i]);
             MeshReadVertices(reader, meshes[i]);
             MeshReadUVCoordinate(reader, meshes[i]);
             MeshReadTriangleIndices(reader, meshes[i]);
        }
        scene.meshes = meshes as IEnumerable<MeshData>;
    }
private static void MeshReadUVCoordinate(BinaryReader reader, MeshData meshData)
    {
        bool hasUv = reader.ReadBoolean();
        if(hasUv == false) { return; }
        Vector2[] uvs = new Vector2[meshData.vertexCount];
        for (int i = 0; i < uvs.Length; i++)
        {
            uvs[i] = new Vector2();
            uvs[i].x = reader.ReadSingle();
            uvs[i].y = reader.ReadSingle();
        }
        meshData.uvs = uvs;
    }
    private static void MeshReadHeader(BinaryReader reader, MeshData meshData)
    {
        meshData.name = reader.ReadString();
        meshData.vertexCount = reader.ReadInt32();
        meshData.triangleCount = reader.ReadInt32();
        meshData.materialIndex = reader.ReadInt32();
    }
    private static void MeshReadVertices(BinaryReader reader, MeshData meshData)
    {
        Vector3[] vertices = new Vector3[meshData.vertexCount];

        for (int i = 0; i < vertices.Length; i++)
        {
            vertices[i] = new Vector3();
            vertices[i].x = reader.ReadSingle();
            vertices[i].y = reader.ReadSingle();
            vertices[i].z = reader.ReadSingle();
        }
        meshData.vertices = vertices;
    }
    private static void MeshReadTriangleIndices(BinaryReader reader, MeshData meshData)
    {
        int[] triangleIndices = new int[meshData.triangleCount];

        for (int i = 0; i < triangleIndices.Length; i++)
        {
            triangleIndices[i] = reader.ReadInt32();
        }
        meshData.triangles = triangleIndices;
    }

MeshData只是一个临时容器,带有来自fbx的反序列化值 . 然后,创建网格:

private static Mesh[] CreateMeshes(SceneGraph scene)
{
    Mesh[] meshes = new Mesh[scene.meshCount];
    int index = 0;
    foreach (MeshData meshData in scene.meshes)
    {
        meshes[index] = new Mesh();           
        Vector3[] vec = meshData.vertices;
        meshes[index].vertices = vec;
        meshes[index].triangles = meshData.triangles;
        meshes[index].uv = meshData.uvs;   
        meshes[index].normals = meshData.normals;  
        meshes[index].RecalculateNormals();
        index++;
    }
    return meshes;
}

我没有在代码中看到任何导致这种行为的原因,我会说如果值是错误的话,它会完全搞砸网格 .

我可以看到我所拥有的fbx文件使用四边形而不是三角形来进行索引 .

可能是Assimp不顺利吗?

1 回答

  • 0

    我没有从Assimp以适当的方式解决问题 .

    我们使用的基本解决方案是对在对象变换中翻转的轴进行负向缩放 .

    更合适的解决方案是将所有顶点馈送到Unity侧的矩阵,以便正确地解析顶点的位置 .

    • 获取顶点列表

    • foreach顶点乘以旋转矩阵

    • 将数组指定给网格

    • 使用网格渲染

相关问题