天天看點

使用投影紋理進行模型貼花(Mesh Decals)

decals using projective texture mapping

講投影紋理的好文章網上是很多的,在此給大家一個參考連結,我就不再呈述了。 此文章的描述很易懂。

投影紋理映射(projective texture mapping)

<a href="http://wwwnno00.irrlicht3d.cn:8011/redirect.php?tid=54109&amp;goto=lastpost">http://wwwnno00.irrlicht3d.cn:8011/redirect.php?tid=54109&amp;goto=lastpost</a>

上面的文章從原理上講述了投影紋理是什麼,本文則利用投影紋理進行一個實際的應用。

在遊戲中貼花最常見的地方就是用滑鼠選擇一個目标後,地上出現的一個圓圈,或者範圍魔法在施放時的提示區域。

這個紋理會随着模型和地圖的表面進地扭曲,而非一個平面,是以,我們不論怎麼做,都會進行一個“投影”的思想,才能讓貼上去

的紋理在某一個方向上看的時候,是一個完整的畫面。(我們地上的圈,就是從上往下貼的,是以你從上往下看時,會看到一個完整無扭曲的圖檔)。

什麼? 地上是一圈?是的,但是呢,我們的紋理是方的。 我們看到是圈,并不表示我們要把紋理貼到一個圈上。

下面是我在rendermonkey裡測試的結果。

使用投影紋理進行模型貼花(Mesh Decals)
使用投影紋理進行模型貼花(Mesh Decals)
使用投影紋理進行模型貼花(Mesh Decals)

ok,圍觀完畢,下面簡單說一下如何實作。

用投影紋理進行貼花有兩種做法。

第一種。

1、正常渲染模型。

無它!

2、根據投影方向,投影半徑找到投影時需要渲染的三角形組。

這種貼花的效率損耗就是花在這裡了,是以三角形剔除算法要比較高效才行。

3、将此三角形組進行渲染(相當于做為一個模型渲染),紋理映射時采用投影紋理。

渲染時,要打開全局混合開關。

采用這一種渲染方式時,不需要占用紋理通道,也就是可以在模型上貼無數個花。

第二種。

這是一種占用紋理通道的做法。就是隻渲染一次,而在ps中,進行紋理混合。

 本文示範的是第一種情況,因為它更貼近于實際應用。并且并未做三角面剔除,而是僅僅将模型渲染了兩次。

下面是投影紋理的hlsl代碼,以及相關解釋。

vs:

struct vs_input 

   float4 position : position0;

};

struct vs_output 

   float4 position : position0; 

   float3 worldpos : texcoord0; 

vs_output vs_main( vs_input input ) 

   vs_output output;

   output.position = mul( input.position, matviewprojection ); 

   output.worldpos = input.position; 

   return( output ); 

}

vs所做的工作并沒有什麼特别的,僅是需要多向ps傳遞一個空間位置。

ps:

sampler2d texture1; //貼這張紋理時,其uv尋址方式最好為clamp 

struct ps_input 

float4 ps_main( ps_input input ) : color0 

   float3 center = float3(0, 0, 20);//投影中心,y值被忽略。 

   float radius = 4;//投影範圍 

   float3 uvector = float3(1, 0, 0)/(2 * radius);//将世界坐标變換到紋理投影空間坐标并規範化到0-1之間(正投影) 

   float3 vvector = float3(0, 0, 1)/(-2 * radius);//同上 

   float2 coord;  

   coord.x = dot(input.worldpos - center, uvector) + 0.5; 

   coord.y = dot(input.worldpos - center, vvector) + 0.5; 

  // if(coord.x &lt; 1 &amp;&amp; coord.y &lt; 1 &amp;&amp; coord.x&gt;0 &amp;&amp; coord.y&gt;0) 

   return tex2d( texture1, coord); 

   //else 

   //return 0; 

ps所做的工作就是将世界坐标轉換到投影空間,再轉換為紋理坐标。

需要說明一點的是,為了測試友善,我僅假設此時攝相機觀察和投影方向為-y方向。是以

dot(input.worldpos - center, uvector)+0.5

上面這句話其實相當于是mul(input.worldpos,matprojtexture)/2.0+0.5;

另外,對于

  // if(coord.x &lt; 1 &amp;&amp; coord.y &lt; 1 &amp;&amp; coord.x&gt;0 &amp;&amp; coord.y&gt;0)

這句話,我寫在這裡,是作為裁剪使用,若沒有這個. 就算你設定為了clamp,那麼當你的紋理邊緣的alpha不為0時,你會看到

紋理會左右延伸。

而若你未選擇clamp尋址方式,那你的效果就百般神奇了。 也可以将上面屏蔽的代碼解開,用于裁剪。

結尾:

一、投影紋理進行模型貼花時,主要是進行三角面剔除,使在渲染貼花時,送出最少的三角面。

二、在貼花pass中,需要将全局混合開啟,并設定相應的srcblend(src_alpha)和destblend(dest_alpha)值。括号内為我用的值。

當然,如果你不想讓貼花與場景(模型)混合,則可以不開啟。

三、請注意紋理的尋址方式以及紋理邊緣的alpha情況。 若紋理邊緣alpha不為0,則可以手工進行裁剪。

四、本文僅是采用了固定的投影方向和shader内部定義變量的方式來進行貼花渲染。 并且,并未進行模型三角面剔除。是以若要使用,則需要注意第一個問題。

六、支援郵件交流:boyuegame#gmail#com

簡介:09年入行,喜歡遊戲和程式設計,對3d遊戲和引擎尤其感興趣。 

版權聲明:本文版權歸作者和部落格園共有,歡迎轉載。轉載必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

轉載:http://www.cnblogs.com/geniusalex/archive/2011/01/07/1929303.html

繼續閱讀