2014-06-11 19 views
1

我正在開發用於HTML5畫布的基本射線引擎,該引擎用於像Wolfenstein 3D和Doom這樣的遊戲中作爲學習練習/愛好項目。我已經到了使用紋理貼圖在畫布上繪製牆的地步,經過相當一部分努力獲得相交測試功能之後,這種方法工作得很好。Raycasting引擎渲染創建輕微變形朝向屏幕邊緣增加

我正在糾正「魚缸」/「魚眼」失真效應(由於距離屏幕中心的角度越來越遠到相交點引起的失真效應),但我仍然有一個非常輕微但顯着的彎曲屏幕邊緣的失真。這可以在下面的圖片中可以看到(我畫直線的紅色線條,使效果更明顯):

example of distortion

任何人都可以闡明這是什麼失真的來源是光?這不是一個大問題,但我一直無法找出原因,所以我明顯錯過了一些東西,我相信有人必須知道答案。我已經非常廣泛地搜索了這個問題,並且網上沒有太多信息,但是我在論壇帖子中發現了以下代碼片段:

「使用恆定角增量而不是水平投影引起的翹曲是另一回事 - 這是橫向拉伸/聚束效應,儘管通常只有一個幾乎不明顯的效果(對於合理的FOV,儘管可以定義999999度FOV的事實應該響鈴),但除此之外,根本沒有任何合理的方式來補償它的開始是正確的......使用固定增量的角度是錯誤的,那就是所有這些。「

這聽起來像它可能指的是我正在經歷的同樣的失真,但除了提示固定角度增量是問題的根源之外,它沒有提供太多的幫助或洞察力(這是一個彎曲的失真,朝向屏幕邊緣看起來符合這個建議)。我使用來校正失真的功能是:

function m_CorrectRayLengthDistortion(dist, angleFromCentre){ 

    return dist * Math.cos(MOD_Maths.degToRad(angleFromCentre)); 
} 

MOD_Maths是一個公用程序模塊(在這種情況下用於從度的角度轉換爲弧度,從而餘弦函數可以使用它)。

對此的任何幫助都非常感謝,如果有人回答此問題,希望爲將來任何人遇到問題提供指導,因爲在線可用的主題缺乏信息。

謝謝:)

+0

這並不像Wolfenstein/Doom的光線投射。他們使用了多個像素寬的列用於牆壁,但在這裏您似乎有1個像素寬的列;那個,或者你的紋理映射是離開的。 –

+0

是的,我使用1像素寬的列,但這與我提到的遊戲(我只是試圖從同一個渲染系統中獲得更高的分辨率)是微不同的。我不是想複製Doom或Wolf3D的復古外觀,那不是重點。 –

回答

3

正常前一段我解決了這個問題,但還沒有得到全面更新了答案直到現在。我刪除了我以前的答案,這是不正確的(它給了幾乎正確的結果,但通過間接方法,這要歸功於我對問題的根本原因缺乏瞭解)。

正如Sam在他之前的評論中提到的,問題的根本原因在於,如果要實現等間隔列(渲染結果看起來不失真所必需),固定角度增量實際上是不正確的。這在論壇帖子here中提到過,但儘管我發現這一點,但我並沒有完全理解爲什麼會出現這種情況,或者如何解決問題,直到很久以後。

爲了在屏幕上實現等間距的列,理所當然的是,每條光線必須從視點移動並穿過沿着投影表面等距分佈的像素,這意味着隨着光線進一步從屏幕的中心像素逐漸變小,從視線方向角度增加。這是通過下面的圖像示出(道歉,它不是本領域的恰好一個工作):

diagram

隨着視圖小字段的問題不是很明顯,但隨着領域更成問題視圖增加(在我的圖中,視野非常大以清楚地說明問題)。正確計算光線角度增量,下面的處理必須使用:

其中:

ang = ray angle from the look direction, whose ray passes through the central x coordinate of the screen; 
opp = opposite side (equivalent to the distance of the screen X coordinate through which the ray passes from the screen X coordinate of the central pixel); 
adj = adjacent side (equivalent to the distance from the point of view to the projection surface, which will be predetermined in code somewhere); 

我們可以使用下面的公式(包括爲清楚起見推導):

tan(ang) = opp/adj 
ang = atan(opp/adj) 
ang = atan((pixel x coord - half screen width)/dist to projection surface) 

Javascript代碼例如來自我的引擎:

for(var x = 0; x < canvasSizeX; x++){ 

    var xAng = _atan((x - canvasSizeHalfX)/m_DistToProjSurf); 
    xRayAngles.push(xAng); 
} 

由於有些sc raycasting引擎上的信息性質,這些信息可以在線獲得,並且由於這個特定問題沒有在任何主要教程中明確涵蓋,所以我想用正確的信息更新這篇文章,以防萬一其他人也有同樣的問題,我不明白爲什麼。希望這會幫助某人。

+1

這裏有一個很好的解釋,並在這裏解決http://www.gamedev.net/topic/635066-2d-ray-casting-problems-dont-align-correctly/。它似乎是因爲增加角度線性假設列覆蓋恆定的角度,但事實並非如此;中間的列比左側/右側的列覆蓋更大的角度。這對我來說並不完全直觀,但你去了,這似乎是原因。 – Sam

+0

謝謝,經過一些進一步的研究,我已經更新了我的答案:) –

+1

謝謝!在我寫了評論之後,我想到了更多的內容,並閱讀並重新閱讀了這篇文章中的評論,最終得到了它。你的圖也有幫助!我正在計劃撰寫一篇關於光線投射的博客文章,希望能有更多關於它的信息:) – Sam