소프트웨어 렌더러에 대한 z-버퍼링을 구현하는 가장 빠른 방법은 무엇입니까?

StackOverflow https://stackoverflow.com//questions/12677218

문제

저는 (학술적 목적으로) 자바스크립트 소프트웨어 렌더러를 구현하고 있습니다.3D 객체를 삼각형으로 표현하고 3D 공간에서 2D 공간으로의 원근 투영을 처리합니다.

지금까지 나는 lineTo 그리고 fillRect 화면의 꼭지점과 선을 나타냅니다.나는 심지어 사용했다 lineTo 스캔 라인 삼각형 채우기를 수행합니다.(프로젝트를 확인할 수 있습니다. 여기)

지금까지 FPS는 꽤 괜찮았습니다.하지만 과제의 마지막 부분은 z-Buffering :P를 구현하는 것입니다.내가 아는 한, 이를 수행하는 유일한 방법은 다음을 사용하여 삼각형 채우기를 중지하는 것입니다. lineTo 1px 라인 배열이나 1px 정사각형 배열로 채웁니다.(왜냐하면 각 "픽셀"을 그리기 전에 깊이 버퍼를 확인하고 실제로 그려야 하는지 여부를 확인해야 하기 때문입니다.)

문제는 작은 직사각형이나 선으로 삼각형을 채우는 것이 느리다는 것입니다.모든 것을 2FPS로 낮춥니다.제 질문은, 작은 선(더 빠를 수도 있음) 대신 하나의 픽셀을 그리는 방법이 있습니까?

아니면 작업 속도를 높이기 위해 또 무엇을 할 수 있나요?내 목표는 원리를 시연할 수 있을 만큼 빠르게 회전시키는 것입니다.(6~10fps면 충분합니다)

건배.

[편집] 답변을 기다리는 동안 1px 대신 4px ​​크기의 "픽셀"을 그리도록 삼각형 채우기 기능을 수정하겠습니다.하지만 그러면 들쭉날쭉해 보일 거예요...

도움이 되었습니까?

해결책

이것 좀 봐: 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);
});
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top