zoukankan      html  css  js  c++  java
  • Reflect & Refract (以水渲染为例)

    我不是Shader帝,虽然知道Shader怎么写,但一直没仔细研究过。最近蛋疼至极,研究了下RenderMonkey,于是抽着几个看着比较有趣的效果做了一下。

    先前的模型贴花http://www.cppblog.com/Leaf/archive/2011/01/07/138093.html

    和CUBE MAP http://www.cppblog.com/Leaf/archive/2011/01/07/138106.html

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

    还是先围观,上图再说

    image

    image

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

    反射和折射通常用于增加场景真实感。由于其代价昂贵(通常是要将场景多渲染两次为代价)。因此在实际的游戏开发中,都省着用。而此次演示的水的反射和折射并未进行场景渲染,只做了以下几点工作。

    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分量存放着折射系数
    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)));

    image图1

    本文并未解释任何事情,仅是将上面那个链接指向的文章内容翻版为水面实现。此实现仅作为探索目的,无任何实用价值(除非你只想演示水)。

    若要用此方案作实时的水面渲染,则需要将场景渲染到一个CUBEMAP上(就算你降到CUBEMAP每秒更新2次,代价也是比较大的,并且不能保证实时感)。

    而其中的扰动纹理,以及所给的相关因子均需要手动调整到一个合适的值。

  • 相关阅读:
    黑马程序员_网络编程
    黑马程序员_ 异常
    黑马程序员_面向对象基础
    黑马程序员_循环语句的使用
    黑马程序员_面向对象深入2
    黑马程序员_ JAVA中的多线程
    黑马程序员_JAVA基础知识总结3
    OC-内存管理
    OC-核心语法(3)(分类、SEL、类本质)
    OC-核心语法2-构造方法
  • 原文地址:https://www.cnblogs.com/qilinzi/p/1930960.html
Copyright © 2011-2022 走看看