- 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. Вот типичный пример использования тесселятора:
Обратите внимание на то, что направление оси V в текстурах противоположно Y в мире. Итак, нарисуем траву на стороне блока ABCD:
Вот еще несколько примеров:
Наш тестовый блок: сторона "стрелка вверх" на юге, сторона "5" на востоке, а сторона "2" на севере.
Красный блок стоит на севере, синий блок стоит на востоке.
Перевернули слева направо.
Покрутили.
Исказили, но это не очень полезно.
Изменили координаты мира на почасовые.. Но куда же делась сторона?
Смотрим с севера на юг: мировые координаты по часовой стрелке ставят текстуру в противоположном направлении. (Текстуры со спины прозрачны).
Диагональ.
Повернули в стороне.
Есть ограничение на то, что можно делать с полями:
Левая половина текстуры, тогда как верхняя сдвинулась на 0.25 вправо.
Правая половина текстуры, тогда как верхняя сдвинулась на 0.25 влево.
Верхняя половина текстуры, тогда как левая сдвинулась на 0.25 вниз.
Верхний край короче нижнего = странное отображение
Точки не на одной плоскости. (Черная линия добавилась, т.к. сторона разделилась на два треугольника).
Некоторые замечания по поводу использования Тесселятора в .renderWorldBlock:
Использование Тесселятора для других шейпов
Хотя обычно Тесселятор используют для отрисовки полей, он так же подходит для других вещей - смотрите ниже возможные настройки drawMode, взятые из GL11.class.
Ванильный код использует некоторые из них, включая GL_LINES, GL_LINE_STRIP, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN. Они используются так же, как поля - то есть
.startDrawing(drawMode), устанавливает флаги, добавляет нужное число вершин, вызывает draw().
Последнее замечание
Если вы хотите использовать Тесселятор для создания легких форм, не тратьте время - используйте Teche, это намного проще.
Но взаимодействие с 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. Вот типичный пример использования тесселятора:
- Tessellator.startDrawingQuads(), говорит тесселятору, что он должен рисовать четырехугольники.
- Tessellator.setTranslation() используется для установки координат в соответствующее место. Часто эти два шага сделаны до вас - например, в рендере блока. updateRenderer устанавливает координаты таким образом, что методы renderBlock и renderFace могут рисовать блок, используя только координаты мира [x,y,z] не заботясь о том, в каком чанке он находится.
- Установка различных флагов (яркость, нормали, окклюзия окружения, цвет, альфа).
- Каждая сторона каждого блока устанавливается путем четырехразового вызова addVertexWithUV(x, y, z, u, v), и единожды для каждой грани. [x,y,z] являются координатами вершины, и [u,v] являются координатами пикселя в текстуре (координатами тексела), соответствующего этой вершине. Посмотрите на изображения и примеры ниже. *Порядок создания вершин очень важен! Например, на стороне блока вершины задаются против часовой стрелки. В противном случае, сторона будет отображаться в другом направлении.
- 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) - соответствует средней точке вашей текстуры)
- Tessellator.draw();
Обратите внимание на то, что направление оси V в текстурах противоположно Y в мире. Итак, нарисуем траву на стороне блока ABCD:
Вот еще несколько примеров:
Наш тестовый блок: сторона "стрелка вверх" на юге, сторона "5" на востоке, а сторона "2" на севере.
Красный блок стоит на севере, синий блок стоит на востоке.
Перевернули слева направо.
Покрутили.
Исказили, но это не очень полезно.
Изменили координаты мира на почасовые.. Но куда же делась сторона?
Смотрим с севера на юг: мировые координаты по часовой стрелке ставят текстуру в противоположном направлении. (Текстуры со спины прозрачны).
- Так же, точки не должны быть за границами поверхности блока.
Диагональ.
Повернули в стороне.
Есть ограничение на то, что можно делать с полями:
- Поле может быть сдвинуто - например, верхнее сдвигается вправо относительно нижнего. Или левое сдвигается вверх относительно правого. До тех пор, пока верхний край имеет одинаковую длину с нижним краем и левый край имеет одинаковую длину с правым краем. Рендер будет проходить без ошибок.
Левая половина текстуры, тогда как верхняя сдвинулась на 0.25 вправо.
Правая половина текстуры, тогда как верхняя сдвинулась на 0.25 влево.
Верхняя половина текстуры, тогда как левая сдвинулась на 0.25 вниз.
- Если вы попытаетесь "прижать" поле (Например, сделать верхний край короче нижнего), то получится довольно странно.
Верхний край короче нижнего = странное отображение
- Если ваши точки не в одной плоскости, то сторона "согнется" в два треугольника и скорее всего, получится не то, что вы хотели.
Точки не на одной плоскости. (Черная линия добавилась, т.к. сторона разделилась на два треугольника).
Некоторые замечания по поводу использования Тесселятора в .renderWorldBlock:
- Как правило, вы не должны испоьзовать методы .startDrawingQuads() или .draw() потому что за вас их уже вызвали.
- Есть несколько вещей, которые нужно создавать в тесселяторе первыми - в частности, яркость и цвет. Например:
Код:
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);
Ванильный код не поддерживает нестандартные блоки. Смотрите больше информации об освещении. - Несколько полезных примеров использования тесселяции можно найти в .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 и выше используется следующее:
А уже в VertexBuffer отправляется весь список точек с координатами.
P.S. Спасибо Liahim'у за информацию.
Код:
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer vertexbuffer = tessellator.getBuffer();
P.S. Спасибо Liahim'у за информацию.
Последнее редактирование: