Мені потрібно написати свій власний програмний 3D-растризатор, і поки що я можу спроектувати свою 3d-модель з трикутників у 2d простір:
Я обертаю, перекладаю і проектую свої точки, щоб отримати 2d-пробільне представлення кожного трикутника. Потім я беру три точки трикутника і реалізую алгоритм сканування (використовуючи лінійну інтерполяцію), щоб знайти всі точки [x] [y] по краях (зліва та справа) трикутників, щоб я міг сканувати трикутник по горизонталі, рядок за рядком і заповнюйте його пікселями.
Це працює. За винятком того, що я також повинен реалізувати z-буферизацію. Це означає, що знаючи обернені та перекладені z координати трьох вершин трикутника, я повинен інтерполювати координату 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 і де (якщо), щоб повернути його назад?)
[EDIT] Ось деякі дані щодо того, які максимальні та мінімальні значення я отримую:
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 поля, кожен четвертий піксель, а не фактичні пікселі на екрані. Тому я малював 16 пікселів на піксель, але перевіряв буфер z лише для одного з них. Я такий сиськи.
TL / DR: Питання все ще стоїть: як / чому / коли потрібно використовувати зворотні Z (як у 1 / z) замість Z? Тому що зараз все працює в будь-якому випадку. (помітної різниці немає).