Самый быстрый способ реализовать z-буферизацию для программного средства визуализации?
-
12-12-2019 - |
Вопрос
Я внедряю программный рендерер javascript (для академических целей).Он обрабатывает представление 3d-объекта в виде треугольников и обрабатывает перспективную проекцию из 3d-пространства в 2d-пространство.
До сих пор я пользовался lineTo
и fillRect
для представления вершин и линий на экране.Я даже использовал lineTo
чтобы выполнить заполнение треугольника линии сканирования.(вы можете ознакомиться с проектом здесь)
До сих пор FPS был довольно хорошим.Но последняя часть задания заключается в реализации z-буферизации:P.Насколько мне известно, единственный способ сделать это - прекратить заполнять мои треугольники с помощью lineTo
и заполните их либо массивом строк размером 1 пиксель, либо массивом квадратов размером 1 пиксель.(потому что, прежде чем я нарисую каждый "пиксель", я должен проверить буфер глубины и посмотреть, действительно ли я должен его нарисовать или нет.)
Проблема в том, что заполнение треугольников крошечными прямоугольниками или линиями происходит медленно.Сокращает скорость до 2 кадров в секунду.Итак, мой вопрос в том, есть ли какой-нибудь способ нарисовать один пиксель вместо крошечной линии (что может быть быстрее)?
В качестве альтернативы, что еще я могу сделать, чтобы ускорить процесс?Моя цель - заставить его вращаться достаточно быстро, чтобы продемонстрировать принцип.(6-10 кадров в секунду было бы достаточно)
Ваше здоровье.
[РЕДАКТИРОВАТЬ] Пока я жду ответа, я попробую изменить свои функции заполнения треугольника, чтобы рисовать "пиксели" размером 4 пикселя вместо 1 пикселя.Но это будет выглядеть неровно...
Решение
Зацени это: http://jsfiddle.net/ZXjAM/2/
// points 0,1,2,3 front face
var fAvgZ = (cube.processPoints[0].colorZ +
cube.processPoints[1].colorZ +
cube.processPoints[2].colorZ +
cube.processPoints[3].colorZ) / 4 / 20;
// points 0,2,4,6 top
var tAvgZ = (cube.processPoints[0].colorZ +
cube.processPoints[2].colorZ +
cube.processPoints[4].colorZ +
cube.processPoints[6].colorZ) / 4 / 20;
// points 4,5,6,7 rear
var reAvgZ = (cube.processPoints[4].colorZ +
cube.processPoints[5].colorZ +
cube.processPoints[6].colorZ +
cube.processPoints[7].colorZ) / 4 / 20;
// points 1,3,5,7 bottom
var bAvgZ = (cube.processPoints[1].colorZ +
cube.processPoints[3].colorZ +
cube.processPoints[5].colorZ +
cube.processPoints[7].colorZ) / 4 / 20;
// points 2,3,6,7 right side
var rAvgZ = (cube.processPoints[2].colorZ +
cube.processPoints[3].colorZ +
cube.processPoints[6].colorZ +
cube.processPoints[7].colorZ) / 4 / 20;
// points 0,1,4,5 left side
var lAvgZ = (cube.processPoints[0].colorZ +
cube.processPoints[1].colorZ +
cube.processPoints[4].colorZ +
cube.processPoints[5].colorZ) / 4 / 20;
var layers = [{key:0, val:fAvgZ},
{key:1, val:fAvgZ},
{key:2, val:tAvgZ},
{key:3, val:tAvgZ},
{key:4, val:reAvgZ},
{key:5, val:reAvgZ},
{key:6, val:bAvgZ},
{key:7, val:bAvgZ},
{key:8, val:rAvgZ},
{key:9, val:rAvgZ},
{key:10, val:lAvgZ},
{key:11, val:lAvgZ}];
var outLay = layers.sort(function(a,b){
return (a.val - b.val);
});
for(var i = 0; i < outLay.length; i++)
{
var k = outLay[i].key;
...
}
Это ни в коем случае не самый эффективный способ усреднения / сортировки значений точек, и, вероятно, это можно сделать с меньшим количеством строк кода, используя уже существующие свойства куба, но основная концепция остается прежней.
Я нахожу средний z-индекс и использую его для определения порядка наслоения.Очевидно, что это никогда не сработает для всего, но для простых многогранников этого должно быть достаточно.
Это может быть упрощено до:
var layers = [];
for (var i = 0; i < cube.sides.length; i++){
var side = cube.sides[i];
var avg = (cube.processPoints[side.a].colorZ +
cube.processPoints[side.b].colorZ +
cube.processPoints[side.c].colorZ) / 3 / 20;
layers.push({key:i, val:avg});
}
var outLay = layers.sort(function(a,b){
return (a.val - b.val);
});
Похоже, действительно есть некоторые второстепенные случаи, когда возникает проблема с быстрым оформлением заказа.
Это кажется более точным: http://jsfiddle.net/ZXjAM/4/
var layers = [];
for (var i = 0; i < 12; ++i){
var side1 = cube.sides[i];
var side2 = cube.sides[++i];
var avg = (cube.processPoints[side1.a].colorZ +
cube.processPoints[side1.b].colorZ +
cube.processPoints[side1.c].colorZ +
cube.processPoints[side2.a].colorZ +
cube.processPoints[side2.b].colorZ +
cube.processPoints[side2.c].colorZ) / 6;
layers.push({key:i-1, val:avg});
layers.push({key:i, val:avg});
}
var outLay = layers.sort(function(a,b){
return (a.val - b.val);
});