Зеркальная сетка и неправильный экспорт времени выполнения UV-карты

РЕДАКТИРОВАТЬ: Итак, после краткого контакта с разработчиком Assimp мне указали на процесс импорта. Поскольку я перенял код у кого-то другого, я не думал, глядя на эту часть:

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

FlipUVs делает именно то, что говорит, он переворачивает по оси Y, поэтому начало координат теперь находится в верхнем левом углу. Итак, теперь я могу получить модель с правильным UV, но все же с зеркальной сеткой. Установка родительского объекта с масштабом x = -1 возвращает его к нормальному состоянию и заставляет его выглядеть нормально, но я думаю, что это не так. Поэтому я продолжаю искать.


Смотрите картинку, есть две модели крана. Тот, что слева, загружается во время выполнения посредством сериализации и реконструкции, а правый — это исходный, который просто перетаскивается на сцену. Сериализация происходит с библиотекой Assimp.

введите описание изображения здесь

Пол создается первым и, кажется, получает правильную карту UV. В то время как другие предметы получают неправильную УФ-карту. Хотя я печатаю значения uv-карт, и они, похоже, соответствуют исходным, как и должны.

Вот как сериализоваться, это класс Mesh из Assimp, а не класс Unity Mesh, сериализация приложения — это приложение Windows, встроенное в UWP:

    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, которые у меня есть, используют quad вместо треугольника для индексации.

Может ли быть так, что Ассимп с этим не ладит?


person Everts    schedule 08.05.2017    source источник
comment
Единственная причина, о которой я мог подумать, - это использование циклов foreach. Иногда foreach не выполняет итерацию, как ожидалось. Попробуйте использовать классический цикл for() как для сериализации, так и для десериализации. Надеюсь это поможет   -  person Nika Kasradze    schedule 08.05.2017
comment
может быть, они были экспортированы с другими настройками из программного обеспечения для 3D-моделирования?   -  person Nika Kasradze    schedule 08.05.2017
comment
В какой момент вы получаете исключение при отладке?   -  person Anup Sharma    schedule 14.05.2017
comment
Нет никаких исключений. Это на самом деле работает полностью, но не так, как ожидалось.   -  person Everts    schedule 15.05.2017
comment
Похоже, ваш авторский инструмент использует правую систему координат, а Unity — левую. Если это так, вам нужно будет сделать немного больше, если вы экспортируете иерархии игровых объектов с поворотами.   -  person Leo Bartkus    schedule 15.05.2017
comment
Я исключил это, поскольку, если бы это была проблема с системой координат, результат был бы повернут, а не зеркально отражен. Я на самом деле видел этот случай, и он будет зеркально отражен и повернут. Это один и тот же файл fbx, используемый в обоих случаях, и он нормально загружается в Unity, если я его перетаскиваю. Я думаю, это связано с тем, как Assimp обрабатывает загрузку, что-то, что я не говорю ему делать правильно.   -  person Everts    schedule 16.05.2017
comment
Если вы решили это, было бы здорово опубликовать ответ и принять его, чтобы этот вопрос можно было завершить.   -  person Zze    schedule 22.01.2018
comment
Я не решил это должным образом. Я больше не работаю над этим проектом, но в качестве ответа я опубликую решение, которое можно сделать.   -  person Everts    schedule 22.01.2018


Ответы (1)


Я не решил проблему должным образом от Assimp.

Основное решение, которое мы использовали, заключалось в отрицательном масштабировании оси, которая была перевернута при преобразовании объекта.

Более подходящим решением было бы передать все вершины матрице на стороне Unity, чтобы она правильно определяла положение вершин.

  • Получить список вершин
  • foreach вершина умножается на матрицу вращения
  • Назначить массив сетке
  • Использовать сетку для рендеринга
person Everts    schedule 22.01.2018