我不是shader帝,雖然知道shader怎麼寫,但一直沒仔細研究過。最近蛋疼至極,研究了下rendermonkey,于是抽着幾個看着比較有趣的效果做了一下。
就是此次蛋疼期的産物之一。
還是先圍觀,上圖再說
本次要蛋疼的是折射和反射。
反射和折射通常用于增加場景真實感。由于其代價昂貴(通常是要将場景多渲染兩次為代價)。是以在實際的遊戲開發中,都省着用。而此次示範的水的反射和折射并未進行場景渲染,隻做了以下幾點工作。
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>
本文并未解釋任何事情,僅是将上面那個連結指向的文章内容翻版為水面實作。此實作僅作為探索目的,無任何實用價值(除非你隻想示範水)。
若要用此方案作實時的水面渲染,則需要将場景渲染到一個cubemap上(就算你降到cubemap每秒更新2次,代價也是比較大的,并且不能保證明時感)。
而其中的擾動紋理,以及所給的相關因子均需要手動調整到一個合适的值。
簡介:09年入行,喜歡遊戲和程式設計,對3d遊戲和引擎尤其感興趣。
版權聲明:本文版權歸作者和部落格園共有,歡迎轉載。轉載必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
轉載:http://www.cnblogs.com/geniusalex/archive/2011/01/08/1930960.html