天天看点

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