2014-04-05 82 views
2

我正在製作3D軟件渲染器,並且我已經完成了平移,旋轉和縮放矩陣。如何將投影點轉換爲屏幕座標(視口矩陣)

現在我已經有了一個透視投影矩陣,它將把深度透視應用於我所有的觀點。我不能做的是投影到屏幕座標上的最終透視投影矢量(視口變換)。

這是我現在使用透視投影矩陣: http://puu.sh/7XikH.jpg(抱歉,不能張貼圖片)

所以基本上我需要一個矩陣,將採取一個已經視角投射載體,把它變成屏幕座標。

好吧,這裏的一些代碼:

這是透視投影矩陣,我創建了其中的一個繁衍最後的矩陣我不得不通過它,所以這個乘以最終完全翻譯旋轉和縮放矩陣

public static Matrix4 CreateProjectionMatrix(double znear, double zfar, int width, int height, double fov) 
    { 
     double[,] ret = new double[4, 4]; 

     double e = 1/Math.Tan(MathUtil.GetRadian(fov)/2.0); 
     double ar = width/height; 
     double zp = zfar + znear; 
     double zn = zfar - znear; 

     ret[0, 0] = e; ret[0, 1] = 0;  ret[0, 2] = 0;   ret[0, 3] = 0; 
     ret[1, 0] = 0; ret[1, 1] = e/ar; ret[1, 2] = 0;   ret[1, 3] = 0; 
     ret[2, 0] = 0; ret[2, 1] = 0;  ret[2, 2] = -(zp/zn); ret[2, 3] = -((2 * zfar * znear)/zn); 
     ret[3, 0] = 0; ret[3, 1] = 0;  ret[3, 2] = -1;   ret[3, 3] = 0; 

     return new Matrix4(ret);  
    } 

另一矩陣相乘以該順序:

public Matrix4 GetTransformationMatrix() 
    { 
     Matrix4 translationm = Matrix4.CreateTranslationMatrix(Translation); 
     Matrix4 rotationm = Matrix4.CreateRotationMatrix(Rotation); 
     Matrix4 scalem = Matrix4.CreateScaleMatrix(Scale); 

     //scale -> rotate -> translate 
     return translationm * (rotationm * scalem); 
    } 

,這是最後的矩陣,一個我獲得通過應用立體投影,然後我乘的所有頂點與結果:

public Matrix4 GetProjectedTransformationMatrix() 
    { 
     Matrix4 projectionm = Projection.GetProjectionMatrix(); 
     Matrix4 tranformationm = GetTransformationMatrix(); 

     Matrix4 ret = projectionm * tranformationm; 

     return ret; 
    } 

我缺少一個視口矩陣,當我乘的最終載體與人會給我正確的X和Y屏幕座標。雖然我不使用OpenGL,但我認爲OpenGL或Direct3D設置視口矩陣的方式是可行的。

編輯

我已經解決了問題,雖然不是我想要的方式。

我在尋找一個能處理所有投影和座標變換的矩陣,這些矩陣可以將已經變換過的點與所有模型和視圖矩陣相乘並將其轉換爲屏幕座標。

我在做什麼,現在正在申請相同的透視投影矩陣我收到了,然後除以Z都X和Y,然後將屏幕尺寸的因素,如:

public Point GetProjectedPoint(Vector vec, Matrix4 mat) 
{ 
    Vector point = vec * mat; 

    double px = point.X/point.Z * Width; 
    double py = point.Y/point.Z * Height; 

    return new Point(px, py); 
} 

方式我認爲這會起作用的是透視投影(http://puu.sh/7XikH.jpg)會被Z分開,因爲這是「透視(更遠點=更小)」效應的來源,並且這會給我最終的世界座標(這使我困惑,因爲我在最終的視口投影中除以Z,所以透視投影是怎麼做的?)。

然後,將其轉換爲屏幕座標,視口矩陣首先將所有內容縮放到Normalized Device Coordinates,然後將其映射到屏幕座標。

如果有人可以澄清管道應該是什麼,我應該做什麼,或解釋一個更好的方法,使用適當的矩陣我會很感激。

+1

您可以請張貼一些代碼/嘗試顯示您的進展到目前爲止?有時最好給出例子以獲得更有意義的答案。 – rdonatoiop

回答

2

我無法理解爲什麼您決定在此解決方案中通過剪輯空間Z來劃分座標。

你應該把你的向量的所有分量(包括W)除以W,然後得到的向量就是NDC。在正交投影中,W將是恆定的並且通常是1.0。從視角來看,W將根據與zNear的距離而有所不同。無論您使用什麼樣的投影,立即在輸出模型視圖和投影矩陣(剪輯空間)的乘法結果後,OpenGL和Direct3D會執行W除法以生成NDC座標。這是在頂點輸出後發生的流水線中不可編程的部分。

修剪此分割之後,XYZW範圍之外的任何點:[-1,1],或者以另一種方式表示位於視口之外的點。更正式地說,這通常被描述爲:

        -Clip W¯¯ ≤夾 X,Y,Z ≤剪輯W¯¯

視角改變了遊戲規則一點點,讓NDC座標空間實際上將更多的相機空間壓縮到遠平面的可見部分上而不是近平面。遠點往往除以W.向着視口的中心收斂,但事實仍然是分工仍然是W和Z.不

如果你只是除以z X和Y,然後深度範圍將無法正常工作。在投影和剪切之後,Z也需要在[-1,1]的範圍內,因爲在渲染結束之前,剪輯空間Z座標仍然有另一個轉換。

實際上,當前視口轉換的實現完全沒有深度範圍。將屏幕空間視爲2D座標空間是很誘人的,但Z仍然存在。屏幕空間Z不用於放置像素,但您應該非常熟悉屏幕空間Z,因爲這是深度緩衝區存儲的內容。您需要深度範圍(glDepthRange (...))才能完成視口轉換的最後部分。

+0

我剛剛遇到了同樣的問題,最初除以Z來計算-1到1的範圍,就像猜測一樣,並且它工作得很好。後來我意識到W總是比Z大0.19(將mvp-Matrix與[tz,ty,tz,1]相乘)。有一個簡單的FPS相機設置。 – lama12345

相關問題