Как реализовать пакеты с помощью WebGL? - PullRequest
1 голос
/ 17 марта 2012

Я работаю над небольшой игрой, использующей webgl. В этой игре у меня есть какой-то лес, который состоит из множества (более 100) деревьев. Поскольку у меня есть только несколько разных моделей дерева, я поворачиваю и масштабирую эти модели по-разному, прежде чем отобразить их.

В данный момент я перебираю все деревья, чтобы показать их:

for (var tree in trees) {
  tree.display();
}

В то время как display() метод дерева выглядит так:

display : function() { // tree
  this.treeModel.setRotation(this.rotation);
  this.treeModel.setScale(this.scale);
  this.treeModel.setPosition(this.position);
  this.treeModel.display();
}

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

Метод отображения treeModel делает все необходимое:

display : function() { // treeModel
  // bind texture
  // set uniforms for projection/modelview matrix based on rotation/scale/position
  // bind buffers
  // drawArrays
}

Все модели деревьев используют один и тот же шейдер, но могут использовать разные текстуры.

Поскольку модель одного дерева состоит только из нескольких треугольников, я хочу объединить все деревья в одно VBO и отобразить весь лес одним вызовом drawArrays().

Некоторые предположения, облегчающие разговор о числах:

  • Есть 250 деревьев для отображения
  • Есть 5 разных моделей дерева
  • Каждая модель дерева имеет 50 треугольников

У меня есть вопросы:

  • На данный момент у меня есть 5 буферов размером 50 * 3 * 8 (position + normal + texCoord) * floatSize байт. Когда я хочу отобразить все деревья с одним vbo, у меня будет буфер с размером 250 * 50 * 3 * 8 * floatSize байт. Я думаю, что не могу использовать индексный буфер, потому что у меня разные значения положения для каждого дерева (вычисленные из значения положения модели дерева и положения / масштаба / поворота дерева). Это правильно, или я все еще могу использовать индексные буферы, чтобы хотя бы немного уменьшить размер буфера? Может быть, есть другие способы оптимизировать это?

  • Как обрабатывать различные текстуры моделей деревьев? Я могу привязать все текстуры к разным текстурным блокам, но как я могу определить в шейдере, какую текстуру следует использовать для фрагмента, который отображается в данный момент?

  • Когда я хочу добавить новое дерево (или любой другой объект) в этот буфер во время выполнения: нужно ли создавать новый буфер и копировать содержимое? Я думаю, что новые значения не могут быть добавлены с помощью glMapBuffer. Это правильно?

Ответы [ 3 ]

4 голосов
/ 17 марта 2012

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

Вы можете добавить деревья в конец буферов, используя GL.bufferSubData.

Если ваши текстуры имеют разумный размер (например, 128x128 или 256x256), вы, вероятно, можете объединить их в одну большую текстуру и обрабатывать все это с помощью UV-координат. Если нет, вы можете добавить еще один атрибут, говорящий о том, к какой текстуре принадлежит вершина, и иметь условие в вершинном шейдере, или же массив сэмплером 2D (не уверен, что он работает, никогда не пробовал). Помните, что условия в шейдерах довольно медленные.

Если вы решите придерживаться своего текущего решения, убедитесь, что деревья отсортированы так, чтобы одноразовые текстуры использовались один за другим - поддержание выключения состояния обязательно, всегда.

2 голосов
/ 19 марта 2012

Несколько мыслей:

  1. Когда вы сажаете дерево в своем мире, вы когда-нибудь модифицировали его?Будет ли это вообще оживлять?Или это просто статическая геометрия?Если это действительно статично, вы всегда можете создать один буфер с несколькими копиями каждого дерева.Когда вы добавляете деревья, сначала примените (в Javascript) преобразование мира этого экземпляра к вершинам.При использовании треугольных полос вы можете связывать деревья вместе, используя вырожденные многоугольники.
  2. Вы можете свернуть свой собственный псевдоэкземплярный чертеж:
    1. Кодировать идентификатор экземпляра в буфере массива.Просто установите это значение одинаково для всех вершин, которые являются частью одного и того же экземпляра дерева.Кажется, я помню, что в ES GLSL не может быть атрибутов вершин, не являющихся плавающими (возможно, это ограничение Chrome), поэтому вам нужно будет ввести их как число с плавающей точкой, но использовать его как int.Поскольку он входит как число с плавающей точкой, вам придется иметь дело с тем фактом, что он интерполируется по вашему треугольнику, и поэтому значение будет иметь небольшие колебания, но простое округление до ближайшего целого числа исправляет это значение вверх.
    2. Используйте отдельную текстуру (которую я назову текстурой данных) для кодирования всей информации для каждого экземпляра.В своем вершинном шейдере посмотрите на идентификатор экземпляра текущей вершины и используйте его для вычисления координаты текстуры в текстуре данных.Вытащите все, что вам нужно для преобразования текущей вершины, и примените ее.Я думаю, что это называется «зависимым чтением текстур», которое, как правило, не одобряется, потому что может вызвать проблемы с производительностью, но может помочь вам скомпоновать вашу геометрию, что поможет решить проблемы с производительностью.Если вам интересно, вам придется попробовать это и посмотреть, что произойдет.
  3. Надеемся на расширение, поддерживающее реальный экземплярный рисунок.
1 голос
/ 17 марта 2012

Ваш нынешний подход не так уж и плох. Я бы сказал: держись, пока не наткнешься на стену.

50 треугольников - это уже разумный размер пакета для одного вызова drawElements / drawArrays. Это не оптимально, но и не так плохо. Так что для каждого дерева меняйте параметры, такие как местоположение, текстура и, возможно, форму через униформу. Затем сделайте вызов для каждого дерева. Кроме того, в общей сложности 250 вызовов drawElements тоже не так уж плохи.

Таким образом, я бы использовал один единственный VBO, который содержит все используемые варианты геометрии дерева. Я бы на самом деле разделил деревья на строительные блоки, чтобы я мог объединить их для дополнительного разнообразия. И для каждого дерева установите соответствующие смещения в VBO перед вызовом drawArrays или drawElements.

Также не забывайте, что вы можете сделать очень дешевый выбор поля зрения каждого дерева.

...