2010-05-21 31 views
1

雖然這個問題的背景是關於製作2D/3D遊戲,但我已經歸結爲一些數學問題。 雖然它是一個2.5D的世界,但我們假裝它只是2d的這個問題。我已經完成了我的2D/3D轉換工作,如何做透視

// xa: x-accent, the x coordinate of the projection 
// mapP: a coordinate on a map which need to be projected 
// _Dist_ values are constants for the projection, choosing them correctly will result in i.e. an isometric projection 
xa = mapP.x * xDistX + mapP.y * xDistY; 
ya = mapP.x * yDistX + mapP.y * yDistY; 

xDistX和yDistX確定x軸的角度,以及xDistY和yDistY確定y軸的角度上的突起(以及網格的大小,但讓我們假設這是1-像素以簡化)。

x-axis-angle = atan(yDistX/xDistX) 
y-axis-angle = atan(yDistY/yDistY) 

一個這樣

--------------- x 
| 
| 
| 
| 
| 
y 

has values like this: 
xDistX = 1; 
yDistX = 0; 
xDistY = 0; 
YDistY = 1; 

「正常」座標系,使在x方向上的每一個步驟將導致在投影到1個像素到右端0像素下來。投影y方向上的每一步都會導致向右0步和向下1步。 當選擇正確的xDistX,yDistX,xDistY,yDistY時,可以投影任何三角形或二維繫統(這就是爲什麼我選擇了這個)。

到目前爲止好,當這是繪製的時候,一切都變好了。如果「我的系統」和思維清晰,讓我們繼續前進。 我想一些觀點添加到該網格,以便我加了一些額外的像這樣:

camera = new MapPoint(60, 60); 
dx = mapP.x - camera.x; // delta x 
dy = mapP.y - camera.y; // delta y 
dist = Math.sqrt(dx * dx + dy * dy); // dist is the distance to the camera, Pythagoras etc.. all objects must be in front of the camera 

fac = 1 - dist/100; // this formula determines the amount of perspective 

xa = fac * (mapP.x * xDistX + mapP.y * xDistY) ; 
ya = fac * (mapP.x * yDistX + mapP.y * yDistY); 

現在真正困難的部分......如果你有什麼(XA,YA)以投影點和希望計算原點(x,y)。 對於第一種情況(沒有透視圖),我確實找到了反函數,但是如何用這個透視圖來完成公式。 5月的數學技能並不完全可以解決這個問題。

(我依稀從很久以前記得數學可以創造一些特殊情況下的反函數......可以把它解決這個問題?可能有人也許嘗試?)

+0

fac是什麼?什麼是「視角量」? 100與什麼有什麼關係? fac是爲了實現由於視角而明顯縮小的物體。這使距離爲100的物體的大小爲零,所以這沒有意義? – sigfpe 2010-05-21 18:52:30

+0

fac代表因子,就像一個透視因子,可以調整大視角或小視角。使用這個函數繪製網格給了一些看起來不錯的東西。對象應始終放置在攝像機前的「柵格」上。這意味着一個物體的距離不會超過sqrt(60^2 + 60^2)85.我選擇100的原因是因爲它大於85,並且給了我所需要的外觀。 我的功能是不正確的,但視覺效果看起來不錯,雖然「透視」有點過頭...... http://img188.imageshack.us/img188/5154/gridpu.png – jdv145 2010-05-22 10:13:55

回答

1

你定義函數不有一個逆。舉個例子,如user207422已經指出任何距離攝像機100個單位的東西都會被映射到(xa,ya)=(0,0),所以逆並不是唯一定義的。

更重要的是,這不是你如何計算透視圖。通常,透視縮放因子被定義爲viewdist/zdist,其中zdist是從相機到物體的垂直距離,並且viewdist是常數,其是從相機到所有投影的假想屏幕的距離。 (請參見圖here,但可以忽略該頁面上的所有其他內容。)您在示例中使用的縮放因子不具有相同的行爲。

這裏有一個試圖將你的代碼轉換成正確的透視計算(注意我不是簡化爲2D;透視是關於將三維投影到兩個,試圖將問題簡化爲2D是毫無意義的):

camera = new MapPoint(60, 60, 10); 
camera_z = camera.x*zDistX + camera.y*zDistY + camera.z*zDistz; 

// viewdist is the distance from the viewer's eye to the screen in 
// "world units". You'll have to fiddle with this, probably. 
viewdist = 10.0; 

xa = mapP.x*xDistX + mapP.y*xDistY + mapP.z*xDistZ; 
ya = mapP.x*yDistX + mapP.y*yDistY + mapP.z*yDistZ; 
za = mapP.x*zDistX + mapP.y*zDistY + mapP.z*zDistZ; 

zdist = camera_z - za; 
scaling_factor = viewdist/zdist; 
xa *= scaling_factor; 
ya *= scaling_factor; 

你只打算從這個函數返回xaya; za僅用於透視計算。我假設「za方向」指向屏幕外,所以如果預投影x軸指向觀看者,那麼zDistX應該是正值,反之亦然,並且類似地對於zDistY。對於三角投影,您可能有xDistZ==0yDistZ<0zDistZ==0。這將使預投影z軸點直線投影后。

現在壞消息:這個函數也沒有反函數。任何點(xa,ya)都是無限多個點(x,y,z)的圖像。但!如果你假設z = 0,那麼你可以解出x和y,這可能就足夠了。

要做到這一點,你必須做一些線性代數。計算camera_xcamera_y類似於camera_z。這是相機的轉換後坐標。屏幕上的點具有後變形座標(xa,ya,camera_z-viewdist)。通過這兩點繪製一條直線,並計算由矢量(xDistX, yDistX, zDistX)(xDistY, yDistY, zDistY)跨越的平面的相交位置。換句話說,您需要解出方程式:

x*xDistX + y*xDistY == s*camera_x + (1-s)*xa 
x*yDistX + y*yDistY == s*camera_y + (1-s)*ya 
x*zDistX + y*zDistY == s*camera_z + (1-s)*(camera_z - viewdist) 

這並不美觀,但它會起作用。

1

我認爲,與您的帖子我可以解決問題。然而,要澄清一些問題:

解決2d中的問題確實沒有用,但這只是爲了使問題更易於掌握(對於我和讀者來說)。我的程序實際上給出了一個完美的3D投影(我用攪拌機渲染的3D圖像進行了檢查)。儘管如此,我確實遺漏了一些關於反函數的內容。反函數僅適用於0..camera.x * 0.5和0 .. camera.y * 0.5之間的座標。所以在我的例子中介於0到30之間。但是即使如此,我還是懷疑我的功能。

在我的投影中,z軸始終筆直向上,因此要計算物體的高度,我只使用vieuwingangle。但是因爲你實際上不能飛入天空或者跳入天空,所以只有2d的一點。這也意味着,當你試圖解決x和y時,z確實是0.

我知道並不是每個函數都有一個反函數,有些函數只能用於特定的域。我在這一切中的基本思想是......如果我可以使用一個函數繪製一個網格...那個網格上的每一個點都映射到一個映射點。我可以讀取x和y座標,所以如果我只是有正確的功能,我將能夠計算逆。 但是,沒有更好的替代,然後一些好的堅實的數學,我非常高興你花時間給了一個非常有益的迴應:)。

+2

只爲未來參考,這通常會編輯您的問題,或者在評論中。 – Joren 2010-05-22 11:09:00

相關問題