2013-03-07 2 views
3

В настоящее время я создаю двигатель воксела (например, Minecraft), и я использую opengl.Как правильно использовать VAO и VBO в движке вокселя

В настоящее время конструкции двигателя выглядит следующим образом:

класса Map -> содержит 2d массива кусков (станд :: вектора станда :: вектора)

класса Chunk -> содержит 3d-массив блока (также с использованием std :: vector)

класс Блок -> содержит вершины блоков. (кубы, построенные от 12 треугольников);

Что я хочу сделать, так это сделать каждый кусок функцией draw(), которая будет рисовать все блоки в куске. Я думал, что сделаю буфер для каждого фрагмента, используя glGenBuffers(). Из учебников, которые я прочитал, следует сначала создать массив вершин с glVertexArray и связать его, а не привязать к нему буфер с целевым GL_ARRAY_BUFFER и заполнить его данными.

До сих пор мне удалось отобразить один кусок с помощью нескольких блоков, используя буфер, созданный в куске с помощью glGenBuffers(), но в основной функции я создаю glVertexArray и свяжу его, чем вызов функции draw() в кусок, и он связывает буфер и рисунок блока, используя glDrawArrays().

Вопрос в том, правильно ли создать VBO для каждого куска? Мне нужно создать glVertexArray для каждого фрагмента? или я должен использовать один для всех кусков и каждый раз связывать другой VBO?

Я попытался больше узнать о VAO и учебниках VBO throught и wiki, но до сих пор я не совсем понял, как это работает и как его следует использовать должным образом.

+1

«std :: vector of std :: vector» ... Это, как правило, не очень эффективно для плотных 2D/3D-массивов. Переключитесь на что-то вроде ['boost.multiarray'] (http://www.boost.org/libs/multi_array/). – genpfault

+2

Я бы рекомендовал не использовать метод draw для класса Block. Хотя это отличный пример инкапсуляции, он может быть очень неэффективным. В частности, для таких действий, как рендеринг, вам может потребоваться резервировать состояние (например, связывать VBOs, менять шейдерную форму и т. Д.) Избыточно в каждом методе 'draw', а инкапсуляция запрещает глобальное представление о том, как вы можете оптимизировать эту операцию. Посмотрите на [Шаблон посетителя] (http://en.wikipedia.org/wiki/Visitor_pattern), который описывает способ координации обхода ваших данных организованным образом. – radical7

+1

Что это за функция 'glVertexArray()', о которой вы говорите? OpenGL имеет [вершинные массивы] (http://www.songho.ca/opengl/gl_vertexarray.html), [объекты массива вершин] (http://www.opengl.org/wiki/Vertex_Specification#Vertex_Array_Object) и [вершина буферных объектов] (http://www.songho.ca/opengl/gl_vbo.html). Ни один из них не использует нечто, называемое 'glVertexArray()'. Возможно, вы думаете о 'glGenVertexArrays()'? – genpfault

ответ

0

Я думаю, что вы, возможно, слишком рано задумывались над вещами. Почему ваша карта разбита на куски? Ожидаете ли вы какую-то страничную страничку, где не все карты находятся в памяти? Если ваша карта вписывается в память GPU, используйте один буфер на карту, и нет необходимости в кусках. Сначала сделайте рендеринг.

После этого вы можете подумать об оптимизации, например, только для рисования видимых частей. Или рисовать отдаленные части на более низких деталях. И в этот момент вы решаете, как поддерживать буферы GPU, когда их обновлять или отбрасывать. Это просто проблема кэширования. Нелегкая задача, но проблема с кешированием.

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

В качестве первого шага просто извлеките из памяти ЦП. Как только вы получите лучшее представление о том, как будет выглядеть последовательность в кешировании. Не смешивайте структуры графического процессора в своем дизайне раньше. Вам также понадобятся структуры процессора для таких вещей, как сбор или ИИ. У вас должен быть один набор данных «истина», который затем имеет разные разделы и представления для разных потребностей.

1

Я знаю, что я очень опаздываю, но я отвечу на этот ответ, если кто-нибудь найдет это в будущем.

Minecraft делает это иначе, чем люди предполагают. Вместо того, чтобы иметь описанную выше систему с вложенными буферами, кусок может уйти просто с массивом целых чисел (или unsigned chars, если у вас менее 256 типов блоков).Вместо того, чтобы иметь много объектов для блоков, вы можете иметь один блок каждого типа, а затем отображать его в определенной позиции, если его идентификатор появляется в массиве блоков.

Это может быть 3D-массив (или вектор векторов векторов в вашем случае, но это не очень эффективно) или 1D-массив, к которому можно получить доступ с шириной, высотой и глубиной. Каждый идентификатор (целое или неподписанный символ) будет связан с одним типом блока. Из-за этого, когда вы хотите отобразить кусок, вы можете просто просмотреть все размеры куска - ширину, высоту, глубину - и посмотреть на идентификатор в этой точке. Если это 3, сделайте блок грязи, если он равен 1, сделайте блок травы, если он равен 0, сохраните это как воздушный блок и т. Д. Эта система делает ее отличной для формирования и создания ландшафта, re просто манипулирует целым массивом. Если вы упорядочили блоки по порядку плотности, вы можете сделать некоторую арифметику на участках куска, чтобы сформировать ландшафт (например, вычесть его из всех идентификаторов в этой области куска), и все типы блоков изменились бы.

Это будет сделано с помощью instancing, так что вы можете иметь один блок грязи в куске и просто визуализировать его несколько раз, где нужно. В какой-то степени это можно было бы сделать даже с униформами, которые сдвигали бы положение блока и отображали его один за другим.

Чтобы ответить на ваш вопрос, вы должны указать один VBO, который определяет данные положения и координаты текстуры блока. Один VAO тоже, для хранения способа размещения этих данных в памяти. Но после этого вы можете связывать разные текстуры перед рендерингом каждого блока в зависимости от ID в блочном массиве в куске. При загрузке, в зависимости от того, насколько большой вы сделали кусок, группируйте все места блоков грязи в куске и один раз привязывайте текстуру, а затем визуализируете все блоки грязи в одном (поскольку вызовы текстурной привязки могут быть проблемой производительности, если они часто случается).

Смежные вопросы