Комментарии 48
Кому интересно, слепок кода: github.com/FunkyCat/3dHabraLessons/tree/b8239503f9d251d94aa3e7b8a66f15495674d0cb
Вся компьютерная графика — это наука о том, как обмануть глаз наиболее дёшево. В большинстве случаев коррекция текстуры дороже тупого подразбиения больших треугольников. Например, на нашей тествой модели вы этого эффекта не заметите, даже несмотря на то, что я не сделал ни малейшего усилия для его уменьшения.
Соответственно, вам решать, как именно дешевле всего разобраться с этой проблемой. Я не планировал включать его коррекцию в этот (напоминаю, краткий) курс.
Мы все дружно просим вас — включите же! Это очень и очень нужый и полезный элемент.
А вот оказывается, что на самом деле не такое уж там и перспективное отображение используется…
Конкретный артефакт не из-за невыразимости перспективного преобразования (вершины-то мы прекрасно нарисовали где и как надо), а из-за линейности самого дешёвого интерполирования.
Да, произнесу очевидную вещь: этот артефакт будет заметен в очень специфических условиях
Например, на таких специфических поверхностях (которые практически не встречаются в играх) как потолок, стены и пол.
если вы наложите вместо шахматной доски на эти же треугольники текстуру песка, то проблемы нет
Если не считать проблемой, что текстура сплющивается в несколько раз вдоль диагоналей прямоугольников.
В софте перспективно-корректное (кусочно-линейное) текстурирование лучше применять всегда, кроме случаев, когда треугольники меньше предела разбиения (16-32 пикселей). Без него получается ужасно страшная картинка (к тому же, в софте обычно используют минимум мелких треугольников, потому что их дорого считать).
коммит тут: github.com/ssloy/tinyrenderer/commit/af1861a2bcab76bb6294e1971df8917ccd6ab0eb
В нем автоматически решилась эта проблема. (но в коммит примешалось чуть больше чем фикс искажений перспективы)
Между делом вот коммит, подготовленный для поправок, он даёт такую картинку:
Этот коммит даёт такую:
dvisvgm --no-fonts --scale=1.5 myfile.tex
Здесь мы требуем:
- --no-fonts — не пытаться применять вставку текста надписью, а рисовать векторную картинку из текста
- --scale=1.5 — увеличить все в 1,5 раза. Это зависит от того, какой был использован стиль и размер шрифта. 1,5 хорошо смотрится для article
#!/bin/sh for i in `ls -1 *tex`; do rubber $i dvisvgm --no-fonts --scale=1.5 `basename $i tex`dvi rubber --clean $i done
www.codecogs.com/latex/eqneditor.php
Он автоматический генерит ссылку на картинку с формулой и очень стабильный.
UPD: Нашел, вот так нужно писать:
latex.codecogs.com/svg.download?sin(x)
Второе возражение — в процессе написания статьи (особенно, если для ее изложения понадобились формулы. Не зря Хокингу издатель сказал, что каждая формула вдове сокращает количество читателей) не очень-то удобно постоянно отвлекаться куда-то за формулой. Но у меня «TeX головного мозга», я в этом смысле очень предвзят.
Дошёл до этого урока про матричные преобразования, думая, что тут-то я просто возьму соответствующий код из своей старой реализации движения, вращения и проецирования проволочного куба, но, кажется, я запутался в столбцах и строках. Помню где-то читал, что в DirectX используются векторы строки и умножение на матрицу преобразования, а в OpenGL всё наоборот - вектора столбцы и умножение матрицы на этот вектор. Это так? Может быть тема раскрыта в следующих статьях курса (я их ознакомительно пролистал, но не нашёл)?
Причём всё было ещё более менее понятно до тех пор, пока я не решил погуглить про эффективные реализации матричной математики на JS, потому что я наткнулся вот на это: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Matrix_math_for_the_web
Где матрица сдвига выглядит как и в моей реализации (через умножение вектора на матрицу)
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1
Но потом матрица вращения вокруг Oz там транспонирована по сравнению с той, что у меня.
cos(a), -sin(a), 0, 0,
sin(a), cos(a), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
Здесь то в статье всё одинаково транспонировано относительно моих матриц и сдвиг и вращение и проецирование.
Можно было бы предположить, что это в той статье ошибка, но у них там ссылка https://jsfiddle.net/b8zjc3ys/, где всё работает.
Возможно ещё дело в "правой" или "левой" системе координат, в том, направлен Z в экран или из, а Y -- вверх или вниз. Или в том, вращение по часовой стрелке или против.
Да ещё на странице https://glmatrix.net/ в разделе "A note about Matrix formatting", говорят что в докуемнтации OpenGL одно представление, а в коде другое.
Итак, вопрос в row major или в column major. Давайте отбросим старые версии OpenGL, где были заковыки (в одном месте пайплайна было одно соглашение, а в другом другое), и возьмём современный OpenGL. В нём вообще нет системных матриц, вы сами всё руками имплементируете. Поэтому выбирайте стиль хранения по вкусу и, главное, следуйте ему везде. Лично мне привычнее векторы представлять столбцами, а ковекторы строками. Впрочем, ковекторы вам вряд ли скоро попадутся. Поэтому самое частое представление вектора - это столбец. Если у вас вектор v преобразуется матрицей M, то их преобразование записывается M*v, то есть, v - это вектор-столбец.
Дальше вопрос про то, где у синусов стоят минусы в матрицах вращения - это отдельная договорённость. Реперы есть левые и правые, обычно пользуются правым, и с договорённостью типа буравчика. То есть, возьмите правую руку, покажите большой палец, вытяните большой палец вдоль положительной оси вращения, и остальные пальцы покажут направление вращения вокруг этой оси, если угол вращения положителен.
Результат
Ради быстрого результата пока оставил умножение вектора строки на матрицу, и, если я правильно понял, вращение получилось правильное - это вокруг OZ на 0.2 Пи с помощью матрицы
[[cos, sin, 0, 0],
[-sin, cos, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]]
Да, всё чётко. Если вектор - это строка, которая умножается справа на матрицу, то Rz так и выглядит. Вращение вокруг осей OX и OZ выглядит так:
Rx = [[1, 0, 0, 0], [0, cos, sin, 0], [0, -sin, cos, 0], [0, 0, 0, 1]]
Ry = [[cos, 0, -sin, 0], [0, 1, 0, 0], [sin, 0, cos, 0], [0, 0, 0, 1]]
Обратите внимание на то, что у Ry паттерн знаков обратный.
Краткий курс компьютерной графики: пишем упрощённый OpenGL своими руками, статья 4a из 6