2012-10-01 3 views
0

저는 (자바 스크립트 목적으로) 자바 스크립트 소프트웨어 렌더러를 구현하고 있습니다. 3D 오브젝트를 삼각형으로 표현하고 3D 공간에서 2D 공간으로 투시 투영을 처리합니다.소프트웨어 렌더러에서 z- 버퍼링을 구현하는 가장 빠른 방법은 무엇입니까?

지금까지 화면의 정점과 선을 나타 내기 위해 lineTofillRect을 사용했습니다. 심지어는 lineTo을 사용하여 주사선 삼각형을 채 웁니다. (당신은 프로젝트 here를 체크 아웃 할 수 있습니다)

지금까지 FPS는 상당히 훌륭했습니다. 그러나 과제의 마지막 부분은 z-Buffering : P를 구현하는 것입니다. 내 지식으로는 이것을 수행하는 유일한 방법은 lineTo을 사용하여 삼각형을 채우지 않고 1px 행 배열 또는 1px 사각형 배열로 채우는 것입니다. (각 "픽셀"을 그리기 전에 깊이 버퍼를 확인하고 실제로 그려야하는지 여부를 확인해야합니다.)

작은 직사각형이나 선이있는 삼각형을 채우는 것이 느립니다. 2FPS까지 모든 것을 가져옵니다. 그래서 내 질문은 거기에 작은 라인 (빠른 수 있습니다) 대신 하나의 픽셀을 그릴 수있는 방법이 무엇입니까?

다른 방법으로 속도를 높이려면 어떻게해야합니까? 내 목표는 원칙을 시연하기에 충분할 정도로 빨리 회전시키는 것입니다. (6-10fps이면 충분합니다.)

건배.

[편집] 답변을 기다리는 동안 삼각형 채우기 기능을 수정하여 1px 대신 4px ​​크기의 "픽셀"을 그려야합니다. 그러나이 jaggedy ...

+1

는 각 폴리곤/삼각형의 깊이를 추적하기 만하고, 가까운 곳 (페인터의 알고리즘)에 멀리에서 그들을 렌더링합니다. – Shmiddty

+0

나는 각 점의 깊이의 평균이 물건을 칠해야하는 순서를 결정하기에 충분하다고 생각한다. – Shmiddty

+0

@Shmiddty 화가의 알고리즘을 알고 있습니다. 그러나 과제는 그렇지 않습니다. 또한 painter의 alg는 이것을 할 수 없습니다 : http://www.cores2.com/3D_Tutorial/_images/PainterFail.png – Spectraljump

답변

2

체크 아웃 모양 : 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); 
}); 
+0

JSFiddle은 더 이상 사용할 수없는 리소스 링크로 인해 손상된 것 같습니다. – Job