這些都是超出White Paper的經驗總結,如有錯誤,請多多指正謝謝!
1、使用哪個苦力
你可以使用GPU或者是CPU,計算隨時間變化的高程。聽起來用GPU的Vertex Shader計算高程好像非常先進,其實不然。因為GPU與CPU的運作機制不同,每個FPS,傳入時間Uniform變量會導致GPU效率低下,在NVIDIA的GPU優化指南中提到過這一點。所以我還是推薦用CPU計算高程,因為牽涉到大量的三角函數的計算,不可能舍得寶貴的GPU資源浪費在這些CPU可以運作如飛的計算上。Vertex Shader應該做矩陣變換,光照向量等等。如果可能用匯編代碼優化一下,把傳入Vertex Shader的Normals給Normalize了。
2、I want get the Mesh
貼關鍵的完整代碼。
#ifndef?RK_HPP
#include?"rk.hpp"
#endif
extern?GLint?AttribTangentSlot;
extern?GLint?LightPositionLoc;
CStreamModel::CStreamModel(short?n?=?64,float?gl?=?1.0f)?:?N(n),GridLength(gl)
{
????//準備物理參數
????EnvCubeMap?=?-1;//立方體環境貼圖
????NormalMap?=?-1;//發現貼圖,也就是凹凸圖
????RefractMap?=?-1;
????omiga?=?new?float[4];
????A?=?new?float[4];
????L?=?new?float[4];
????Q?=?new?float[4];
????A[0]?=?0.05f;
????A[1]?=?0.05f;
????A[2]?=?0.02f;
????A[3]?=?0.03f;
????L[0]?=?1.0f;
????L[1]?=?1.2f;
????L[2]?=?2.0f;
????L[3]?=?1.2f;
????for(int?i=0;i<4;i++){
????????omiga[i]?=?sqrt(9.8f*2.0f*3.14f/L[i]);//L?=?0.01
????????Q[i]?=?1/(omiga[i]*A[i]*4.0f);
????}
???
????//Q?=?0.01235;
????Mesh?=?new?float[N*N*3];
????VertexIndex?=?new?unsigned?short?[N*N*3];
????TexCoord?=?new?float[N*N*2];
????Binormal?=?new?float[N*N*3];
????Tangent?=?new?float[N*N*3];
????Normal?=?new?float[N*N*3];
????//生成頂點索引?
????//優化乘法?*N可以表示為?<<6
????int?cnt?=?0;
????for(int?i=0;?i<N-2;?i++)?
????{
????????for(int?j=0;?j<N;?j++)?
????????{
????????????VertexIndex[cnt]?=?i*N?+?j;?cnt++;?
????????????VertexIndex[cnt]?=?i*N?+?j?+?N;?cnt++;?
????????}
????????i++;?
????????j?=?N-1;?
????????VertexIndex[cnt]?=?i*N?+?j?+?N;?cnt++;?
????????VertexIndex[cnt]?=?i*N?+?j;?cnt++;
????????for(j=N-2;j>=0;j--)?
????????{
????????????VertexIndex[cnt]?=?i*N?+?j?+?N;?cnt++;?
????????????VertexIndex[cnt]?=?i*N?+?j;?cnt++;?
????????}
????}
????cout<<"size?of?VertexIndex?:?"<<cnt<<endl;
????int?p?=?0;
????for(int?x?=?0;?x?<?N;?x++){
????????for(int?z?=?0;?z?<?N;?z++){
????????????TexCoord[p*2]?=?float(x)?/?float(N);
????????????TexCoord[1+p*2]?=?float(z)?/?float(N);
????????????p++;
????????}
????}
????
????for(int?i=0;?i<16;?i++)
????????cout<<"TexCoord?:?"<<TexCoord[i]<<endl;
????PixelProcesser?=?new?CPixel();
????PixelProcesser->LoadTextureFromBMP(".\\TEXTURES\\Waterbump.bmp",NormalMap);
????if?(?glIsTexture(NormalMap)){
????????cout<<"NormalMap?Texture?Loaded?Ok
"<<endl;
????}else{
????????cout<<"NormalMap?Faild?!"<<endl;
????????_sleep(2000);
????????exit(-1);
????}
????PixelProcesser->LoadTextureFromBMP(".\\TEXTURES\\WaterRefract.bmp",RefractMap);
????if?(?glIsTexture(RefractMap)?){
????????cout<<"WaterRefract?Texture?Loaded?Ok
"<<endl;
????}else{
????????cout<<"RefractMap?Faild?!"<<endl;
????????_sleep(2000);
????????exit(-1);
????}
????char?*szCubeFace[6]?=?{".\\TEXTURES\\RIGHT.bmp",".\\TEXTURES\\LEFT.bmp",".\\TEXTURES\\TOP.bmp",".\\TEXTURES\\BOTTOM.bmp",".\\TEXTURES\\BACK.bmp",".\\TEXTURES\\FRONT.bmp"};
?????PixelProcesser->LoadTextureFrom6CUBEMAP(szCubeFace,EnvCubeMap);
????if?(?glIsTexture(EnvCubeMap)){
????????cout<<"CubeMap?Texture?Loaded?Ok
"<<endl;
????}else{
????????cout<<"cubeMap?Faild?!"<<endl;
????????_sleep(2000);
????????exit(-1);
????}
};
void?CStreamModel::ReBuildHeightMap()
{
????//Dx?Dy還沒有選擇,就用從內向外的斜方向?(-0.1,0,1)
????
????//生成網格與紋理坐標還有TBN向量
????//測試:只有一個方向
????//i?行?j列?OpenGL是反的
????/**/
????//cout<<"N?is?:?"<<N<<",?And?N^2?is?:?"<<N*N<<endl;
????//float?fi?=?0.23;?//fi*t相位
????float?D[4][2]={};
????D[0][0]?=?0.23f;
????D[0][1]?=?-0.08f;
????
????D[1][0]?=?0.12f;
????D[1][1]?=?0.34f;
????
????D[2][0]?=?-0.23f;
????D[2][1]?=?-0.1f;
????D[3][0]?=?-0.2f;
????D[3][1]?=?0.01f;
????int?i?=?0;
????int?p?=?0;//位置
????for(?int?i?=?0?;?i?<??N?;?i++?){
????????for(?int?j?=?0?;?j?<?N?;?j++?){
????????????float?x?=?i?/?8.0?-?4.0f;
????????????float?z?=?j?/?8.0?-?4.0f;
????????????//定點需要的三角計算
????????????float?sigemaCx?=?0.0f,sigemaCz?=?0.0f;
????????????float?sigemaS?=?0.0f;
????????????//向量需要的三角計算
????????????float?N1?=?0.0f;
????????????float?N2?=?0.0f;
????????????float?N3?=?0.0f;
????????????float?T1?=?0.0f;
????????????float?T2?=?0.0f;
????????????float?T3?=?0.0f;
??????????? for(int?k=0;k<4;k++){
????????????????float?C?=?cos(omiga[k]*(D[k][0]*x+D[k][1]*z)+t);
????????????????float?S?=?sin(omiga[k]*(D[k][0]*x+D[k][1]*z)+t);
????????????????sigemaCx?+=?Q[k]*A[k]*D[k][0]*C;
????????????????sigemaCz?+=?Q[k]*A[k]*D[k][1]*C;
????????????????sigemaS?+=?A[k]*C;
????????????????float?OAC?=?omiga[k]*A[k]*C;
????????????????float?OAS?=?omiga[k]*A[k]*S;
????????????????N1?+=?D[k][0]*OAC;
????????????????N2?+=?D[k][1]*OAC;
????????????????N3?+=?Q[k]*OAS;
????????????????T1?+=?Q[k]*D[k][0]*D[k][1]*OAS;
????????????????T2?+=?Q[k]*pow(D[k][1],2)*OAS;
????????????????T3?+=?D[k][1]*OAC;
????????????};
????????????
????????????Mesh[p*3]?=?x?+?sigemaCx;
????????????Mesh[p*3+2]?=?z?+?sigemaCz;
????????????Mesh[p*3+1]?=?sigemaS;
????????????
????????????Normal[?p*3?]?=?-?N1;
????????????Normal[?p*3?+2]?=?-?N2;
????????????Normal[?p*3?+1]?=?1?-?N3;
????????????Tangent[?p*3?]?=?-T1;
????????????Tangent[?p*3?+2]?=?1-T2;?
????????????Tangent[?p*3?+1]?=?T3;
????????????p++;
????????}
????}
????//glEnableClientState(GL_INDEX_ARRAY);
????//glIndexPointer(GL_SHORT,0,VertexIndex);
????t+=0.1f;
};
void?CStreamModel::Draw()
{????
????//glutSolidSphere(1.0,32,32);
????glUniform3f(::LightPositionLoc,0,0,10);
????ReBuildHeightMap();
????glEnableClientState(GL_VERTEX_ARRAY);
????glEnableClientState(GL_NORMAL_ARRAY);
????glEnableVertexAttribArray(::AttribTangentSlot);
????glEnableClientState(GL_TEXTURE_COORD_ARRAY);
????glTexCoordPointer(2,GL_FLOAT,0,TexCoord);
????glVertexPointer(3,GL_FLOAT,0,Mesh);
????glNormalPointer(GL_FLOAT,0,Normal);
????glVertexAttribPointer(::AttribTangentSlot,3,GL_FLOAT,0,0,Tangent);
????glActiveTexture(GL_TEXTURE2);
????glEnable(GL_TEXTURE_CUBE_MAP);
????glBindTexture(GL_TEXTURE_CUBE_MAP,EnvCubeMap);
????glActiveTexture(GL_TEXTURE1);
????glBindTexture(GL_TEXTURE_2D,NormalMap);
????glActiveTexture(GL_TEXTURE0);
????glBindTexture(GL_TEXTURE_2D,RefractMap);
????glPushMatrix();
????????glTranslatef(0,0,15);
????????glDrawElements(GL_TRIANGLE_STRIP,7936,GL_UNSIGNED_SHORT,VertexIndex);
????glPopMatrix();
//????glPopMatrix();
????glDisableClientState(GL_VERTEX_ARRAY);
????glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableVertexAttribArray(::AttribTangentSlot);
}; 代碼很臭,大蝦不要見笑。在繪制函數中,最最關鍵的就是
ReBuildHeightMap()這個函數。每個fps它都將被渲染器執行一次。公式參考了GPU GEMS。把參數解釋一下。Omiga,角頻率;A,水波的振幅;L,波長;Q很特殊,是一個可以控制水波形狀的參數,太大了會導致一個環。可惜我沒有學過流體力學那個NS方程,實在不清楚怎么回事。把頂點的高程,向量計算后,就可以傳入Shader計算了。可是,且慢。
3、Vertex Or Triangles
地形的索引是如何做的?這里水波的索引也就是如何做的。地形也就是個三角形拼成的大網。所以,當興沖沖的計算了一個1024x1024的巨大Water Vertex Mesh,卻發現需要的是三角形。看我上面的代碼中的一段,保準你看的舒心,用的省心。(雞蛋皮鞋亂飛中)。
4、人要臉樹要皮
好了,可以貼圖了。由于水是沒有顏色的,他只是靠反射折射獲取顏色。所以說,在Pixel(Fragment) Shader完成的工作是進行紋理貼圖的顏色調制。這個公式來自微軟研究院的幾個家伙的一White Paper。C
Water = F
aboveC
reflect+(1-F
above)C
refract+A
shadowC
specular 準備好你的折射圖,也就是水底的貼圖,立方體貼圖也就是反射圖,以及你的Bump貼圖。這里陰影貼圖一般用BumpMapping了。那個GPU GEMS2中用Vertex Texture Fetch生成水波的,不是打擊其他人,需要一個非常有經驗的美工才行呵呵。F是Fresnel系數,也就是衰減系數。簡便的公式是
Fresnel = 1 - EyeDir*N或者是寫作1-cos(b)
視覺向量與向量的點乘。我不知道應該轉換到正切空間中,從幾何的角度來說應該是一樣的。
上面的混色公式用GLSL還是cg還是FX都可以很簡單的使用。
關鍵就這些的差不多了。只需要一個很小的框架程序就可以很簡單的作一切了。
我從來不封裝DLL,對于任何人來說,那些都是神秘的二進制。我只把我掌握的東西奉獻給大家,讓大多數人明白背后的道理。
posted on 2006-08-03 09:50
周波 閱讀(1143)
評論(0) 編輯 收藏 引用 所屬分類:
無庸技術