2017-05-04 98 views
0

我一直在寫一個簡單的3d渲染器,並一直在研究繪製順序。該引擎將3d多邊形(按正確繪圖順序的3d點組)渲染到2d空間中,返回代表給定多邊形投影的2d點列表。我這樣做的方法可能有點非正統的,因爲我想看看我是否能夠做我自己,所以我重視我的代碼如下預測:如何用簡單的多邊形使用ZBuffer?

public class Camera { 
/*position is the position of the camera, x, y, z; 
cameraRotation is the rotation of the camera, in the order of rotation about x, rotation about y, rotation about z 
the camera initially faces the +x direction 
*/ 
private double focalAngle; 
private double[] position, cameraRotation, cameraDirectionVector, cameraXVector, cameraZVector; 
private double[][][] rotationMatrices = new double[3][3][3]; 
private double[][] compoundedRotationMatrices; 

public Camera(double[] positionIn, double[] cameraRotationIn, double focalAngleIn){ 
    position = positionIn; 
    focalAngle = focalAngleIn; 
    cameraRotation = cameraRotationIn; 
    updateRotation(); 
} 

private void updateRotation(){ 
    updateRotationMatrices(); 
    updateCameraDirectionVector(); 
} 

private void updateRotationMatrices(){ 
    compoundedRotationMatrices = Matrix.getCompoundedRotationMatrix(cameraRotation[0], cameraRotation[1], cameraRotation[2]); 
} 

private void updateCameraDirectionVector(){ 
    double[] xVector = {1,0,0}; 
    double[] yVector = {0,-1,0}; 
    double[] zVector = {0,0,1}; 
    cameraDirectionVector = Matrix.vecMultiply(compoundedRotationMatrices, xVector); 
    cameraXVector = Matrix.vecMultiply(compoundedRotationMatrices, yVector); 
    cameraZVector = Matrix.vecMultiply(compoundedRotationMatrices, zVector); 
} 

public ArrayList<int[][]> getPolygonProjections(ArrayList<double[][]> polySets, double screenWidth, double screenHeight){ 
    ArrayList<int[][]> outPoints = new ArrayList(); 
    for(int i = 0; i < polySets.size(); i++){ 
     int[][] polyPoints = new int[2][polySets.get(i).length]; 
     /*in the calculation of proejctions, divide by zeros and NaNs can pop up, 
     polygonsLegitimate boolean keeps track of whether the polygon being drawn can be drawn without error, 
     and the while loop stops calcuating the polygon once it determines it cannot be properly drawn 
     */ 
     boolean polygonsLegitimate = true; 
     int j = 0; 
     while(j < polyPoints[0].length && polygonsLegitimate){ 
      int[] xy = getVectorProjection(polySets.get(i)[j], screenWidth, screenHeight); 
      if(xy != null){ 
       polyPoints[0][j] = xy[0]; 
       polyPoints[1][j] = xy[1]; 

      }else{ 
       polygonsLegitimate = false; 
      } 
      j++; 
     } 
     if(polygonsLegitimate){ 
      outPoints.add(polyPoints); 
     } 
    } 
    return outPoints; 
} 

private int[] getVectorProjection(double[] vector, double screenWidth, double screenHeight){ 
    double[] subVector = Vector.subtract(vector, position); 
    double zDepth = getZDepthOfVector(subVector); 
    if(zDepth > 0){ 
     double sliceSize = getSliceSizeAtDepth(zDepth); 
     double cameraXProj = Vector.dot(subVector, cameraXVector); 
     double cameraZProj = Vector.dot(subVector, cameraZVector); 
     double xPercent = (cameraXProj+(sliceSize/2))/sliceSize; 
     double zPercent = (cameraZProj+(sliceSize/2))/sliceSize; 
     int[] xy = {(int)(xPercent * screenWidth),(int)((((1-zPercent) * screenWidth))-(screenHeight/2))}; 
     return xy; 
    } 
    return null; 
} 

public double getZDepthOfVector(double[] vector){ 
    return Vector.dot(cameraDirectionVector, vector); 
} 

private double getSliceSizeAtDepth(double zDepth){ 
    return 2.0*Math.cos(focalAngle)*zDepth; 
} 

目前,我決定通過排序繪製順序三維多邊形除以多邊形最靠近角落到相機的距離,然後按最遠多邊形到最近多邊形的順序繪製。然而,由於抽籤順序是完全基於多邊形到相機的最近點的距離來確定,有防止算法有時正常工作了幾cornercases,如本視頻:

https://youtu.be/olTOTOCw42M

我已經在Z緩衝區做了大量的研究,而且這個概念很簡單 - 實際上與我正在做的非常相似。就我的理解而言,對於每個渲染像素,將比較同一像素上呈現的所有點,並顯示距離攝像機最近的z深度。然而,考慮到在這種情況下,我正在使用的唯一要點就是組成每個多邊形拐角的那些點,我不知道一個好方法來比較多邊形中包含的任何點的z深度而不僅僅是在角落。

我有這個問題有兩個可能的解決方案:)

1拆分每個多邊形成多個更小的多邊形。當我嘲笑Python中的渲染器時,我從未在Z深度排序中添加,但是我確實將每個多邊形劃分爲多個較小的多邊形,這樣我可以非常容易地分別點亮每個多邊形,結果如下所示:

http://imgur.com/a/U3Xke

然而,這是非常昂貴的,因爲許多投影點被多次投影,因爲它們的值是通過計算相鄰多邊形的投影來確定的。也許有一個合理的方法來解決這個問題,但對我來說,看起來太粗糙是沒有道理的。

2)找到每個三維多邊形所在的平面,將其限定爲多邊形的形狀,然後求解與這些平面通過視角定向的各個掃描線的交點,然後選擇與距攝像機最近的z深度顯示在該掃描線的像素處。這樣,不是每個多邊形的投影點用java的多邊形填充方法填充,每個像素將被單獨渲染。然而,我不確定如何「綁定」一架飛機,使其不會超出多邊形的邊界,對我來說理解起來有點棘手,因爲目前數學對我而言有點過於先進。如果這是應該完成的方式,我可以學習,我只是想確保這是一種可行的方法。 3)將每個多邊形分成許多點的集合,而不是分成更小的多邊形:我認爲這種方法會有缺陷,因爲一個好的渲染所需的點的數量(即每個像素一個3d點,不需要相同多邊形形狀上的多個3d點渲染到完全相同的像素上,或者具有太少的3d點以致像素在渲染過程中被「跳過」)隨Z深度和用於計算將這些點放置在何處的公式每次移動相機似乎都很難制定並且運行起來很昂貴。

回答

0

使用排序表,Playstation 1使用的算法。

將Z範圍分成N個相同大小的部分。

  • 創建N個指向多邊形的指針數組。
  • 每幀都將該數組清零。
  • 對於每一個三角形要繪製:
    • 計算出相應的Z-指數我。
    • 將它插入訂單[i]就像鏈接列表一樣。
  • 經過反向(後到前)的陣列,繪畫三角形你遍歷

C代碼

Triangle *Order[256]; 

void Clear() { 
    memset(Order,0,sizeof(Order)); 
} 

void Insert(Triangle *tri) { 
    int index = (tri->averageZ-zNear) * 256/(zFar - zNear); 
    tri->next = Order[index]; 
    Order[index] = tri; 
} 

void Paint() { 
    for(int i=255;i>=0;i--) 
     for(Triangle *tri=Order[i];tri;tri=tri->next) 
      DrawTriangle(tri); 
} 

來源:小煜 「RYG」 吉森(Farbrausch的成名)有一個題爲「當光速不夠快」的演講,他提出了這個想法,包括這個代碼。

0

我認爲你誤解了Z緩衝區的想法,最接近真相的是你的解決方案沒有。 3) - 將你的多邊形分割成單個像素。

Z緩衝區每像素工作,是的,有很多Z比較,但它是如何工作。您不能將其簡化爲僅使用多邊形的特定頂點。

我假設你有一些網格讓我們說'顏色'結構,你要填充你的渲染。這將成爲您的目標圖像。您需要添加另一個同樣大小的浮動網格 - 這將是您的Z緩衝區。在開始時,你用一些大的值填充你的Z緩衝區,比如1​​000000.

現在忽略多邊形的排序--Z緩衝區會爲你解決它。您可以稍後添加排序以測試不同繪圖訂單之間的性能差異,但不需要使其工作。

現在您需要光柵化階段,在這裏您可以傳遞多邊形邊角並獲取該多邊形覆蓋的所有像素列表。您可以使用掃描線來計算它,正如您在2)中所述。我建議你爲單個三角形編寫光柵化,並將所有的多邊形分割成三角形,這將使你的代碼更簡單。如果你願意的話,你可以返回這個階段的像素列表(在這種情況下,列表將會很慢,但對於學習目的來說很好)。最好在這個階段直接填充像素網格,而不是將這些數據存儲在內存中)但是你需要一個重要的改變 - 除了X和Y之外,像素需要正確的Z值。

當你有這樣的光柵化像素列表時,你只需將它們放入像素網格,這就是Z測試發生的地方。迭代每個像素,並使用像素屏幕位置(X,Y)從Z緩衝區中讀取當前Z值。如果該值大於當前像素的Z值,則在彩色緩衝區中寫入像素顏色,在Z緩衝區中寫入像素Z.

+0

這對我的問題有更多的瞭解,但我怎樣才能單獨計算在某個像素上繪製的多邊形上的3d點的Z值?我知道一個光線是通過與給定像素的x和y位置相交的角度從相機的位置投射出來的,但是我怎樣才能確定這個光線通過像素與多邊形相交的Z深度(這只是一個列表3D點在每個角落)? – pete2fiddy

+0

爲了便於說明,在選項3中,我實際上是在討論如何將3d多邊形點分成許多3d點,以便在投影后將一個點用於屏幕上的一個像素。然而,我不確定如何去解決這個問題(而且這看起來也不正確) - 從我所知道的情況來看,不是將多邊形分成多個3d點,而是要讓我畫出它因爲我現在只使用它的角點,然後確定多邊形的每個繪製像素之後的多邊形的Z深度,然後進行Z深度比較。 – pete2fiddy

+0

您可以通過插值Z值從多邊形頂點計算像素Z. Raycast對此會慢很多。從現在開始,將您的聚合物分解成三角形並考慮三角形。現在你正在繪製一個三角形,它的三個角都在屏幕上,每個都有X,Y,Z值。對於此三角形內的每個像素,可以使用像素到角點的距離來插值Z值。它被稱爲重心座標,你可以在這裏閱讀它https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes – kolenda

相關問題