Мне нужно написать собственный программный 3d растеризатор, и пока я могу проецировать свою 3d модель из треугольников в 2d пространство:
Я вращаю, перемещаю и проецирую свои точки, чтобы получить двухмерное представление каждого треугольника. Затем я беру 3 точки треугольника и реализую алгоритм линии сканирования (используя линейную интерполяцию), чтобы найти все точки [x] [y] по краям (слева и справа) треугольников, чтобы я мог сканировать треугольник по горизонтали, строка за строкой, и заполните его пикселями.
Это работает. Кроме того, я должен также реализовать z-буферизацию. Это означает, что, зная повернутые и переведенные z-координаты 3-х вершин треугольника, я должен интерполировать z-координату для всех остальных точек, которые я найду с помощью моего алгоритма линии сканирования.
Концепция кажется достаточно ясной, я сначала нахожу Za и Zb с этими вычислениями:
var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);
Затем для каждого Zp я делаю ту же интерполяцию по горизонтали:
var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);
И если текущий z ближе к зрителю, чем предыдущий z с этим индексом, ТО записывает цвет в буфер цвета И записывает новый z в буфер z. (моя система координат: x: слева -> справа; y: сверху -> снизу; z: ваше лицо -> экран компьютера;)
Проблема в том, что это сходит с ума. Проект находится здесь, и если вы выберете переключатель «Z-Buffered», вы увидите результаты ... ( обратите внимание, что я использую алгоритм рисовальщика (-только - для рисования каркаса) в режиме «Z-Buffered» в целях отладки )
PS: я читал здесь, что вы должны превратить z в их взаимные (смысл z = 1/z
), прежде чем интерполировать. Я попробовал это, и кажется, что нет никаких изменений. Что мне не хватает? (кто-нибудь может уточнить, где именно вы должны превратить z в 1 / z и где (если), чтобы повернуть его обратно?)
[РЕДАКТИРОВАТЬ] Вот некоторые данные о том, какие максимальные и минимальные значения z я получаю:
max z: 1; min z: -1; //<-- obvious, original z of the vertices of the triangles
max z: 7.197753398761272; min z: 3.791703256899924; //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.
Прежде чем приступить к кропотливой отладке, может ли кто-нибудь подтвердить, что моя концепция до сих пор верна?
[EDIT2]
Я решил z-буферизацию. Как выяснилось, порядок рисования совсем не испортился. Координаты z рассчитывались правильно.
Проблема заключалась в том, что, пытаясь увеличить частоту кадров, я рисовал прямоугольники 4px / 4px, каждый 4-й пиксель, вместо реальных пикселей на экране. Поэтому я рисовал 16 пикселей на пиксель, но проверял буфер z только для одного из них. Я такая сиська.
TL / DR: Вопрос все еще стоит: как / почему / когда вы должны использовать обратную величину Z (как в 1 / z) вместо Z? Потому что сейчас все работает в любом случае. (нет заметной разницы).