2D特效之水波 |
|
axsoft
版主 發表:681 回覆:1056 積分:969 註冊:2002-03-13 發送簡訊給我 |
2D特效之水波 by: 劉小軍 Water源碼
資料來源:http://www.cpp3d.com/articles/show.asp?aid=26 水波特效在游戲當中也比較多見,波紋實時生成算法很多,這里介紹一種快速算法。之所以說它是一種快速算法,是因為它的計算既沒有用到sin、cos函數也沒有用到sin、cos函數的查表算法,它只是根據波的傳播原理,通過少量的加減、位移運算來完成。如要多了解一些波的知識,趕快去翻書哦,現在去學或複習還來得及。當然快速的代價是內存的消耗,這一點我們曾在文章里也提到過,為了追求更高的效率,往往可採取犧牲部分內存這樣一種手段來達到目的。 附:演示代碼編譯需VC、DXGuide、DX6或以上SDK。
在開始之前我們先作一些假設,同時你可參考左面的圖。首先假設波是從右往左傳播,0為波在當前時刻的波形,1為前1/8周期時的波形,2為前1/4周期時的波形。設波的周期為T。圖中向下的箭頭是各點處的振動速度,箭頭線長表示振動速度的大小。 現設有任一點x(Y方向暫不考慮),它在三個波形上分別對應點P0、P1和P2,三點在振幅方向的偏移量(含方向)分別為D0、D1和D2。設波形函數為D0 = sin(2*Pi/T*t b),則D1 = sin(2*Pi/T*(t-T/8) b),D2 = sin(2*Pi/T*(t-T/4) b),我們下面來証明21/2*D1 = D0 D2: 設2*Pi/T b=a,則
D0 = sin(a),D1=sin(a-Pi/4),D2 = sin(a-Pi/2) ==》
D0 D2 = sin(a) sin(a-Pi/2)
=2*sin((a (a-Pi/2))/2)*cos((a-(a-Pi/2))/2)
=2*sin(a-Pi/4)*cos(pi/4)
=21/2*D1 利用這一特征我們就可以來計算波形了,我們可以以1/8個周期為一顯示幀,然后用兩個緩衝區來保留前兩幀的波形,用上述公式就可以依次推算出后續波的波形。這里需要做一些優化,首先將21/2放大為2,則有D0=2*D1-D2,計算后的D0會偏大一些(相當于波能加大),這樣的波會越振越厲害,不停地振動下去永不止,所以要將D0的值減少一部分,辦法是減去1/n個D0,將n值取成2的5(或其它?)次方,這樣就可以用移位來計算:D0-=D0>>5,最后要處理的是波的傳播了,一般我們在某一點給出一個幹擾源(波源),這一點的能量要向四周傳播出去我們才能看出波的抖動,否則光一個點上下抖動看起來是不會象水波的,water2.gif (1036 bytes)我們用平均算法來傳遞波能,每一點的波形都是其前后左右各點的平均值。如右圖,若藍點是波源,則它由綠、黃、紅依次向外傳播,各位注意不要被此圖所誤導,波形絕不是如圖示那樣呈菱形向外傳播,這個圖只不過是為了說明波的傳播次序,因為即使是顏色相同的點其能量(或者說偏移)都不會是相同的。 由上面所分析我們有如下的波傳播代碼:
void CWaterApp::RippleSpread() { // m_buf1 is the previous frame, // and m_buf2 is the frame before that int I; for (I=320; I<64000-320; I ) { // Spread out m_buf2[I] = ( ((m_buf1[I-1] m_buf1[I 1] m_buf1[I-320] m_buf1[I 320])>>1)) - m_buf2[I]; // Energy damping m_buf2[I] -= m_buf2[I]>>5; } // Swap m_buf1 and m_buf2 short *ptmp = m_buf1; m_buf1 = m_buf2; m_buf2 = ptmp; }最后一步就是根據計算出來的波形做渲染了,我們可以隨便選一幅位圖來作為我們的渲當背景(紋理)。由于我們的緩衝區是各點的偏移(偏離水平面的高度),所以我們可以將當前點前后和左右兩個落差作為光折射后的偏移量來計算光的折射。為了讓紋理圖看起來更象水,可將圖的藍色加深。代碼如下: void CWaterApp::RenderRipple() { DDSURFACEDESC2 ddsd, ddsd1; ddsd.dwSize = sizeof (DDSURFACEDESC2); m_pTexture->Lock(&ddsd); ddsd1.dwSize = sizeof(DDSURFACEDESC2); m_pRender->Lock(&ddsd1); DWORD dwPixel; int xoff, yoff; int k = 320; for (int I=1; I<199; I ) { for (int j=0; j<320; j ) { // do refraction xoff = m_buf1[k-1]-m_buf1[k 1]; yoff = m_buf1[k-320]-m_buf1[k 320]; dwPixel = m_pTexture->GetPixel(&ddsd, 160 j xoff, 140 I yoff); // do shading int p = dwPixel & 0x1F; p = xoff; if (p>31) p = 31; if (p<0) p = 0; dwPixel = (dwPixel & 0xFFFFFFE0) | p; m_pRender->PutPixel(&ddsd1, j, I, dwPixel); k ; } } m_pTexture->Unlock(); m_pRender->Unlock(); }在作渲染的同時不停的加入波源,你們會發現無論波源的多少,其運算速度是一樣的快捷,事實上這可從代碼中看出來,算法與波源的多少是無關的。 網路志工聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- |
xshado
一般會員 發表:2 回覆:4 積分:1 註冊:2002-07-24 發送簡訊給我 |
|
axsoft
版主 發表:681 回覆:1056 積分:969 註冊:2002-03-13 發送簡訊給我 |
引言: 請問 DXGuide.h 這個檔是sdk裡面就有的嘛 為什麼我編譯時它說我沒這個檔... 請問要去哪下載ㄋ....謝謝ㄌ^^試試看!把DirectX SDK中的DXGuide.h copy 至\include下 #include < DXGuide.h > 網路志工聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- 發表人 - axsoft 於 2002/12/13 13:05:20 |
xshado
一般會員 發表:2 回覆:4 積分:1 註冊:2002-07-24 發送簡訊給我 |
|
axsoft
版主 發表:681 回覆:1056 積分:969 註冊:2002-03-13 發送簡訊給我 |
引言: > <.....還是找不到DXguide.h 可以麻煩有的人可以寄給我好嗎....^^ 真的很想看執行出來的結果 謝謝了...真的感激不盡..^^ bqfrv@sinamail.com您到這下載DirectX v9.0 SDK http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp 網路志工聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- |
ra
一般會員 發表:0 回覆:1 積分:0 註冊:2002-12-29 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |