天天看點

Reflect & Refract (以水渲染為例)

我不是shader帝,雖然知道shader怎麼寫,但一直沒仔細研究過。最近蛋疼至極,研究了下rendermonkey,于是抽着幾個看着比較有趣的效果做了一下。

就是此次蛋疼期的産物之一。

還是先圍觀,上圖再說

Reflect & Refract (以水渲染為例)
Reflect & Refract (以水渲染為例)

本次要蛋疼的是折射和反射。

反射和折射通常用于增加場景真實感。由于其代價昂貴(通常是要将場景多渲染兩次為代價)。是以在實際的遊戲開發中,都省着用。而此次示範的水的反射和折射并未進行場景渲染,隻做了以下幾點工作。

1、渲染天空球。

2、渲染一個水面,并用cubemap對其進行映射,映射時紋理坐标采用投影方式,并附帶擾動。(擾動用的是一個立方體紋理)

附加說明:此次是對rendermonkey 1.82裡的reflections refractions例子裡的ocean進行改造。 原本ocean裡隻做了反射,我強加上了折射。

關于折射,有一個哥們的資料解釋得挺好的。連結如下

<a href="http://www.zwqxin.com/archives/shaderglsl/review-reflect-and-refract.html">http://www.zwqxin.com/archives/shaderglsl/review-reflect-and-refract.html</a>

下面是vertex shader代碼。以及其解釋

float4x4 view_proj_matrix;//: register(c0); 

float4 scale;//: register(c5); 

float4 view_position; 

struct vs_output { 

   float4 pos:    position; 

   float3 pos:    texcoord0; 

   float3 normal: texcoord1; 

   float3 vvec:   texcoord2; 

};

vs_output main(float4 pos: position, float3 normal: normal){ 

   vs_output out;

   // get some size on the water 

   pos.xy *= 1000; //由于rendermonkey裡的oceansurface.3ds比較小,這裡進行了強制縮放,若是其它模型,則可以屏蔽掉這兩條語句 

   pos.z = pos.z -30;

   out.pos = mul(pos,view_proj_matrix); 

   out.pos = pos.xyz * scale; 

   out.vvec = pos - view_position;//視線方向 注意:是世界空間。 

   out.normal = normal;

   return out; 

}

float wavespeed: register(c2); //水波速度  0.3 

float noisespeed: register(c3);//躁聲速度 0.26 

float fadebias: register(c4);//退化矯正 0.3 

float fadeexp: register(c5); //退化幕 6.08 

float time_0_x: register(c0);//時間 

float4 watercolor: register(c1);//水面顔色 

float4 scale: register(c6);//縮放, 其w分量存放着折射系數 

sampler noise: register(s0);//3d躁聲圖 

sampler skybox: register(s1);//cube map  天空盒 

float4 main(float3 pos: texcoord0, float3 normal: texcoord1, float3 vvec: texcoord2) : color {

//這兩條語句是對其進行偏移,使通路紋理坐标的時候,産生流動和擾動效果 

   pos.x += wavespeed  * time_0_x; 

   pos.z += noisespeed * time_0_x;

   float4 noisy = tex3d(noise, pos); //對躁聲紋理進行采樣

   // signed noise 

   float3 bump = 2 * noisy - 1; //由于采樣同來的躁聲紋理每個分量的值是 [0,1] 對此将其規範化到[-1.0,1.0] 

   bump.xy *= 0.15;//縮放一定值。 

   // make sure the normal always points upwards

///法向量矯正,使其永遠向上。注:在這裡,xy與ocean平面平行,z為向上 

   bump.z = 0.8 * abs(bump.z) + 0.2; 

   // offset the surface normal with the bump

//偏移法向量 

   bump = normalize(normal + bump);

   // find the reflection vector

//計算反射和折射 

   float3 reflvec = reflect(vvec, bump); 

   float3 refrac = refract(normalize(vvec),normalize(bump),scale.w);

//根據反射和折射方向通路cube map

   float4 refl = texcube(skybox, reflvec.yzx); 

   float4 wa = texcube(skybox, refrac.yzx); 

   wa = wa*0.5+watercolor*0.5;

//下面是fresnel效果計算,就是用于計算折射和反射圖之間的插值因子的。詳情請仔細google

  //這就是上面那個老兄的ratio = f + (1 - f) (1 - invec • norm)fresnelpower 公式

//圖1中,n1 = 1.0    n2 = 1.3 

   float f = 0.0170132325; 

   float lrp =f+(1-f)*(1 - dot(-normalize(vvec), bump)); 

   // interpolate between the water color and reflection 

   return lerp(wa, refl, saturate(fadebias + pow(lrp, fadeexp))); 

<a href="http://www.zwqxin.com/archives/shaderglsl/review-reflect-and-refract.html"></a>

Reflect &amp; Refract (以水渲染為例)

本文并未解釋任何事情,僅是将上面那個連結指向的文章内容翻版為水面實作。此實作僅作為探索目的,無任何實用價值(除非你隻想示範水)。

若要用此方案作實時的水面渲染,則需要将場景渲染到一個cubemap上(就算你降到cubemap每秒更新2次,代價也是比較大的,并且不能保證明時感)。

而其中的擾動紋理,以及所給的相關因子均需要手動調整到一個合适的值。

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

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

轉載:http://www.cnblogs.com/geniusalex/archive/2011/01/08/1930960.html