decals using projective texture mapping
講投影紋理的好文章網上是很多的,在此給大家一個參考連結,我就不再呈述了。 此文章的描述很易懂。
投影紋理映射(projective texture mapping)
<a href="http://wwwnno00.irrlicht3d.cn:8011/redirect.php?tid=54109&goto=lastpost">http://wwwnno00.irrlicht3d.cn:8011/redirect.php?tid=54109&goto=lastpost</a>
上面的文章從原理上講述了投影紋理是什麼,本文則利用投影紋理進行一個實際的應用。
在遊戲中貼花最常見的地方就是用滑鼠選擇一個目标後,地上出現的一個圓圈,或者範圍魔法在施放時的提示區域。
這個紋理會随着模型和地圖的表面進地扭曲,而非一個平面,是以,我們不論怎麼做,都會進行一個“投影”的思想,才能讓貼上去
的紋理在某一個方向上看的時候,是一個完整的畫面。(我們地上的圈,就是從上往下貼的,是以你從上往下看時,會看到一個完整無扭曲的圖檔)。
什麼? 地上是一圈?是的,但是呢,我們的紋理是方的。 我們看到是圈,并不表示我們要把紋理貼到一個圈上。
下面是我在rendermonkey裡測試的結果。
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 < 1 && coord.y < 1 && coord.x>0 && coord.y>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 < 1 && coord.y < 1 && coord.x>0 && coord.y>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