Как стать автором
Обновить

Комментарии 48

Замечательная серия статей! Спасибо огромное.
ох уж эти матрицы! Хорошо, что мы не живём в 4х мерном мире, а то работать с матрицами 5*5 будет совсем не весело )
Зато в четырехмерном мире можно будет идеально причесать ежа: В нашем мире еж — сфера четной размерности (S2, как выражаются топологи), а в четырехмерном — нечетной (S3).
А четырехмерный ёж тоже будет идеально причёсываться?
Идеально причесываются только ежи нечетной размерности.
А случайно нету картинки идеально причёсанного четырехмерного или шестимерного ежа?
Всё чудесатее и чудесатее :) Вот, код работы с матрицами нагло взял у вас и немного причесал под свои эстетические нужды, и добавил таки карту нормалей:
Картинка
image

Кому интересно, слепок кода: github.com/FunkyCat/3dHabraLessons/tree/b8239503f9d251d94aa3e7b8a66f15495674d0cb
Отлично! В следующий раз я причешу код, тк вызов растеризатора заставляет глаза слезиться :)
Всё оставлять в файле main уже невозможно, код становится нечитаемым.
Вам осталось сделать блики и тени. Возможно, подповерхностное рассеяние.
НЛО прилетело и опубликовало эту надпись здесь
Да, было бы неплохо текстуры отдельно пояснить. У меня это всегда было камнем преткновения ((
Да, у меня будет работать как на среднем рисунке. Коррекция этогого артефакта муторная и в реальности ненужная, т.к. достаточно разделить треугольник на более мелкие, чтобы он перестал быть заметен.

Вся компьютерная графика — это наука о том, как обмануть глаз наиболее дёшево. В большинстве случаев коррекция текстуры дороже тупого подразбиения больших треугольников. Например, на нашей тествой модели вы этого эффекта не заметите, даже несмотря на то, что я не сделал ни малейшего усилия для его уменьшения.
Да, произнесу очевидную вещь: этот артефакт будет заметен в очень специфических условиях: на очень больших (как минимум сотни пикселей на экране) треугольниках, на которые к тому же наложена текстура с сильной анизотропностью. Например, если вы наложите вместо шахматной доски на эти же треугольники текстуру песка, то проблемы нет.

Соответственно, вам решать, как именно дешевле всего разобраться с этой проблемой. Я не планировал включать его коррекцию в этот (напоминаю, краткий) курс.
>>> Я не планировал включать его коррекцию в этот (напоминаю, краткий) курс.
Мы все дружно просим вас — включите же! Это очень и очень нужый и полезный элемент.
Ок, добавляю в todo, при случае напишу отдельно.
Да, разумеется, это очень нужно! На курсах компьютерной графики нам говорили, что постоить матрицу перспективного отображения нельзя, так как оно не является афинным преобразованием, а матрицы только такие и описывают (если ничего не путаю). У меня это всегды вызывало недоумение: как же так, а как тогда все игры работают?

А вот оказывается, что на самом деле не такое уж там и перспективное отображение используется…
Я думаю, что вы путаете немного. Если оставаться в своей размерности, то и не всякое аффинное преобразование можно выразить матрицей (линейным приобразованием). Простейший пример — параллельный перенос. Если себе позволить погружение в более ёмкие пространства, то всё хорошо. Что, собственно, я и показывал в этой статье…

Конкретный артефакт не из-за невыразимости перспективного преобразования (вершины-то мы прекрасно нарисовали где и как надо), а из-за линейности самого дешёвого интерполирования.
Да, произнесу очевидную вещь: этот артефакт будет заметен в очень специфических условиях

Например, на таких специфических поверхностях (которые практически не встречаются в играх) как потолок, стены и пол.

если вы наложите вместо шахматной доски на эти же треугольники текстуру песка, то проблемы нет

Если не считать проблемой, что текстура сплющивается в несколько раз вдоль диагоналей прямоугольников.

В софте перспективно-корректное (кусочно-линейное) текстурирование лучше применять всегда, кроме случаев, когда треугольники меньше предела разбиения (16-32 пикселей). Без него получается ужасно страшная картинка (к тому же, в софте обычно используют минимум мелких треугольников, потому что их дорого считать).
Пожалуйста, не надо ёрничать. Постарайтесь общаться спокойно.

Если я правильно понял, предложенный вами метод коррекции точно так же подразбивает домен текстурирования, как и просто более мелкие треугольники. Да, они не проходят через сборщик примитивов, поэтому это быстрее, но всё же.
Посмотрите исправленный автором вариант кода. Диалог тут: habrahabr.ru/post/248963/#comment_8248129
коммит тут: github.com/ssloy/tinyrenderer/commit/af1861a2bcab76bb6294e1971df8917ccd6ab0eb
В нем автоматически решилась эта проблема. (но в коммит примешалось чуть больше чем фикс искажений перспективы)
Задний ход, поправки неверные. Отдельная статья про коррекцию перспективного искажения на подходе.
Между делом вот коммит, подготовленный для поправок, он даёт такую картинку:
Скрытый текст



Этот коммит даёт такую:
Скрытый текст

Обращаю внимание читателей на использование SVG для отрисовки формул в данной статье. Чтобы этого добиться, можно получить любым способом файл в формате DVI (просто передав в TeX файл с формулой), после чего использовать замечательный рендер dvisvgm с такими примерно параметрами:
dvisvgm  --no-fonts --scale=1.5 myfile.tex

Здесь мы требуем:
  • --no-fonts — не пытаться применять вставку текста надписью, а рисовать векторную картинку из текста
  • --scale=1.5 — увеличить все в 1,5 раза. Это зависит от того, какой был использован стиль и размер шрифта. 1,5 хорошо смотрится для article
Маленькая заметка: засада в том, что habrastorage не ест .svg, поэтому их придётся хостить где-то снаружи.
у меня по отдельному теховскому файлу на каждую формулу, вот так они рендерятся в svg:

#!/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
Используя связку из bash, latexml, парочки XSLT и dropbox-uploader, можно автоматизировать процесс превращения статьи из TeX в готовую публикацию, которую будет достаточно только скопипастить.
Угу, после чего читатели начинают наблюдать через некоторое время картинку про Error 509:
Скрытый текст

Это если на дропбокс выдавать то, что Хабрасторадж не подхватывает.
Хостить svg придется в другом месте, khdavid хорошую ссылку дал ниже.
Для формул на хабре я всегда использую этот сервис
www.codecogs.com/latex/eqneditor.php
Он автоматический генерит ссылку на картинку с формулой и очень стабильный.
Сходу я не нашел на нем возможность получить формулу в векторе. Основная неприятность при просмотре растеризованных формул — то что они портятся при масштабировании. У меня хабр всегда увеличен до 200%, поэтому все такие формулы превращаются в распикселенную кашу.

UPD: Нашел, вот так нужно писать:
latex.codecogs.com/svg.download?sin(x)


Второе возражение — в процессе написания статьи (особенно, если для ее изложения понадобились формулы. Не зря Хокингу издатель сказал, что каждая формула вдове сокращает количество читателей) не очень-то удобно постоянно отвлекаться куда-то за формулой. Но у меня «TeX головного мозга», я в этом смысле очень предвзят.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
залил формулы и сюда тоже
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
без картинки тяжело
НЛО прилетело и опубликовало эту надпись здесь
Ну что, очень недурно, хотя ещё есть куда расти :)
Перечитал несколько раз, но так и не понял как из уравнения y1 = y/(1 — z/c) следует вывод: Мы вывели зависимость коэффициентов r = -1/c.. r вы определили в матрицах, но в последующем примере в «обычной» координатной системе никакого r нет.
Правильно, нет, так как r был заменён на -1/c. Изначальная матрица (самая первая в пункте «переходим к 3д») была [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,r,1]]. И я показал, как r связан с расстоянием до камеры c. Больше r не нужен.
Спасибо. Теперь я понял, что это следует из
rz +1 = 1 — z/c
Теперь карты нормалей!

Дошёл до этого урока про матричные преобразования, думая, что тут-то я просто возьму соответствующий код из своей старой реализации движения, вращения и проецирования проволочного куба, но, кажется, я запутался в столбцах и строках. Помню где-то читал, что в 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 паттерн знаков обратный.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации