[Туториал] Что такое "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'у за информацию.
 
Последнее редактирование:
1,137
5
3
Молодец, отлично написано. Только это не шейпы, а примитивы(примитивные формы, треугольник и тд(лучше только трианглы юзать)). А ещё, списки довольны быстры(почти как ВБО). Стоит так же учесть, что  создавать новый лист нужно только в том случае, если хочешь заново перерисовать.
P.S. Спойлеры убоги
 
216
6
19
wilah написал(а):
Молодец, отлично написано. Только это не шейпы, а примитивы(примитивные формы, треугольник и тд(лучше только трианглы юзать)). А ещё, списки довольны быстры(почти как ВБО). Стоит так же учесть, что  создавать новый лист нужно только в том случае, если хочешь заново перерисовать.
P.S. Спойлеры убоги
Со спойлерам на этом форуме всегда беда, сейчас все пофиксил.
 
4,046
63
645
Для 1.10 и выше (и, может быть, ниже... не проверял) используется следующее:
Код:
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer vertexbuffer = tessellator.getBuffer();
А уже в VertexBuffer отправляется весь список точек с координатами.
 
Сверху