posts - 43,  comments - 64,  trackbacks - 0
  这些都是超出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*+ j; cnt++
            VertexIndex[cnt] 
= i*+ j + N; cnt++
        }
        i
++
        j 
= N-1
        VertexIndex[cnt] 
= i*+ j + N; cnt++
        VertexIndex[cnt] 
= i*+ j; cnt++;
        
for(j=N-2;j>=0;j--
        {
            VertexIndex[cnt] 
= i*+ j + N; cnt++
            VertexIndex[cnt] 
= i*+ 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;//位置

    
forint i = 0 ; i <  N ; i++ ){
        
forint 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。

CWater = FaboveCreflect+(1-Fabove)Crefract+AshadowCspecular
  准备好你的折射图,也就是水底的贴图,立方体贴图也就是反射图,以及你的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 周波 阅读(1112) 评论(0)  编辑 收藏 引用 所属分类: 无庸技术

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

周波 87年出生 南京林业大学05421班242信箱 专业木材科学与工程工业装备与过程自动化 迁移到 jedimaster(dot)cnblogs(dot)com

常用链接

留言簿(4)

随笔分类

随笔档案

新闻档案

同学们Blog

搜索

  •  

积分与排名

  • 积分 - 52484
  • 排名 - 421

最新评论

阅读排行榜