OpenGL OpenTK - несовместимая загрузка модели с помощью Assimp

Я пытаюсь импортировать модель с несколькими сетками (sponza) с помощью Assimp в свой модуль рендеринга OpenGL. Хотя у меня есть рабочий obj-файл сцены, кажется, он не загружается должным образом. Для простоты я оставляю все текстуры, даже если UV-развертки все еще загружаются, и просто устанавливаю синий цвет. Вот что у меня получается

Односеточные объекты с большим количеством полигонов, такие как Стэнфордский дракон, загружаются очень хорошо.

Вот как я загружаю объект

if (Path.ToLower().EndsWith(".x"))        
{
                _scene = _context.ImportFile(Path, PostProcessSteps.LimitBoneWeights
                    | PostProcessSteps.Triangulate
                    | PostProcessSteps.ValidateDataStructure
                    | PostProcessSteps.FlipWindingOrder
                    | PostProcessSteps.FixInFacingNormals
                );
}
        

else
{
        _scene = _context.ImportFile(Path, PostProcessSteps.LimitBoneWeights
            | PostProcessSteps.Triangulate
            | PostProcessSteps.ValidateDataStructure
        );
}

for (int i = 0; i < _scene.MeshCount; i++)
{
    for (int j = 0; j < _scene.Meshes[i].Vertices.Count; j++)
    {
        _verts.Add(_scene.Meshes[i].Vertices[j].X);
        _verts.Add(_scene.Meshes[i].Vertices[j].Y);
        _verts.Add(_scene.Meshes[i].Vertices[j].Z);


        _verts.Add(_scene.Meshes[i].HasTextureCoords(0) ? _scene.Meshes[i].TextureCoordinateChannels[0][j].X : 0f);
        _verts.Add(_scene.Meshes[i].HasTextureCoords(0) ? _scene.Meshes[i].TextureCoordinateChannels[0][j].Y : 0f);


        _verts.Add(_scene.Meshes[i].Normals[j].X * InvertNormal.X);
        _verts.Add(_scene.Meshes[i].Normals[j].Y * InvertNormal.Y);
        _verts.Add(_scene.Meshes[i].Normals[j].Z * InvertNormal.Z);

    }
}
float[] _data = _verts.ToArray();
GL.NamedBufferData(VBO, _verts.Count * sizeof(float), _data, BufferUsageHint.StaticDraw);

// Indecis
List<uint> _indecisList = new List<uint>();
for (int i = 0; i < _debugMeshes; i++)
{
    uint[] _tempArr = _scene.Meshes[i].GetUnsignedIndices();
    for (int j = 0; j < _tempArr.Length; j++)
    {
        _indecisList.Add(_tempArr[j]);
    }
}
uint[] _indecis = _indecisList.ToArray();
GL.NamedBufferData(IBO, _indecis.Length * sizeof(uint), _indecis, BufferUsageHint.StaticDraw);
GL.BindVertexArray(Renderer.Forward.OBJ4.VAO);        
{       
    _modelViewMatrix = Matrix4.CreateScale(0.01f) * Matrix4.CreateTranslation(30, 0, 10);
    GL.UniformMatrix4(21, false, ref _modelViewMatrix);

    ColorMode(1);
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, Renderer.Forward.OBJ4.IBO);
    GL.DrawElements(PrimitiveType.Triangles, 786801, DrawElementsType.UnsignedInt, 0); _drawCalls++;
    ColorMode(0);
}


person quantum    schedule 07.09.2020    source источник


Ответы (1)


Ваш код просто объединяет все сетки в один массив вершин + массив элементов. Однако данные элемента для каждой сетки - это индекс данных вершин в этой конкретной сетке, отсчитываемый от 0. Следовательно, все, что находится после самой первой сетки, будет использовать данные элемента, которые ссылаются на неправильные вершины.

Если вы хотите исправить это, вы должны сместить данные индекса элемента на сумму всех вершин сеток, которые вы добавили в массив вершин перед текущей сеткой.

Однако ваш подход кажется сомнительным. Обычно объекты разбиваются на разные сетки по какой-то причине, например, по разным текстурам и свойствам материала. В любом случае вы не можете нарисовать их за один вызов отрисовки (по крайней мере, наивно). GL предлагает такие функции, как glDrawElementsBaseVertex для сценариев, в которых вы хотите нарисовать разные подсетки из одного комбинированного массива вершин, и который внутренне выполняет указанное смещение за вас.

Также обратите внимание, что, комбинируя меши таким образом, вы также игнорируете преобразования из иерархии сцены.

person derhass    schedule 07.09.2020
comment
Хорошо, теперь у меня это работает с glDrawElementsBaseVertex. (Спасибо!) Действительно ли так можно было бы сделать в более серьезном проекте или есть другие методы, которые работают лучше? Вы говорили о разделении сцены на разные меши, означает ли это, что я должен создавать VBO для каждой Mesh или даже загружать текущие данные мешей в VBO каждый кадр? - person quantum; 07.09.2020
comment
Что ж, это всегда зависит от обстоятельств. Размещение всех сеток в одном VBO возможно, если вам не нужно добавлять, удалять или изменять отдельные объекты. Начните с простого, оптимизируйте позже, когда станет ясно, где у вас узкие места. - person derhass; 08.09.2020