我不是Shader帝,雖然知道Shader怎么寫,但一直沒仔細研究過。最近蛋疼至極,研究了下RenderMonkey,于是抽著幾個看著比較有趣的效果做了一下。
先前的模型貼花http://www.shnenglu.com/Leaf/archive/2011/01/07/138093.html
和CUBE MAP http://www.shnenglu.com/Leaf/archive/2011/01/07/138106.html
就是此次蛋疼期的產(chǎn)物之一。
還是先圍觀,上圖再說
本次要蛋疼的是折射和反射。
反射和折射通常用于增加場景真實感。由于其代價昂貴(通常是要將場景多渲染兩次為代價)。因此在實際的游戲開發(fā)中,都省著用。而此次演示的水的反射和折射并未進行場景渲染,只做了以下幾點工作。
1、渲染天空球。
2、渲染一個水面,并用CUBEMAP對其進行映射,映射時紋理坐標采用投影方式,并附帶擾動。(擾動用的是一個立方體紋理)
附加說明:此次是對RenderMonkey 1.82里的Reflections Refractions例子里的Ocean進行改造。 原本Ocean里只做了反射,我強加上了折射。
關于折射,有一個哥們的資料解釋得挺好的。鏈接如下
http://www.zwqxin.com/archives/shaderglsl/review-reflect-and-refract.html
下面是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分量存放著折射系數(shù)
sampler Noise: register(s0);//3D躁聲圖
sampler skyBox: register(s1);//CUBE MAP 天空盒
float4 main(float3 pos: TEXCOORD0, float3 normal: TEXCOORD1, float3 vVec: TEXCOORD2) : COLOR {
//這兩條語句是對其進行偏移,使訪問紋理坐標的時候,產(chǎn)生流動和擾動效果
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] 對此將其規(guī)范化到[-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);
//根據(jù)反射和折射方向訪問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)));
}
圖1
本文并未解釋任何事情,僅是將上面那個鏈接指向的文章內(nèi)容翻版為水面實現(xiàn)。此實現(xiàn)僅作為探索目的,無任何實用價值(除非你只想演示水)。
若要用此方案作實時的水面渲染,則需要將場景渲染到一個CUBEMAP上(就算你降到CUBEMAP每秒更新2次,代價也是比較大的,并且不能保證實時感)。
而其中的擾動紋理,以及所給的相關因子均需要手動調(diào)整到一個合適的值。