directx + hlsl实现水面效果

假期没事干,就自己找了点事情干,做个水面的效果,曾经在网上看到好多人做的水面都很漂亮,那时,心里就暗暗较劲,自己什么时候也能做出这样完美的水面呢?
花费了3天时间研究书和网站上的方法,终于做出比较不错的水面了。。。以下是愚的简单方法,不一定完全正确,而且我觉得找到一个好的波动方程真的是看人品的。。。网上的东西试验过了,最后还是自己结合起来写了一个波动方程。。。很简单粗糙的,不过效果不错~
1、自己第一天找到了一个网页,上面写的是直接贴图,然后根据法线图计算纹理采样。具体方法是把预先用3ds max做好的normal map进行采样得到该像素点的法线值,模拟定点法线进行反射纹理采样的纹理坐标。
做完以后,效果如图:

directx + hlsl实现水面效果_第1张图片

效果还不够理想,于是下一步。
2、做水面顶点
上一步做的时候,只是简单的4个顶点,并没有用到任何波动方程,于是摄像机拉近后,只是简单的平面,根本没有起伏的感觉。。。
于是又想起教材上面的红旗飘飘。。。又搜了下顶点的波动方程。。。综合自己不算出众的数学知识,写了个渲染代码,网个图片如图:

directx + hlsl实现水面效果_第2张图片

3、颜色插值。。。这一步很郁闷,要算法线,自己才疏学浅。。。搞了好半天才想到做导数,但是只知道所谓的切线斜率可以求导得到,然后就不知道怎么做了,原来,切线空间有3个向量表示图形,法线(normal),副法线(binormal)和切线(tangen)三者关系是互相垂直,差乘等于另一个(实际直接取,没有算差乘,不知道为什么,否则有问题。。)
这样以来有了颜色的区分,切线空间转换矩阵也得到了。。。然后加上第一步的方法,就差不多了
如图:

directx + hlsl实现水面效果_第3张图片


 



 

有点样子了吧?


4、完善光照,颜色,再加一个折射图。
directx + hlsl实现水面效果_第4张图片

directx + hlsl实现水面效果_第5张图片
directx + hlsl实现水面效果_第6张图片

这样,一个完美的水面就搞定了~~~(图不太清晰厄。。。)
至于动态的问题,要先弄好环境空间以后再进行动态贴图。。。加油努力!!
完美的水面,其实每个人都能做出来!
以下是暂时的hlsl effect代码:

float4x4 matWorldViewProj;
float4x4 matWorld;
float4        vecEye;
float4        vecLightDir;
float4x4 matView;


float fTime;
float4 deepColor;
float4 shallowColor;

texture RefractMap;
sampler    RefractMapSampler = sampler_state
{
    Texture = ;
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

texture ReflectMap;
sampler    ReflectMapSampler = sampler_state
{
    Texture = ;
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};


texture NormalMap;
sampler NormalMapSampler = sampler_state
{
    Texture = ;
    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

struct VS_OUTPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD0;
    float3x3 matTan2World : TEXCOORD1;
    float4 Color : COLOR0;
     float3 View : TEXCOORD4;
};

struct Wave
{
    float fFreq;
    float fLmd;
    float fAmp;
    float2 vDir;
};

Wave Waves[] =
{
//       { 0.20f, 50.0f , 1.00f, float2( 0.5f, 0.1f ) },
    { 0.50f, 500.0f , 25.00f, float2( 0.7f, -0.7f ) },
     { 0.20f, 700.0f , 30.00f, float2( 0.2f, 0.1f ) },
};

float2 EvaluateWave( Wave w, float2 vPos, float time )
{
    float dist = dot(w.vDir , vPos) / sqrt(w.vDir.x * w.vDir.x + w.vDir.y * w.vDir.y);
    float hight = w.fAmp * sin( time * 2 * 3.14 * w.fFreq + dist / (w.fLmd * w.fFreq) );   //Asin(wt + dot(dir,pos) / v)
    float k = w.fAmp * 2 * 3.14 / w.fLmd * cos( time * 2 * 3.14 * w.fFreq + dist / (w.fLmd * w.fFreq) ); //cos(wt + dot(dir,pos) / v)
    float2 ret = float2(hight , k);
    return ret;
}

VS_OUTPUT VS(float4 Pos : POSITION, float2 Tex : TEXCOORD0)
{
    VS_OUTPUT Out = (VS_OUTPUT)0;
    Out.Pos = mul(Pos , matWorldViewProj);       
    Out.Tex = Tex;   
   
    float tx = 0.0f;
    float bz = 0.0f;
    for( int i = 0; i != 2; i++ )
    {
        float2 ret = EvaluateWave( Waves[i], Pos.xz, fTime);
        float k = ret.y;
         Out.Pos.y += ret.x;
         tx += k * Waves[i].vDir.x / sqrt(Waves[i].vDir.x * Waves[i].vDir.x + Waves[i].vDir.y * Waves[i].vDir.y);
         bz += k * Waves[i].vDir.y / sqrt(Waves[i].vDir.x * Waves[i].vDir.x + Waves[i].vDir.y * Waves[i].vDir.y);        
    }
   
   
    float3 vT = normalize(float3(tx , 3 , 0));
//     float3 vB = normalize(float3(0, 3 , bz));
    float3 vN = normalize(float3(-tx , 3 , -bz));
    float3 vB = cross(vT , vN);


    Out.matTan2World[0] = mul( vT, matWorld);
    Out.matTan2World[1] = mul( vB, matWorld);
    Out.matTan2World[2] = mul( vN, matWorld);
    float3 PosWorld = normalize(mul(Pos , matWorld));
    float3 vecEyeDir = vecEye - PosWorld.xyz;
    vecEyeDir = normalize(vecEyeDir);
    Out.View = vecEyeDir;
    float facing = saturate(dot(vecEyeDir , vN));
    float4 waterColor1 = lerp(shallowColor,deepColor,facing);
   
    Out.Color = waterColor1 * 0.8 ;

    return Out;
}

float4 PS(VS_OUTPUT In) : COLOR
{
    float4 Out;
    float2 vBump0 = In.Tex + float2(fTime / 10 , fTime / 10);
    float2 vBump1 = In.Tex * 2.0f + float2(fTime / 15 , 0);
    float2 vBump2 = In.Tex * 4.0f + float2(fTime / 20 , fTime / 10);
    float3 bumpNormal0 = tex2D(NormalMapSampler , vBump0);
    float3 bumpNormal1 = tex2D(NormalMapSampler , vBump1);
    float3 bumpNormal2 = tex2D(NormalMapSampler , vBump2);

    float3 bumpNormal = 2 * (bumpNormal0 + bumpNormal1 + bumpNormal2) - 3;
    bumpNormal = normalize(mul(In.matTan2World , bumpNormal));
    bumpNormal /= 5;
    float3 Incident = - normalize(mul(In.matTan2World , In.View));

    float4 ReflectColor = tex2D(ReflectMapSampler , In.Tex + bumpNormal);
    float4 RefractColor = tex2D(RefractMapSampler , In.Tex + bumpNormal);
    float4 color = ReflectColor * 0.8+ RefractColor * 0.4 ;
   
   
    float4 light = float4(1.0f , 1.0f , 1.0f , 1.0f);
   
    float3 LightDir = normalize(vecLightDir.xyz);   
    float3 Reflect = normalize(2 * dot(bumpNormal , LightDir) * bumpNormal - LightDir);
    float4 spec = light * pow(dot(Reflect , In.View) , 0.2f) * color;
    float4 diff = light * dot(bumpNormal , LightDir) * color;
    Out = spec * 0.8 + diff * 0.4 + In.Color * 0.8;

    return Out;
}

technique TShader
{
    pass P0
    {
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
    }
}

你可能感兴趣的:(GPU,Direct3D)