2013-03-27 68 views
2

我正在實現動態視場。我決定使用着色器來使照明更好看,以及它如何影響牆壁。這是我工作的場景: http://i.imgur.com/QxZVyo7.jpg使用着色器在2D環境中實現視場

  1. 我有地圖,有平坦的地面和牆壁。這裏的每一件事都是2D,沒有3D幾何,只有2D多邊形組成牆。

  2. 使用投影陰影的多邊形的頂點來定義可視區域。 (紫色線條是我在下一步中使用的蒙版的一部分)

  3. 在場景頂部繪製陰影時使用着色器,我避免牆也被遮擋。

  4. 這樣的陰影爲視野改變

我用下面的着色器來實現這一沿着牆壁動態投。但是我覺得這是怎樣的一個矯枉過正的和真的效率不高:

uniform sampler2D texture; 
uniform sampler2D filterTexture; 
uniform vec2 textureSize; 
uniform float cellSize; 
uniform sampler2D shadowTexture; 



void main() 
{ 
    vec2 position; 
    vec4 filterPixel; 
    vec4 shadowPixel; 
    vec4 pixel = texture2D(texture, gl_TexCoord[0].xy); 


    for(float i=0 ; i<=cellSize*2 ; i++) 
    { 
     position = gl_TexCoord[0].xy; 
     position.y = position.y - (i/textureSize.y); 
     filterPixel = texture2D(filterTexture, position); 

     position.y = position.y - (1/textureSize.y); 
     shadowPixel = texture2D(texture, position); 

     if (shadowPixel == 0){ 
      if(filterPixel.r == 1.0) 
      { 
       if(filterPixel.b == 1.0){ 
        pixel.a = 0; 
        break; 
       } 
       else if(i<=cellSize) 
       { 
        pixel.a = 0; 
        break; 
       } 
      } 
     } 
    } 

    gl_FragColor = pixel; 
} 

迭代每個frament只是去尋找紅色像素的面具看起來像一個巨大的過載,但我看不出如何完成這通過使用着色器以任何其他方式進行。

+0

爲什麼你想使用着色器呢? – 2013-03-27 12:10:29

+0

我正在使用的庫是SFML。我試圖弄清楚如何讀取圖像上的像素信息(以便將可見光像素上方的牆設置爲可見),但操作非常緩慢,並且應該對每個像素進行此過程,所以它不是真的可行。我遇到了着色器,並決定嘗試一下。我喜歡這個結果,但是我擔心表現並不好,但我對着色器完全陌生,所以我想聽聽其他人的意見。 – Leo 2013-03-27 12:14:04

回答

3

這裏的解決方案非常簡單:使用陰影貼圖。

您的情況可能是2D而不是3D,但基本概念是相同的。你想根據世界上某個點與「光源」(你的情況,玩家角色)之間是否存在障礙物表面來「遮蔽」區域。

在3D中,陰影貼圖通過從光源的角度渲染世界來工作。這導致了2D紋理,其中值表示從光線(在特定方向)到最近的障礙物的深度。當您渲染真實場景時,通過將其投影到2D深度紋理(陰影貼圖)中來檢查當前片段的位置。如果您爲當前片段計算的深度值比陰影圖中投影位置中距離最近的障礙更近,則可以從光線中看到片段。如果不是,那麼它不是。

您的2D版本將不得不做同樣的事情,只有少一個維度。從「光源」的角度來渲染你的2D世界。在這種情況下,你的2D世界實際上只是阻礙四邊形(你將不得不用線多邊形填充來渲染它們)。任何妨礙視線的四邊形應該被渲染到陰影圖中。紋理訪問是完全不必要的;你需要的唯一信息就是深度。你的着色器甚至不必寫顏色。通過將2D空間投影到1D紋理中來渲染這些對象。

這將是這個樣子:

 X..X 
XXXXXXXX..XXXXXXXXXXXXXXXXXXXX 
X.............\.../..........X 
X..............\./...........X 
X...............C............X 
X............../.\...........X 
X............./...\..........X 
X............/.....\.........X 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 

C是字符的位置;點只是規則的,無阻礙的地板。 X是牆壁。來自C的行表示您需要渲染2D線的四個方向。

在3D中,要對點光源進行陰影映射,必須將該場景以6個不同方向渲染6次,才能投射到立方體陰影貼圖的面上。在2D中,您必須將場景以4個不同的方向渲染4次,並將其渲染成4個不同的1D陰影貼圖。你可以爲此使用一維數組紋理。

一旦你有了你的陰影貼圖,你只需在着色器中使用它們來檢測一個片段是否可見。要做到這一點,您需要一系列從窗口空間到4個不同投影的變換,這些投影表示您渲染到的4個視圖方向。根據片段相對於目標的位置,只有其中一個將用於任何特定的片段。

爲了實現這一點,我首先得到一個簡單的方向「陰影」的例子來工作。也就是說,不要使用職位;只是一個「輕」的方向。這將測試您開發2D到1D投影矩陣的能力,以及適當的相機空間矩陣,以將您的世界空間四邊形轉換爲相機空間。一旦你掌握了這一點,那麼你可以用不同的預測來做4次。

+0

我明白了,但在確定牆的哪些部分應顯示時,未能看到1D投影如何有用。我不應該在每個方向上對每個牆進行投影,以使它們正確嗎?例如:http://i.imgur.com/CtuPu1t.jpg紅色矩形中的一行是ligh/shadow的一維投影。但是對於方塊1和方塊2來說,這種投影是不正確的,因爲方塊2是完全可見的,方塊1大部分是可見的,但在投影中,這些區域被標記爲模糊......也許我的想法是錯誤的? – Leo 2013-03-27 13:08:37

+0

@ user2215331:這不是一個二進制值;這是一個深度。你得到*最接近的*遮擋表面的距離。來自塊1的貢獻將離開,因此塊1和目標之間的任何片段將被視爲可見。 – 2013-03-27 13:19:44

+0

我現在明白了!我只有一個問題。正如我所說的,我對着色器很陌生,並且非常利用GPU。我的問題是關於工作負載分配:這些任務中的哪一個是由GPU完成的,哪些由CPU正常處理?對於GPU完成的任務,何時應該使用着色器? – Leo 2013-03-27 13:31:31