[Туториал] Что такое "Tessellator"?

216
6
19
Перевод зарубежной статьи по тесселятору.​

Решил поинтересоваться данной темой на иностранных сайтах и понял что не помешало бы перевести одну из статей для себя (чтобы лучше понять описанное в ней), ибо давно хотел понять процесс тесселяции.​


Перевод довольно сложен, поэтому ошибок и некорректностей не избежать. О них, а так же о предложения по уроку, можно сообщить в ВК и в ЛС форума.​

--------------------------------------------------------------------------------------------​
Minecraft использует OpenGL, чтобы рисовать все то, что вы видите на экране.
Но взаимодействие с OpenGL напрямую довольно костыльно, поэтому используют класс Тесселятора, для упрощения.

Все что вы видите на экране - это огромный список инструкций рендеринга, выполняющийся OpenGl'ем и вашей видеокартой. Эти инструкции похожи на "draw a pixel at [3,4,5]", или "draw a line from [1,2,3] to [4,5,6]", или "draw a quadrilateral with vertices [1,2,3], [4,5,6], [7,8,9] and [10,11,12], filling it with bitmap texture abc." Этот список инструкций называется "Display List" (Список отображаемого) (glRenderList в фордже).

Тесселятор используется для добавления чего-либо в список отображаемого. Список отображаемого уже создан заранее, например, в WorldRenderer.updateRenderer - GL11.glNewList. Вот типичный пример использования тесселятора:

  1. Tessellator.startDrawingQuads(), говорит тесселятору, что он должен рисовать четырехугольники.
  2. Tessellator.setTranslation() используется для установки координат в соответствующее место. Часто эти два шага сделаны до вас - например, в рендере блока. updateRenderer устанавливает координаты таким образом, что методы renderBlock и renderFace могут рисовать блок, используя только координаты мира [x,y,z] не заботясь о том, в каком чанке он находится.
  3. Установка различных флагов (яркость, нормали, окклюзия окружения, цвет, альфа).
  4. Каждая сторона каждого блока устанавливается путем четырехразового вызова addVertexWithUV(x, y, z, u, v), и единожды для каждой грани. [x,y,z] являются координатами вершины, и [u,v] являются координатами пикселя в текстуре (координатами тексела), соответствующего этой вершине. Посмотрите на изображения и примеры ниже. *Порядок создания вершин очень важен! Например, на стороне блока вершины задаются против часовой стрелки. В противном случае, сторона будет отображаться в другом направлении.
  5. Minecraft использует одну большую текстуру для всех сторон блоков. Регистрируясь при запуске, все иконки сливаются в одну большую текстуру - (смотрите glTexImage2D в TextureUtil). Когда вы рендерите, вы используете малую часть всей этой текстуры, которая заданная для нужной вам текстуры. Обычный способ получения координат [u,v] для вашей текстуры: icon.getMinU(), icon.getMaxU(), icon.getMinV(), icon.getMaxV(). Для точек, не лежащих на краю текстуры используют icon.getInterpolatedU(от 0 до 16), icon.getInterpolatedV(от 0 до 16). Например: icon.getInterpolatedU(8), icon.getInterpolatedV(8) - соответствует средней точке вашей текстуры)
  6. Tessellator.draw();



n2Yn5zGSjz7zgA.png



Обратите внимание на то, что направление оси V в текстурах противоположно Y в мире. Итак, нарисуем траву на стороне блока ABCD:
​

a04c956d34.png


Вот еще несколько примеров:

dabca34e37.png

Наш тестовый блок: сторона "стрелка вверх" на юге, сторона "5" на востоке, а сторона "2" на севере.​


43f8c08d09.png

Красный блок стоит на севере, синий блок стоит на востоке.​

198e8df831.png

Перевернули слева направо.​

539c187188.png

Покрутили.​

4f13113719.png

Исказили, но это не очень полезно.​

fb7fde71eb.png

Изменили координаты мира на почасовые.. Но куда же делась сторона?​

2592e10485.png

Смотрим с севера на юг: мировые координаты по часовой стрелке ставят текстуру в противоположном направлении. (Текстуры со спины прозрачны).​

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

a35c7d1291.png

Диагональ.​


a4002c3ec5.png

Повернули в стороне.​


Есть ограничение на то, что можно делать с полями:
  • Поле может быть сдвинуто - например, верхнее сдвигается вправо относительно нижнего. Или левое сдвигается вверх относительно правого. До тех пор, пока верхний край имеет одинаковую длину с нижним краем и левый край имеет одинаковую длину с правым краем. Рендер будет проходить без ошибок.



df298091fc.png

Левая половина текстуры, тогда как верхняя сдвинулась на 0.25 вправо.
​


12c9a59710.png

Правая половина текстуры, тогда как верхняя сдвинулась на 0.25 влево.​


4b38445f9d.png

Верхняя половина текстуры, тогда как левая сдвинулась на 0.25 вниз.​


  • Если вы попытаетесь "прижать" поле (Например, сделать верхний край короче нижнего), то получится довольно странно.

19be7cd21f.png

Верхний край короче нижнего = странное отображение
​
  • Если ваши точки не в одной плоскости, то сторона "согнется" в два треугольника и скорее всего, получится не то, что вы хотели.
c746bb69c3.png

Точки не на одной плоскости. (Черная линия добавилась, т.к. сторона разделилась на два треугольника).​

Некоторые замечания по поводу использования Тесселятора в .renderWorldBlock:
  1. Как правило, вы не должны испоьзовать методы .startDrawingQuads() или .draw() потому что за вас их уже вызвали.
  2. Есть несколько вещей, которые нужно создавать в тесселяторе первыми - в частности, яркость и цвет. Например:
    Код:
       Tessellator tessellator = Tessellator.instance;
       tessellator.startDrawingQuads();
       int lightValue = block.getMixedBrightnessForBlock(world, x, y, z);
       tessellator.setBrightness(lightValue);
       tessellator.setColorOpaque_F(1.0F, 1.0F, 1.0F);
    Расчеты для "Окклюзии окружения" (если включено) довольно сложны и не подходит для блоков с пользовательским рендерингом.
    Ванильный код не поддерживает нестандартные блоки. Смотрите больше информации об освещении.
  3. Несколько полезных примеров использования тесселяции можно найти в .drawCrossedSquares() и .renderBlockTorch()

Использование Тесселятора для других шейпов

Хотя обычно Тесселятор используют для отрисовки полей, он так же подходит для других вещей - смотрите ниже возможные настройки drawMode, взятые из GL11.class.
Ванильный код использует некоторые из них, включая GL_LINES, GL_LINE_STRIP, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN. Они используются так же, как поля - то есть
.startDrawing(drawMode), устанавливает флаги, добавляет нужное число вершин, вызывает draw().
Код:
public static final int GL_POINTS = 0;
public static final int GL_LINES = 1;
public static final int GL_LINE_LOOP = 2;
public static final int GL_LINE_STRIP = 3;
public static final int GL_TRIANGLES = 4;
public static final int GL_TRIANGLE_STRIP = 5;
public static final int GL_TRIANGLE_FAN = 6;
public static final int GL_QUADS = 7;
public static final int GL_QUAD_STRIP = 8;
public static final int GL_POLYGON = 9;

Последнее замечание
Если вы хотите использовать Тесселятор для создания легких форм, не тратьте время - используйте Teche, это намного проще.

Для 1.10 и выше используется следующее:
Код:
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer vertexbuffer = tessellator.getBuffer();
А уже в VertexBuffer отправляется весь список точек с координатами.

P.S. Спасибо Liahim'у за информацию.
 
Последнее редактирование:
Молодец, отлично написано. Только это не шейпы, а примитивы(примитивные формы, треугольник и тд(лучше только трианглы юзать)). А ещё, списки довольны быстры(почти как ВБО). Стоит так же учесть, что  создавать новый лист нужно только в том случае, если хочешь заново перерисовать.
P.S. Спойлеры убоги
 
wilah написал(а):
Молодец, отлично написано. Только это не шейпы, а примитивы(примитивные формы, треугольник и тд(лучше только трианглы юзать)). А ещё, списки довольны быстры(почти как ВБО). Стоит так же учесть, что  создавать новый лист нужно только в том случае, если хочешь заново перерисовать.
P.S. Спойлеры убоги
Со спойлерам на этом форуме всегда беда, сейчас все пофиксил.
 
Для 1.10 и выше (и, может быть, ниже... не проверял) используется следующее:
Код:
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer vertexbuffer = tessellator.getBuffer();
А уже в VertexBuffer отправляется весь список точек с координатами.
 
Назад
Сверху