引擎技术研究之水的渲染

 

水的表面显示场景物体倒影的效果。这是把场景渲染到水面上来实现,不是简单的渲染,而要经过反射处理,即要反射渲染目标。

法线贴图是可以应用到3D表面的特殊纹理,有时也称凹凸纹理,它包括了每个像素的高度值,内含许多细节的表面信息,能够在平平无奇的物体上,创建出许多种特殊的立体外形。可以把法线贴图想像成与原表面垂直的点,所有点组成另一个不同的表面。对于视觉效果而言,它的效率比原有的表面更高,若在特定位置上应用光源,可以生成精确的光照方向和反射。

现具体讨论一下实现水效果的步骤:

一:设计一继承模型类的water类,并为其设计一shader文件,可在其构造函数里设置相应的shader文件,在water改写模型类的_Rend()函数,函数内对water进行特殊的渲染。

_Rend()具体操作如下:

先使用当前的shader变量设置纹理

m_pShader->SetTexture("BumpMap",m_pBumpmap);

BumpMapshader里与C++的接口

再使用IDirect3DDevice9接口设置四个渲染状态:

    SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);

     SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

    SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );//关闭alpha测试

SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );//打开alpha混合

最后调用模型类的渲染函数 _Render(),即调用Water_Render()

如此递归调用water的渲染函数使water的纹理和渲染状态即时更新,使水的效果随场景的变化而变化。

二:设计一监听器ReflectListener和相应的渲染目标mpReflectTarget

(参考“引擎技术之渲染到目标“)

其对应Execute()函数主要负责摄像机信息的设置,以实现水面的反射功能

先看一下水面反射图:

 

 

Execute()要设置摄像机的视点在水下对应位置和方向后进行物体的渲染,渲染后再设置为原来地面的视点和方向。

具体实现如下:

先获取当前摄像机的视点OldEye,获取水面高度WaterH,

则水下的摄像机视点NewEye为:OldEye 2 * OldEye WaterH

化简得:NewEye = 2 * WaterH OldEye

获取当前摄像机的方向 Direction ,则其在水面下方向为 Direction

设置摄像机新的视点和方向后,进行场景物体的渲染:scene->_Render();

渲染后再把摄像机设置为原来的视点和方向。

三:在场景类的渲染函数里,在物体渲染前执行:

      渲染目标  mpReflectTarget->Render() 

     设置 water的纹理 water->SetTexture(mpReflectTarget->GetTexture())

四:现讨论water对应的shader文件的编写。 有关shader的基本设置可参考

   “引擎技术研究之shader技术“

1 VS_Scene的实现

    VSOut OUT = (VSOut)0;

    //矩阵变换

    inPosition = mul( inPosition, World );

    OUT.vPosition = mul( inPosition, View );

    OUT.vPosition = mul( OUT.vPosition, Projection );

    //计算水对应的屏幕坐标,从投影坐标到纹理坐标转换

    float4 vHPos=OUT.vPosition;

    vHPos.xy = -vHPos.xy;

    float4 screenpos;

    screenpos.xyz = (vHPos.xyz + vHPos.w)*0.5f;

    screenpos.w =  vHPos.w;       

    OUT.vProjCoord=screenpos;

    //计算绕动纹理坐标

    float wavescale=0.5;

    float2 uv=inPosition.xz*0.01/wavescale;

    float2 fTranslation=float2(0,1)*time*0.005;// float2(0,1) 水波流动的方向

    OUT.Wave0.xy = uv + fTranslation*2.0;

    OUT.Wave1.xy = uv*2.0 + fTranslation*4.0;

    OUT.Wave2.xy = uv*4.0+fTranslation*2.0;

    OUT.Wave3.xy = uv*8.0+fTranslation;    

return OUT;

2 ComputeBumpTexCoord()函数的实现//为凹凸纹理计算纹理坐标

//vBumpTexA等是通过对应的Wave0即纹理坐标读取出来的像素

     float3 vBumpTexA = tex2D(BumpSampler, IN.Wave0).xyz;

    float3 vBumpTexB = tex2D(BumpSampler, IN.Wave1).xyz;

    float3 vBumpTexC = tex2D(BumpSampler, IN.Wave2).xyz;

    float3 vBumpTexD = tex2D(BumpSampler, IN.Wave3).xyz;

//vBumpTexA B C D用于计算最终的纹理坐标抖动量,用来采样反射贴图

    float3 vBumpTex  = 2*(vBumpTexA+vBumpTexB+vBumpTexC+vBumpTexD)/4

-float3(1,1,1);

    float3 vReflBump = vBumpTex.xyz * float3(0.1, 0.1, 1.0);

    return vReflBump.xy;

3 PS_Scene的实现

    //为凹凸纹理计算纹理坐标

    float2 bumpTexcoord=ComputeBumpTexCoord(IN);

    //计算最终纹理坐标

    float2 vProjUV = (IN.vProjCoord.xy/IN.vProjCoord.w);

    float2 uv=float2(1,1)-vProjUV;

    float4 color= tex2D(ColorSampler, uv + bumpTexcoord ).rgba;

    color.a=0.6f;

    return color;

 

 

效果图如下:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值