<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    demibug

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      24 Posts :: 3 Stories :: 2 Comments :: 0 Trackbacks
    轉(zhuǎn)自http://www.cppblog.com/kesalin


    基礎(chǔ)知識(shí):

    在講解代碼之前,我們來(lái)回顧一下在高中的物理課上我們所學(xué)的關(guān)于水波的知識(shí)。水波有擴(kuò)散,衰減,折射,反射,衍射等幾個(gè)特性:

     

    擴(kuò)散 : 當(dāng)你投一塊石頭到水中,你會(huì)看到一個(gè)以石頭入水點(diǎn)為圓心所形成的一圈圈的水波,這里,你可能會(huì)被這個(gè)現(xiàn)象所誤導(dǎo),以為水波上的每一點(diǎn)都是以石頭入水點(diǎn)為中 心向外擴(kuò)散的,這是錯(cuò)誤的。實(shí)際上,水波上的任何一點(diǎn)在任何時(shí)候都是以自己為圓心向四周擴(kuò)散的,之所以會(huì)形成一個(gè)環(huán)狀的水波,是因?yàn)樗ǖ膬?nèi)部因?yàn)閿U(kuò)散的 對(duì)稱而相互抵消了。

    衰減 :因?yàn)樗怯凶枘岬模駝t,當(dāng)你在水池中投入石頭,水波就會(huì)永不停止的震蕩下去。

    折射 :因?yàn)樗ㄉ喜煌攸c(diǎn)的傾斜角度不同,所以我們從觀察點(diǎn)垂直往下看到的水底并不是在觀察點(diǎn)的正下方,而有一定的偏移。如果不考慮水面上部的光線反射,這就是我們能感覺(jué)到水波形狀的原因。

    反射 :水波遇到障礙物會(huì)反射。

    衍射 :在水池中央放上一塊礁石,或放一個(gè)中間有縫的隔板,那么就能看到水波的衍射現(xiàn)象了。

     

    算法推導(dǎo):

    好了,有了這幾個(gè)特性,再運(yùn)用數(shù)學(xué)和幾何知識(shí),我們就可以模擬出真實(shí)的水波了。但是,如果你曾用 3DMax 做過(guò)水波的動(dòng)畫(huà),你就會(huì)知道要渲染出一幅真實(shí)形狀的水波畫(huà)面少說(shuō)也得好幾十秒,而我們現(xiàn)在需要的是實(shí)時(shí)的渲染,每秒種至少也得渲染 20 幀才能使得水波得以平滑的顯示。考慮到電腦運(yùn)算的速度,我們不可能按照正弦函數(shù)或精確的公式來(lái)構(gòu)造水波,不能用乘除法,更不能用 sin  cos 等三角函數(shù),只能用一種取近似值的快速算法,盡管這種算法存在一定誤差,但是為了滿足實(shí)時(shí)動(dòng)畫(huà)的要求,我們不得不這樣做。

     

    首先我們要建立兩個(gè)與水池圖象一樣大小的數(shù)組 buf1[PoolWidth * PoolHeight]  buf2[PoolWidth * PoolHeight]  PoolWidth 為水池圖象的象素寬度、 PoolHeight 為水池圖象的象素高度),用來(lái)保存水面上每一個(gè)點(diǎn)的前一時(shí)刻和后一時(shí)刻波幅數(shù)據(jù),因?yàn)椴ǚ簿痛砹瞬ǖ哪芰浚栽诤竺嫖覀兎Q這兩個(gè)數(shù)組為波能緩沖區(qū)。水面在初始狀態(tài)時(shí)是一個(gè)平面,各點(diǎn)的波幅都為 0 ,所以,這兩個(gè)數(shù)組的初始值都等于 0 

    下面來(lái)推導(dǎo)計(jì)算波幅的公式

    我們假設(shè)存在這樣一個(gè)一次公式,可以在任意時(shí)刻根據(jù)某一個(gè)點(diǎn)周?chē)啊⒑蟆⒆蟆⒂宜膫€(gè)點(diǎn)以及該點(diǎn)自身的振幅來(lái)推算出下一時(shí)刻該點(diǎn)的振幅,那么,我們就有可能用歸納法求出任意時(shí)刻這個(gè)水面上任意一點(diǎn)的振幅。如左圖,你可以看到,某一時(shí)刻, X0 點(diǎn)的振幅除了受 X0 點(diǎn)自身振幅的影響外,同時(shí)受來(lái)自它周?chē)啊⒑蟆⒆蟆⒂宜膫€(gè)點(diǎn)( X1  X2  X3  X4 )的影響(為了簡(jiǎn)化,我們忽略了其它所有點(diǎn)),而且,這四個(gè)點(diǎn)對(duì) X0 點(diǎn)的影響力可以說(shuō)是機(jī)會(huì)均等的。那么我們可以假設(shè)這個(gè)一次公式為:

     

    X0’ = a * (X1 + X2 + X3 + X4) + b * X0            ( 公式 1)

     

    a, b 為待定系數(shù), X0’  X0 點(diǎn)下一時(shí)刻的振幅,

    X0  X1  X2  X3  X4 為當(dāng)前時(shí)刻的振幅

     

    下面我們來(lái)求解 a  b 

    假設(shè)水的阻尼為 0 。在這種理想條件下,水的總勢(shì)能將保持不變,水波永遠(yuǎn)波動(dòng)。也就是說(shuō)在任何時(shí)刻,所有點(diǎn)的振幅的和保持不變。那么可以得到下面這個(gè)公式:

     

    X0’ + X1’ + ... + Xn’  =  X0 + X1 + ... + Xn

     

    將每一個(gè)點(diǎn)用公式 1 替代,代入上式,得到:

     

    (4a + b) * X0 + (4a + b) * X1 + ... (4a + b) * Xn = X0 + X1 + ... + Xn  =  4a + b = 1

     

    找出一個(gè)最簡(jiǎn)解: a = 1/2  b = -1 

     

    因?yàn)?/span> 1/2 可以用移位運(yùn)算符 “>>” 來(lái)進(jìn)行,不用進(jìn)行乘除法,所以,這組解是最適用的而且是最快的。那么最后得到的公式就是:

     

    X0’=  X1 + X2 + X3 + X4  / 2 - X0

     

    好了,有了上面這個(gè)近似公式,你就可以推廣到下面這個(gè)一般結(jié)論:已知某一時(shí)刻水面上任意一點(diǎn)的波幅,那么,在下一時(shí)刻,任意一點(diǎn)的波幅就等于與該點(diǎn)緊鄰的前、后、左、右四點(diǎn)的波幅的和除以 2 、再減去該點(diǎn)的波幅。

     

    應(yīng)該注意到,水在實(shí)際中是存在阻尼的,否則,用上面這個(gè)公式,一旦你在水中增加一個(gè)波源,水面將永不停止的震蕩下去。所以,還需要對(duì)波幅數(shù)據(jù)進(jìn)行衰減處理,讓每一個(gè)點(diǎn)在經(jīng)過(guò)一次計(jì)算后,波幅都比理想值按一定的比例降低。這個(gè)衰減率經(jīng)過(guò)測(cè)試,用 1/32 比較合適,也就是 1/2^5 。可以通過(guò)移位運(yùn)算很快的獲得。

    到這里,水波特效算法中最艱難的部分已經(jīng)明了,下面是 Android 源程序中計(jì)算波幅數(shù)據(jù)的代碼。

     

    // 某點(diǎn)下一時(shí)刻的波幅算法為:上下左右四點(diǎn)的波幅和的一半減去當(dāng)前波幅,即

    //    X0' =  X1 + X2 + X3 + X4  / 2 - X0

    //  +----x3----+

    //  +      |       +

    //  +      |        +

    // x1---x0----x2

    //  +      |       +

    //  +      |       +

    //  +----x4----+

    //

    void rippleSpread()

    {

        int pixels = m_width * ( m_height - 1);

        for ( int i = m_width ; i < pixels; ++i) {

           // 波能擴(kuò)散 : 上下左右四點(diǎn)的波幅和的一半減去當(dāng)前波幅

            // X0' =  X1 + X2 + X3 + X4  / 2 - X0

           //

           m_buf2 [i] =

    ( short )((( m_buf1 [i - 1] + m_buf1 [i + 1]+

              m_buf1 [i - m_width ] + m_buf1 [i + m_width ]) >> 1)

    m_buf2 [i]);

     

           // 波能衰減 1/32

          //

           m_buf2 [i] -= m_buf2 [i] >> 5;

        }

     

        // 交換波能數(shù)據(jù)緩沖區(qū)

        short [] temp = m_buf1 ;

        m_buf1 m_buf2 ;

        m_buf2 = temp;

    }

     

    渲染:

    然后我們可以根據(jù)算出的波幅數(shù)據(jù)對(duì)頁(yè)面進(jìn)行渲染。

     

    因 為水的折射,當(dāng)水面不與我們的視線相垂直的時(shí)候,我們所看到的水下的景物并不是在觀察點(diǎn)的正下方,而存在一定的偏移。偏移的程度與水波的斜率,水的折射率 和水的深度都有關(guān)系,如果要進(jìn)行精確的計(jì)算的話,顯然是很不現(xiàn)實(shí)的。同樣,我們只需要做線性的近似處理就行了。因?yàn)樗嬖絻A斜,所看到的水下景物偏移量就 越大,所以,我們可以近似的用水面上某點(diǎn)的前后、左右兩點(diǎn)的波幅之差來(lái)代表所看到水底景物的偏移量。

     

    在程序中,用一個(gè)頁(yè)面裝載原始的圖像,用另外一個(gè)頁(yè)面來(lái)進(jìn)行渲染。先取得指向兩個(gè)頁(yè)面內(nèi)存區(qū)的指針 src  dst ,然后用根據(jù)偏移量將原始圖像上的每一個(gè)象素復(fù)制到渲染頁(yè)面上。進(jìn)行頁(yè)面渲染的代碼如下:

     

    void rippleRender()

    {

        int offset;

        int i = m_width ;

        int length = m_width m_height ;

        for ( int y = 1; y < m_height - 1; ++y) {

           for ( int x = 0; x < m_width ; ++x, ++i) {

              // 計(jì)算出偏移象素和原始象素的內(nèi)存地址偏移量 :

              //offset = width * yoffset + xoffset

              offset = ( m_width * ( m_buf1 [i - m_width ] - m_buf1 [i + m_width ])) + ( m_buf1 [i - 1] - m_buf1 [i + 1]);

                

              // 判斷坐標(biāo)是否在范圍內(nèi)

              if (i + offset > 0 && i + offset < length) {

                 m_bitmap2 [i] = m_bitmap1 [i + offset];

              }

              else {

                 m_bitmap2 [i] = m_bitmap1 [i];

              }

           }

        }

    }

     

    增加波源:

    俗話說(shuō):無(wú)風(fēng)不起浪,為了形成水波,我們必須在水池中加入波源,你可以想象成向水中投入石頭,形成的波源的大小和能量與石頭的半徑和你扔石頭的力量都有關(guān)系。知道了這些,那么好,我們只要修改波能數(shù)據(jù)緩沖區(qū) buf ,讓它在石頭入水的地點(diǎn)來(lái)一個(gè)負(fù)的  尖脈沖  ,即讓 buf[x,y] = -n 。經(jīng)過(guò)實(shí)驗(yàn), n 的范圍在( 32 ~ 128 )之間比較合適。

     

    控制波源半徑也好辦,你只要以石頭入水中心點(diǎn)為圓心,畫(huà)一個(gè)以石頭半徑為半徑的圓,讓這個(gè)圓中所有的點(diǎn)都來(lái)這么一個(gè)負(fù)的  尖脈沖  就可以了(這里也做了近似處理)。

    增加波源的代碼如下:

     

    // stoneSize    波源半徑

    // stoneWeight : 波源能量

    //

    void dropStone( int x, int y, int stoneSize, int stoneWeight)

    {

        // 判斷坐標(biāo)是否在范圍內(nèi)

        if ((x + stoneSize) > m_width || (y + stoneSize) > m_height

              || (x - stoneSize) < 0 || (y - stoneSize) < 0) {

           return ;

         }

     

        int value = stoneSize * stoneSize;

        short weight = ( short )-stoneWeight;

       for ( int posx = x - stoneSize; posx < x + stoneSize; ++posx)    {

          for ( int posy = y - stoneSize; posy < y + stoneSize; ++posy)       {

             if ((posx - x) * (posx - x) + (posy - y) * (posy - y)

                < value)

             {

                    m_buf1 [ m_width * posy + posx] = weight;

             }

          }

       }

    }

     

    如果我們想要模擬在水面劃過(guò)時(shí)引起的漣漪效果,那么我們還需要增加新的算法函數(shù) breasenhamDrop 

     

    void dropStoneLine( int x, int y, int stoneSize, int stoneWeight) {

       // 判斷坐標(biāo)是否在屏幕范圍內(nèi)

       if ((x + stoneSize) > m_width || (y + stoneSize) > m_height

          || (x - stoneSize) < 0 || (y - stoneSize) < 0) {

             return ;

       }

     

       for ( int posx = x - stoneSize; posx < x + stoneSize; ++posx)    {

          for ( int posy = y - stoneSize; posy < y + stoneSize; ++posy)       {

             m_buf1 [ m_width * posy + posx] = -40;

          }

       }

    }

     

    // xs , ys : 起始點(diǎn), xe ye : 終止點(diǎn)

    // size : 波源半徑, weight : 波源能量

    void breasenhamDrop ( int xs, int ys, int xe, int ye, int size, intweight)

    {

       int dx = xe - xs;

       int dy = ye - ys;

       dx = (dx >= 0) ? dx : -dx;

       dy = (dy >= 0) ? dy : -dy;

     

       if (dx == 0 && dy == 0) {

          dropStoneLine(xs, ys, size, weight);

       }

       else if (dx == 0) {

           int yinc = (ye - ys != 0) ? 1 : -1;

           for ( int i = 0; i < dy; ++i){

               dropStoneLine (xs, ys, size, weight);

               ys += yinc;

           }

       }

       else if (dy == 0) {

          int xinc = (xe - xs != 0) ? 1 : -1;

          for ( int i = 0; i < dx; ++i){

             dropStoneLine(xs, ys, size, weight);

             xs += xinc;

          }

       }

       else if (dx > dy) {

          int p = (dy << 1) - dx;

          int inc1 = (dy << 1);

          int inc2 = ((dy - dx) << 1);

          int xinc = (xe - xs != 0) ? 1 : -1;

          int yinc = (ye - ys != 0) ? 1 : -1;

     

          for ( int i = 0; i < dx; ++i) {

             dropStoneLine(xs, ys, size, weight);

             xs += xinc;

             if (p < 0) {

                p += inc1;

             }

             else {

                ys += yinc;

                p += inc2;

             }

          }

       }

       else {

          int p = (dx << 1) - dy;

          int inc1 = (dx << 1);

          int inc2 = ((dx - dy) << 1);

          int xinc = (xe - xs != 0) ? 1 : -1;

          int yinc = (ye - ys != 0) ? 1 : -1;

     

          for ( int i = 0; i < dy; ++i) {

             dropStoneLine(xs, ys, size, weight);

             ys += yinc;

             if (p < 0) {

                p += inc1;

             }

             else {

                xs += xinc;

                p += inc2;

             }

          }

       }

    }

     

     

    效果圖:

     

    劃過(guò)水面時(shí)的漣漪特效

    雨滴滴落水面特效

     

    結(jié)語(yǔ):

    這種用數(shù)據(jù)緩沖區(qū)對(duì)圖像進(jìn)行水波處理的方法,有個(gè)最大的好處就是,程序運(yùn)算和顯示的速度與水波的復(fù)雜程度是沒(méi)有關(guān)系的,無(wú)論水面是風(fēng)平浪靜還是波濤洶涌,程序的 fps 始終保持不變,這一點(diǎn)你研究一下程序就應(yīng)該可以看出來(lái)

    posted on 2011-05-09 16:36 Hiji 閱讀(859) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 又大又粗又爽a级毛片免费看| 嫩草在线视频www免费观看| 色噜噜亚洲精品中文字幕| 亚洲码和欧洲码一码二码三码| 亚洲欧洲免费无码| 亚洲另类小说图片| 毛片免费观看网址| 亚洲国产高清国产拍精品| 日韩精品免费电影| 羞羞漫画小舞被黄漫免费| 免费国产成人高清视频网站| 日亚毛片免费乱码不卡一区 | 一本色道久久88亚洲综合 | 无人视频免费观看免费视频 | 中文字幕永久免费| 亚洲av综合色区| 最近中文字幕大全中文字幕免费| 亚洲麻豆精品果冻传媒| 在线看免费观看AV深夜影院| 亚洲熟妇成人精品一区| 亚洲国产精品国产自在在线| 怡红院免费的全部视频| 综合自拍亚洲综合图不卡区| 1024免费福利永久观看网站| 亚洲精品欧美综合四区 | 亚洲国产精品无码久久一线| h在线观看视频免费网站| 亚洲国产成人久久精品大牛影视| 亚洲精品无码久久久久AV麻豆| 国产午夜成人免费看片无遮挡| 亚洲视频免费一区| 国产真人无遮挡作爱免费视频| 成全视成人免费观看在线看| 91亚洲国产成人精品下载| 女人18毛片特级一级免费视频| 一级成人a免费视频| 亚洲av女电影网| 国产精品免费综合一区视频| 好湿好大好紧好爽免费视频| 亚洲最大免费视频网| 亚洲精品成人久久久|