• 用DirectX实现动态纹理


    什么是动态纹理

    动态纹理是相对于常规的纹理而言的,通常的纹理都是静态的,而动态纹理就是模型保持不动,而纹理动态变化,凡是能够对模型应用的变换,也能作用于纹理,比如平移,旋转,缩放,投影,shear等都不在话下,使用动态纹理可以模拟很多现象,最常见的就是Dynamic cloud。

    如何实现动态纹理

    话说这个问题还是我在一次面试的时候遇到的。

    面试官:怎样让一个纹理动起来

    我:让模型动起来即可

    面试官:如果不允许移动模型呢?只动纹理

    我:。。。

    其实这个问题并不难,只要明白一点,纹理也是有坐标的,既然有坐标,就可以改变位置,位置可以改变,就能做出动态效果来。普通的纹理坐标都是二维的,用(u, v)来表示,这里u表示横坐标,从左到右递增,v表示纵坐标,从上到下递增,如下图

     

    纹理效果的本质无非是按照一定的规则动态变化uv坐标而已,由于这里的纹理都是二维的,所以变换矩阵是三维的(通常DX的变换矩阵都是四维的)。来看一下三个变换矩阵 

    平移矩阵(沿着u坐标方向移动Tu距离,沿着v坐标方向移动Tv距离)

    旋转矩阵(旋转角度:θ,旋转方向:逆时针。关于旋转方向,DX帮助文档中是这么描述的,Angles are measured clockwise when looking along the rotation axis toward the origin. 也就是沿着旋转轴朝原点看是顺时针方向,而Z轴指向屏幕内部的,所以我们看到的旋转就是逆时针方向)

     

    缩放矩阵(u坐标缩放Su倍,v坐标缩放Sv倍)

    代码

    准备工作,设置纹理的渲染状态及寻址模式,为了使纹理能够循环显示,需要指定纹理的寻址方式为D3DTADDRESS_WRAP

    // Texture state
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP );
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );

    下面的函数是最关键的部分,所有的动态效果都在这里实现,平移是按照u方向进行的,也就是横坐标平移,旋转是绕z轴逆时针旋转,缩放是循环进行的,如果到达最大最小边界,则会反向缩放。这里我们把所有的变换都放到一个矩阵中,最后使用SetTransform应用这个矩阵即可,这和设置模型的世界矩阵是一个道理。

    void UpdateTextureCoordinates(float timeDelta)
    {
    g_pd3dDevice->SetTextureStageState(0,
    D3DTSS_TEXTURETRANSFORMFLAGS,
    D3DTTFF_COUNT2);

    if (g_EffectFlag ==1) // Translation
    {
    // Translate
    matTexture._31 += timeDelta /3 ;
    }
    elseif (g_EffectFlag ==2) // Rotation
    {
    angle += timeDelta ; // increasing total angle
    matTexture._11 = cosf(angle) ;
    matTexture._12 = sinf(angle) ;
    matTexture._21 =-sinf(angle) ;
    matTexture._22 = cosf(angle) ;
    }
    elseif (g_EffectFlag ==3) // Scaling
    {
    // if the picture is too small, increasing
    if (matTexture._11 <0.2)
    g_Factor =-g_Factor ;

    // if the picture is too large, decreasing
    if (matTexture._11 >5.0f)
    g_Factor =-g_Factor ;

    matTexture._11 += timeDelta * g_Factor;
    matTexture._22 += timeDelta * g_Factor;
    }

    g_pd3dDevice->SetTransform(D3DTS_TEXTURE0, &matTexture) ;
    }

    几个需要注意的问题

    注意纹理的缩放与普通模型的缩放是不同的,确切的说是完全相反,因为纹理的缩放完全是靠u,v坐标来实现的,所以坐标值越大,纹理反而越小,坐标值越小,纹理反而越大。(为什么?

    旋转貌似只能沿着XOY平面进行,其他的情况我还没有试过,因为纹理坐标是二维的,且位于XOY面,故二维纹理只能绕Z轴旋转。

    旋转和缩放都是以纹理坐标原点(0, 0)点为参照的(通常是纹理图片的左上角),如果要以矩形纹理的中心为旋转点,则需要先平移,在旋转,最后再平移回去。 

    效果 

    原始图

    平移效果

    旋转效果

    缩放效果

    上面的图片都是静态的,不是很直观,大家可以下载下面的程序看看动态效果

    示例程序下载(使用方法,T键-平移,R键-旋转,S键-缩放)

    Happy Coding!

    == The End ==

  • 相关阅读:
    javascript实战演练,制作新按钮,‘新窗口打开网站’,点击打开新窗
    P1332 血色先锋队
    P4643 [国家集训队]阿狸和桃子的游戏
    T149876 公约数
    P1462 通往奥格瑞玛的道路
    P1083 借教室
    Tribles UVA
    Fence Repair POJ
    Crossing Rivers
    关于一轮
  • 原文地址:https://www.cnblogs.com/graphics/p/1910172.html
Copyright © 2020-2023  润新知