Что такое 'Tessellator'?

Была ли тема полезна?


  • Всего проголосовало
    24
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



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


12c9a59710.png


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


4b38445f9d.png


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


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

19be7cd21f.png


Верхний край короче нижнего = странное отображение​


  • Если ваши точки не в одной плоскости, то сторона "согнется" в два треугольника и скорее всего, получится не то, что вы хотели.
[/align]
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, это намного проще.
 
Последнее редактирование:
  • Like
Реакции: volt
7,099
324
1,510
А где брать этот самый IIcon, если имеется только путь к текстуре в assets? Посмотрел в некоторых рендерах - там текстура берется из предмета, но это как-то костыльно, если у меня такого предмета быть не должно и текстура больше, чем 16*16.
 
1,137
5
3
Дело в том, что менять текстуру - дорого. Для этого создается огромный атлас с иконками. А благодаря IIcon можно получить UV этой иконки. Если есть текстура в памяти, то ее можно загрузить. С диска просто - использовать SimpleTexture. Указать путь, загрузить и использовать texture Id для бинда. Можно еще грузить из Buffered Image. Просто посмотри, как в опенгл грузятся текстуры. И все!
 
2,505
81
397
Как сказал wilah, IIcon это, так сказать, место расположения иконки в большом атласе. Дак зачем тебе IIcon, если у тебя просто тектура.


Просто забинди ее ResourceLocation и рисуй
 
7,099
324
1,510
ок, а u,v задать самому т.е?
 
2,505
81
397
Это координаты на текстуре.
 
7,099
324
1,510
Ага, я немного напутал с тем, как они задаются.
 
271
2
0
Опечатка
Последнее замечание
Если вы хотите использовать Тесселятор для создания легких форм, не тратьте время - используйте Teche, это намного проще.

Не Teche, а Techne
 
Сверху