学过OpenGL的人都很容易的把图片贴到四边形和三角行上,但将纹理贴到一般的曲面上认为很困难,其实

通过本文的简单分析,其实很简单。本文以波浪模拟为例,来介绍一般纹理贴图技术,大家很容易举一反三来

模拟其他的现象。代码的蓝本主要来自NeHe。
1.简单的数学知识介绍

向量的乘积(这里指叉乘)。
用程序写出来如下。

// 三维点定义
struct  cvPoint
... {
 float x,y,z; //点的坐标
} ;
// 矢量相乘C=A*B (方向符合右手定则)
void  vect_mult( struct  cvPoint  * A,  struct  cvPoint  * B,  struct  cvPoint  * C)
... {
 C->x=A->y * B->z -A ->z * B->y;
 C->y=A->z * B->x -A ->x * B->z;
 C->z=A->x * B->y -A ->y * B->x;
}

四边形的法向选取
    四边形的法向选取采用四边形两条对角线向量相乘。问什么不采用四边形的边相乘,因为四边形四顶点点

并不一定共平面,采用四边形两条对角线向量相乘,显然要更精确一些。

波浪方程(其实就是正弦或余弦函数绕z轴旋转的)

double  t = 0.0 ; // 相位
double  sf( double  x, double  y)
... {
 return cos(sqrt(x*x+y*y)+t);
}

2.创建纹理(NeHe)
不清楚的可参考NeHe的教程,清楚地可跳过本节。

GLuint texture[ 3 ];
AUX_RGBImageRec  * LoadBMP( char   * Filename)      //  载入位图图象
... {
 FILE *File=NULL;       // 文件句柄
 if(!Filename)        // 确保文件名已

提供
 ...{
  return NULL;       // 如果没提供,

返回 NULL
 }
 File=fopen(Filename,"r");      // 尝试打开文件
 if(File)        // 文件存在么?
 ...{
  fclose(File);       // 关闭句柄
  return auxDIBImageLoad(Filename);    // 载入位图并返

回指针
 }
 return NULL;        // 如果载入失败

,返回 NULL
}
int  LoadGLTextures()         //  载入位图(调用

上面的代码)并转换成纹理
... {
 int Status=FALSE;       // 状态指示器
 AUX_RGBImageRec *TextureImage[1];     // 创建纹理的存

储空间
 memset(TextureImage,0,sizeof(void *)*1);    // 将指针设为 

NULL
 // 载入位图,检查有无错误,如果位图没找到则退出
 if(TextureImage[0]=LoadBMP("Data/NeHe.bmp"))
 ...{
  Status=TRUE;       // 将 Status 设

为 TRUE
  glGenTextures(3, &texture[0]);     // 创建纹理
  
  // 创建 Nearest 滤波贴图
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  // 创建线性滤波纹理
  glBindTexture(GL_TEXTURE_2D, texture[1]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  // 创建 MipMapped 纹理
  glBindTexture(GL_TEXTURE_2D, texture[2]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); 
  gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); 
 }
 if (TextureImage[0])       // 纹理是否存在
 ...{
  if (TextureImage[0]->data)     // 纹理图像是否

存在
  ...{
   free(TextureImage[0]->data);    // 释放纹理图像

占用的内存
  }  
  free(TextureImage[0]);      // 释放图像结构
 }
 return Status;        // 返回 Status
}

3.曲面纹理贴图的关键
    曲面纹理贴图的关键就是把曲面分成小块(本文采用四边形),纹理贴图也要相对应的分成小块,然后相

对应的把纹理贴到相对应的曲面小块。注意一定要相对应,连顶点都要相对应。
    先将曲面分割,并存储其分割的顶点。

float  ver[ 21 ][ 21 ][ 3 ];
GLvoid initVer()
... {
 int i,j;
 float dx=D_PI*8/20.0,dy=D_PI*8/20.0;
 for(i=0;i<=20;i++)
  for(j=0;j<=20;j++)
  ...{
   ver[i][j][0]=i*dx-D_PI*4;
   ver[i][j][1]=j*dy-D_PI*4;
   ver[i][j][2]=(float)sf(ver[i][j][0],ver[i][j][1]);
  }
}
开始贴图
cvPoint pa,pb,pc;
for ( int  i = 0 ;i < 20 ;i ++ )
     for ( int  j = 0 ;j < 20 ;j ++ )
     ... {
        //第一条对角线
        pa.x=ver[i+1][j+1][0]-ver[i][j][0];
        pa.y=ver[i+1][j+1][1]-ver[i][j][1];
        pa.z=ver[i+1][j+1][2]-ver[i][j][2];
        //第二条对角线
        pb.x=ver[i][j+1][0]-ver[i+1][j][0];
        pb.y=ver[i][j+1][1]-ver[i+1][j][1];
        pb.z=ver[i][j+1][2]-ver[i+1][j][2];

        vect_mult(&pa,&pb,&pc);//计算法向,注意顺序
        glNormal3f(pc.x,pc.y,pc.z);
        //注意要一一对应
        glBegin(GL_QUADS);
        glTexCoord2f(0.05*i,0.05*j);
        glVertex3f(ver[i][j][0],ver[i][j][1],ver[i][j][2]);
        glTexCoord2f(0.05*(i+1),0.05*j);
        glVertex3f(ver[i+1][j][0],ver[i+1][j][1],ver[i+1][j][2]);
        glTexCoord2f(0.05*(i+1),0.05*(j+1));
        glVertex3f(ver[i+1][j+1][0],ver[i+1][j+1][1],ver[i+1][j+1][2]);
        glTexCoord2f(0.05*i,0.05*(j+1));
        glVertex3f(ver[i][j+1][0],ver[i][j+1][1],ver[i][j+1][2]);
        glEnd();
    }

动起来
这个So Simple!改变相位即可。

t += 0.05 ;

搞定,曲面纹理贴图技术就这么简单。

完整的代码(运行前,先在创建Data文件夹,并放一张256×256的位图以供加载纹理)

#include  < windows.h >    //  Windows的头文件
#include  < GL / gl.h >    //  包含最新的gl.h,glu.h库
#include  < GL / glu.h >    //  包含OpenGL实用库
#include  < GL / glaux.h >
#include  < stdio.h >    //  标准输入/输出库的头文件
#include  < math.h >
#define  D_PI 3.141592653
#pragma  warning(disable:4305)
#pragma  warning(disable:4244)

struct  cvPoint
... {
 float x,y,z; //点的坐标
} ;
// 矢量相乘C=A*B 
void  vect_mult( struct  cvPoint  * A,  struct  cvPoint  * B,  struct  cvPoint  * C)
... {
 C->x=A->y * B->z -A ->z * B->y;
 C->y=A->z * B->x -A ->x * B->z;
 C->z=A->x * B->y -A ->y * B->x;
}

double  t = 0.0 ;
double  sf( double  x, double  y)
... {
 return cos(sqrt(x*x+y*y)+t);
}
float  ver[ 21 ][ 21 ][ 3 ];
GLvoid initVer()
... {
 int i,j;
 float dx=D_PI*8/20.0,dy=D_PI*8/20.0;
 for(i=0;i<=20;i++)
  for(j=0;j<=20;j++)
  ...{
   ver[i][j][0]=i*dx-D_PI*4;
   ver[i][j][1]=j*dy-D_PI*4;
   ver[i][j][2]=(float)sf(ver[i][j][0],ver[i][j][1]);
  }
}


HDC   hDC = NULL;   //  窗口着色描述表句柄
HGLRC  hRC = NULL;   //  OpenGL渲染描述表句柄
HWND  hWnd = NULL;   //  保存我们的窗口句柄
HINSTANCE hInstance;   //  保存程序的实例

bool  keys[ 256 ];    //  保存键盘按键的数组
bool  active = TRUE;   //  窗口的活动标志,缺省为TRUE
bool  fullscreen = TRUE;  //  全屏标志缺省,缺省设定成全屏模式
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);  //  WndProc的定义

int  rx = 0 ,ry = 0 ,rz = 0 ;

BOOL light;          //  光源的开/关
bool  lp;
GLfloat LightAmbient[] = ... {0.5f,0.5f,0.5f,1.0f} ; 
GLfloat LightDiffuse[] = ... {1.0f,1.0f,1.0f,1.0f} ;
GLfloat LightPosition[] = ... {0.0f,0.0f,2.0f,1.0f} ;
GLuint texture[ 3 ];

AUX_RGBImageRec  * LoadBMP( char   * Filename)      //  载入位图图象
... {
 FILE *File=NULL;       // 文件句柄
 if(!Filename)        // 确保文件名已

提供
 ...{
  return NULL;       // 如果没提供,

返回 NULL
 }
 File=fopen(Filename,"r");      // 尝试打开文件
 if(File)        // 文件存在么?
 ...{
  fclose(File);       // 关闭句柄
  return auxDIBImageLoad(Filename);    // 载入位图并返

回指针
 }
 return NULL;        // 如果载入失败

,返回 NULL
}
int  LoadGLTextures()         //  载入位图(调用

上面的代码)并转换成纹理
... {
 int Status=FALSE;       // 状态指示器
 AUX_RGBImageRec *TextureImage[1];     // 创建纹理的存

储空间
 memset(TextureImage,0,sizeof(void *)*1);    // 将指针设为 

NULL
 // 载入位图,检查有无错误,如果位图没找到则退出
 if(TextureImage[0]=LoadBMP("Data/NeHe.bmp"))
 ...{
  Status=TRUE;       // 将 Status 设

为 TRUE
  glGenTextures(3, &texture[0]);     // 创建纹理
  
  // 创建 Nearest 滤波贴图
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  // 创建线性滤波纹理
  glBindTexture(GL_TEXTURE_2D, texture[1]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  // 创建 MipMapped 纹理
  glBindTexture(GL_TEXTURE_2D, texture[2]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); 
  gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); 
 }
 if (TextureImage[0])       // 纹理是否存在
 ...{
  if (TextureImage[0]->data)     // 纹理图像是否

存在
  ...{
   free(TextureImage[0]->data);    // 释放纹理图像

占用的内存
  }  
  free(TextureImage[0]);      // 释放图像结构
 }
 return Status;        // 返回 Status
}


GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   //  重置OpenGL窗口大小
... {
 if (height==0)          

// 防止被零除
 ...{
  height=1;          

// 将Height设为1
 }

 glViewport(0,0,width,height);      // 重置当前的视



 glMatrixMode(GL_PROJECTION);      // 选择投影矩阵
 glLoadIdentity();         

// 重置投影矩阵

 // 设置视口的大小
 gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

 glMatrixMode(GL_MODELVIEW);       // 选择

模型观察矩阵
 glLoadIdentity();         

// 重置模型观察矩阵
}

int  InitGL(GLvoid)          

//  此处开始对OpenGL进行所有设置
... {
 initVer();
 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); 
 glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
 glEnable(GL_LIGHT1);

 if(!LoadGLTextures())
 ...{
  return false;
 }
    glEnable(GL_TEXTURE_2D);

 glShadeModel(GL_SMOOTH);       // 启用

阴影平滑
 glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // 黑色背景
 glClearDepth(1.0f);         

// 设置深度缓存
 glEnable(GL_DEPTH_TEST);       // 启用

深度测试
 glDepthFunc(GL_LEQUAL);        // 所作

深度测试的类型
 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉系统对透视进行修正
 return TRUE;          

// 初始化 OK
}

int  DrawGLScene(GLvoid)          //  从这

里开始进行所有的绘制
... {
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
 glLoadIdentity();

 glTranslatef(0,0,-6.0);

 glRotatef(float(rx),1.0,0.0,0.0);
 glRotatef(float(ry),0.0,1.0,0.0);
 glRotatef(float(rz),0.0,0.0,1.0);
 
 glBindTexture(GL_TEXTURE_2D, texture[0]);

    initVer();//重新赋值
 cvPoint pa,pb,pc;
 glPushMatrix();
 glScalef(0.1,0.1,0.1);
 glTranslatef(-D_PI/2,-D_PI/2,0);
 glRotatef(-60,1,0,0);
 glRotatef(-30,0,0,1);
 for(int i=0;i<20;i++)
  for(int j=0;j<20;j++)
  ...{
   //第一条对角线
   pa.x=ver[i+1][j+1][0]-ver[i][j][0];
   pa.y=ver[i+1][j+1][1]-ver[i][j][1];
   pa.z=ver[i+1][j+1][2]-ver[i][j][2];
            //第二条对角线
   pb.x=ver[i][j+1][0]-ver[i+1][j][0];
   pb.y=ver[i][j+1][1]-ver[i+1][j][1];
   pb.z=ver[i][j+1][2]-ver[i+1][j][2];

   vect_mult(&pa,&pb,&pc);//计算法向,注意顺序
   glNormal3f(pc.x,pc.y,pc.z);
   glBegin(GL_QUADS);
   glTexCoord2f(0.05*i,0.05*j);
   glVertex3f(ver[i][j][0],ver[i][j][1],ver[i][j][2]);
   glTexCoord2f(0.05*(i+1),0.05*j);
   glVertex3f(ver[i+1][j][0],ver[i+1][j][1],ver[i+1][j][2]);
   glTexCoord2f(0.05*(i+1),0.05*(j+1));
   glVertex3f(ver[i+1][j+1][0],ver[i+1][j+1][1],ver[i+1][j+1][2]);
   glTexCoord2f(0.05*i,0.05*(j+1));
   glVertex3f(ver[i][j+1][0],ver[i][j+1][1],ver[i][j+1][2]);
   glEnd();
  }
 glPopMatrix();

 glEnable(GL_LIGHTING);
 t+=0.05;//改变相位
 Sleep(20);
 return TRUE;          

// 一切 OK
}

GLvoid KillGLWindow(GLvoid)         //  正常

销毁窗口
... {
 if (fullscreen)          

// 我们处于全屏模式吗?
 ...{
  ChangeDisplaySettings(NULL,0);     // 是的话,切换

回桌面
  ShowCursor(TRUE);        

// 显示鼠标指针
 }

 if(hRC)           

//我们拥有OpenGL描述表吗?
 ...{
  if(!wglMakeCurrent(NULL,NULL))     // 我们能否释放

DC和RC描述表?
  ...{
   MessageBox(NULL,"释放DC或RC失败。","关闭错误",MB_OK | 

MB_ICONINFORMATION);
  }

  if(!wglDeleteContext(hRC))      // 我们

能否删除RC?
  ...{
   MessageBox(NULL,"释放RC失败。","关闭错误",MB_OK | MB_ICONINFORMATION);
  }
  hRC=NULL;          

// 将RC设为 NULL
 }

 if(hDC&&!ReleaseDC(hWnd,hDC))     // 我们能否释放 DC?
 ...{
  MessageBox(NULL,"释放DC失败。","关闭错误",MB_OK | MB_ICONINFORMATION);
  hDC=NULL;          

// 将 DC 设为 NULL
 }

 if(hWnd && !DestroyWindow(hWnd))     // 能否销毁窗口?
 ...{
  MessageBox(NULL,"释放窗口句柄失败。","关闭错误",MB_OK | MB_ICONINFORMATION);
  hWnd=NULL;          

// 将 hWnd 设为 NULL
 }

 if (!UnregisterClass("OpenG",hInstance))   // 能否注销类?
 ...{
  MessageBox(NULL,"不能注销窗口类。","关闭错误",MB_OK | MB_ICONINFORMATION);
  hInstance=NULL;         

// 将 hInstance 设为 NULL
 }
}

/**/ /* 这个函数创建我们OpenGL窗口,参数为:        

 *
 * title   - 窗口标题        

    *
 * width   - 窗口宽度        

    *
 * height   - 窗口高度        

    *
 * bits   - 颜色的位深(8/16/32)       

  *
 * fullscreenflag - 是否使用全屏模式,全屏模式(TRUE),窗口模式(FALSE)  */
 
BOOL CreateGLWindow( char *  title,  int  width,  int  height,  int  bits,  bool  fullscreenflag)
... {
 GLuint  PixelFormat;   // 保存查找匹配的结果
 WNDCLASS wc;      // 窗口类结构
 DWORD  dwExStyle;    // 扩展窗口风格
 DWORD  dwStyle;    // 窗口风格
 RECT  WindowRect;    // 取得矩形的左上角和右下角的坐

标值
 WindowRect.left=(long)0;   // 将Left   设为 0
 WindowRect.right=(long)width;  // 将Right  设为要求的宽度
 WindowRect.top=(long)0;    // 将Top    设为 0
 WindowRect.bottom=(long)height;  // 将Bottom 设为要求的高度

 fullscreen=fullscreenflag;   // 设置全局全屏标志

 hInstance   = GetModuleHandle(NULL);    

// 取得我们窗口的实例
 wc.style   = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // 移动时重画,

并为窗口取得DC
 wc.lpfnWndProc  = (WNDPROC) WndProc;     // 

WndProc处理消息
 wc.cbClsExtra  = 0;         

// 无额外窗口数据
 wc.cbWndExtra  = 0;         

// 无额外窗口数据
 wc.hInstance  = hInstance;       

// 设置实例
 wc.hIcon   = LoadIcon(NULL, IDI_WINLOGO);   // 装入

缺省图标
 wc.hCursor   = LoadCursor(NULL, IDC_ARROW);   // 装入

鼠标指针
 wc.hbrBackground = NULL;         

// GL不需要背景
 wc.lpszMenuName  = NULL;         

// 不需要菜单
 wc.lpszClassName = "OpenG";        

// 设定类名字

 if (!RegisterClass(&wc))         

// 尝试注册窗口类
 ...{
  MessageBox(NULL,"注册窗口失败","错误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;          

 // 退出并返回FALSE
 }
 
 if (fullscreen)           

 // 要尝试全屏模式吗?
 ...{
  DEVMODE dmScreenSettings;        

// 设备模式
  memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // 确保内存清空为零
  dmScreenSettings.dmSize=sizeof(dmScreenSettings);  // Devmode 结构

的大小
  dmScreenSettings.dmPelsWidth = width;    // 所选

屏幕宽度
  dmScreenSettings.dmPelsHeight = height;    // 所选

屏幕高度
  dmScreenSettings.dmBitsPerPel = bits;     // 每象

素所选的色彩深度
  dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

  // 尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态条
  if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!

=DISP_CHANGE_SUCCESSFUL)
  ...{
   // 若模式失败,提供两个选项:退出或在窗口内运行。
   if (MessageBox(NULL,"全屏模式在当前显卡上设置失败!使用窗口模

式?","NeHe G",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
   ...{
    //如果用户选择窗口模式,变量fullscreen 的值变为FALSE,程序继续运


    fullscreen=FALSE;  // 选择窗口模式

(Fullscreen=FALSE)
   }
   else
   ...{
    //如果用户选择退出,弹出消息窗口告知用户程序将结束。并返回FALSE

告诉程序窗口未能成功创建。程序退出。
    MessageBox(NULL,"程序将被关闭","错误",MB_OK|MB_ICONSTOP);
    return FALSE;        

 // 退出并返回 FALSE
   }
  }
 }

 if (fullscreen)           

 // 仍处于全屏模式吗?
 ...{
  dwExStyle=WS_EX_APPWINDOW;        

// 扩展窗体风格
  dwStyle=WS_POPUP;         

 // 窗体风格
  ShowCursor(FALSE);         

 // 隐藏鼠标指针
 }
 else
 ...{
  dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // 扩展窗体风格
  dwStyle=WS_OVERLAPPEDWINDOW;       

// 窗体风格
 }

 AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);  // 调整窗口达到

真正要求的大小

 // 创建窗口
 if (!(hWnd=CreateWindowEx( dwExStyle,       

// 扩展窗体风格
        "OpenG",    

   // 类名字
        title,     

   // 窗口标题
        dwStyle |    

   // 必须的窗体风格属性
        WS_CLIPSIBLINGS |   

  // 必须的窗体风格属性
        WS_CLIPCHILDREN,   

  // 必须的窗体风格属性
        0, 0,     

   // 窗口位置
        WindowRect.right-

WindowRect.left, // 计算调整好的窗口宽度
        WindowRect.bottom-

WindowRect.top, // 计算调整好的窗口高度
        NULL,     

   // 无父窗口
        NULL,     

   // 无菜单
        hInstance,    

   // 实例
        NULL)))     

   // 不向WM_CREATE传递任何东东
 ...{
  KillGLWindow();        // 重置

显示区
  MessageBox(NULL,"窗口创建错误","错误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }

 static PIXELFORMATDESCRIPTOR pfd=    //pfd 告诉窗口我们所希望

的东东,即窗口使用的像素格式
 ...{
  sizeof(PIXELFORMATDESCRIPTOR),    // 上述格式描述符的大小
  1,           

// 版本号
  PFD_DRAW_TO_WINDOW |      // 格式支持窗口
  PFD_SUPPORT_OPENGL |      // 格式必须支持

OpenGL
  PFD_DOUBLEBUFFER,       // 必须

支持双缓冲
  PFD_TYPE_RGBA,        // 申请 

RGBA 格式
  bits,          

// 选定色彩深度
  0, 0, 0, 0, 0, 0,       // 忽略

的色彩位
  0,           

// 无Alpha缓存
  0,           

// 忽略Shift Bit
  0,           

// 无累加缓存
  0, 0, 0, 0,         

// 忽略聚集位
  16,           

// 16位 Z-缓存 (深度缓存) 
  0,           

// 无蒙板缓存
  0,           

// 无辅助缓存
  PFD_MAIN_PLANE,        // 主绘

图层
  0,           

// 不使用重叠层
  0, 0, 0          

// 忽略层遮罩
 };
 
 if (!(hDC=GetDC(hWnd)))       // 取得设备描述

表了么?
 ...{
  KillGLWindow();        // 重置

显示区
  MessageBox(NULL,"不能创建一个窗口设备描述表","错误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }

 if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Windows 找到相应的象素格式了吗?
 ...{
  KillGLWindow();        // 重置

显示区
  MessageBox(NULL,"不能创建一种相匹配的像素格式","错误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }

 if(!SetPixelFormat(hDC,PixelFormat,&pfd))  // 能够设置象素格式么?
 ...{
  KillGLWindow();        // 重置

显示区
  MessageBox(NULL,"不能设置像素格式","错误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }

 if (!(hRC=wglCreateContext(hDC)))    // 能否取得OpenGL渲染描

述表?
 ...{
  KillGLWindow();        // 重置

显示区
  MessageBox(NULL,"不能创建OpenGL渲染描述表","错误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }

 if(!wglMakeCurrent(hDC,hRC))     // 尝试激活着色描述表
 ...{
  KillGLWindow();        // 重置

显示区
  MessageBox(NULL,"不能激活当前的OpenGL渲然描述表","错

误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }

 ShowWindow(hWnd,SW_SHOW);      // 显示窗口
 SetForegroundWindow(hWnd);      // 略略提高优先


 SetFocus(hWnd);         // 设置

键盘的焦点至此窗口
 ReSizeGLScene(width, height);     // 设置透视 GL 屏幕

 if (!InitGL())         // 初始

化新建的GL窗口
 ...{
  KillGLWindow();        // 重置

显示区
  MessageBox(NULL,"初始化失败","错误",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }

 return TRUE;         // 成功
}

LRESULT CALLBACK WndProc( HWND hWnd,    //  窗口的句柄 
       UINT uMsg,    //  窗口

的消息
       WPARAM wParam,    //  附加

的消息内容
       LPARAM lParam)    //  附加

的消息内容
... {
 switch (uMsg)         // 检查

Windows消息
 ...{
  case WM_ACTIVATE:       // 监视

窗口激活消息
  ...{
   if (!HIWORD(wParam))     // 检查最小化状


   ...{
    active=TRUE;      // 程序

处于激活状态
   }
   else
   ...{
    active=FALSE;      // 程序

不再激活
   }

   return 0;        

// 返回消息循环
  }

  case WM_SYSCOMMAND:       // 系统

中断命令
  ...{
   switch (wParam)       // 检查

系统调用
   ...{
    case SC_SCREENSAVE:     // 屏保

要运行?
    case SC_MONITORPOWER:    // 显示器要进入

节电模式?
    return 0;       

// 阻止发生
   }
   break;         

// 退出
  }

  case WM_CLOSE:        // 收到

Close消息?
  ...{
   PostQuitMessage(0);      // 发出

退出消息
   return 0;        

// 返回
  }

  case WM_KEYDOWN:       // 有键

按下么?
  ...{
   keys[wParam] = TRUE;     // 如果是,设为

TRUE
   return 0;        

// 返回
  }

  case WM_KEYUP:        // 有键

放开么?
  ...{
   keys[wParam] = FALSE;     // 如果是,设为

FALSE
   return 0;        

// 返回
  }

  case WM_SIZE:        // 调整

OpenGL窗口大小
  ...{
   ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  // 

LoWord=Width,HiWord=Height
   return 0;        

// 返回
  }
 }

 // 向 DefWindowProc传递所有未处理的消息。
 return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

int  WINAPI WinMain(HINSTANCE hInstance,    //  当前窗口实例
     HINSTANCE hPrevInstance,   //  前一个窗口实


     LPSTR  lpCmdLine,    //  命令

行参数
      int    nCmdShow)   

//  窗口显示状态
... {
 MSG  msg;         

// Windowsx消息结构
 BOOL done=FALSE;        // 用来

退出循环的Bool 变量

 // 提示用户选择运行模式
 if (MessageBox(NULL,"你想在全屏模式下运行么?", "设置全屏模

式",MB_YESNO|MB_ICONQUESTION)==IDNO)
 ...{
  fullscreen=FALSE;       // FALSE

为窗口模式
 }

 // 创建OpenGL窗口
 if (!CreateGLWindow("NeHe's OpenGL 程序框架",640,480,16,fullscreen))
 ...{
  return 0;         

// 失败退出
 }

 while(!done)         // 保持

循环直到 done=TRUE
 ...{
  if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // 有消息在等待吗?
  ...{
   if (msg.message==WM_QUIT)    // 收到退出消息?
   ...{
    done=TRUE;       

// 是,则done=TRUE
   }
   else         

// 不是,处理窗口消息
   ...{
    TranslateMessage(&msg);    // 翻译消息
    DispatchMessage(&msg);    // 发送消息
   }
  }
  else          

// 如果没有消息
  ...{
   // 绘制场景。监视ESC键和来自DrawGLScene()的退出消息
   if (active)        

// 程序激活的么?
   ...{
    if (keys[VK_ESCAPE])    // ESC 按下了么?
    ...{
     done=TRUE;      

// ESC 发出退出信号
    }
    else        

// 不是退出的时候,刷新屏幕
    ...{
     DrawGLScene();     // 绘制

场景
     SwapBuffers(hDC);    // 交换

缓存 (双缓存)
     if (keys['L'] && !lp)    // L 键

已按下并且松开了?
     ...{
      lp=TRUE;    // lp 设

为 TRUE
      light=!light;    // 切换

光源的 TRUE/FALSE
      if (!light)    // 如果

没有光源
      ...{
       glDisable(GL_LIGHTING);  // 禁用

光源
      }
      else     // 否则
      ...{
       glEnable(GL_LIGHTING);  // 启用

光源
      }
     }
     if (!keys['L'])     // L键松

开了么?
     ...{
      lp=FALSE;    // 若是

,则将lp设为FALSE
     }
    }
   }

   if (keys[VK_F1])      // F1键

按下了么?
   ...{
    keys[VK_F1]=FALSE;     // 若是

,使对应的Key数组中的值为 FALSE
    KillGLWindow();      // 销毁

当前的窗口
    fullscreen=!fullscreen;    // 切换 全屏 / 

窗口 模式
    // 重建 OpenGL 窗口
    if (!CreateGLWindow("NeHe's OpenGL 程序框

架",640,480,16,fullscreen))
    ...{
     return 0;      

// 如果窗口未能创建,程序退出
    }
   }
  }
 }

 // 关闭程序
 KillGLWindow();         // 销毁

窗口
 return (msg.wParam);       // 退出程序
}

OpenGL曲面纹理贴图技术--波浪的模拟(转 作者 Y_Y)相关推荐

  1. OpenGL:纹理贴图

    纹理贴图是在栅格化的模型表面上覆盖图像的技术.它是为渲染场景添加真实感的最基本和最重要的方法之一.硬件也为纹理贴图提供了硬件支持,使得它具备实现实时的照片级真实感的超高性能.纹理单元是专为纹理设计的硬 ...

  2. OpenGL立方体纹理贴图

    OpenGL正方体纹理贴图 0. 写在最前面 1. 正方体顶点属性构建 2. 绑定多个VAO.VBO 3. 创建多个纹理 4. 渲染循环 5. 实现代码 6. 多个立方体纹理贴图 0. 写在最前面 要 ...

  3. openCV读入图片,openGL实现纹理贴图

    本文结合结合openCV,openGL的优点,实现混合编程. (1)OpenCV提供图形处理和计算机视觉方面的通用算法,读入二维图片很方便: (2)OpenGL是跨平台的图形程序接口,它用于二维,三维 ...

  4. 纹理窗口Qt+OpenGL之纹理贴图

    上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助.今天在这里和大家一起学习一下纹理窗口 NeNe的代码中是加载到了一个正方体当中,代码很长.其实单纯的想要纹理贴图是很便利的.具体的纹理贴图技巧在 ...

  5. 手把手教会OpenGL之纹理贴图、包含纹理载入、纹理过滤、边界处理、纹理参数设置(入门级别案例,棋盘)

    一.OpenGL中纹理的加载(对glTexImage2D函数的使用) 二.纹理过滤(glTexParameteri参数中的GL_TEXTURE_MAG_FILTER与 GL_TEXTURE_MIN_F ...

  6. Opengl实现纹理贴图

    纹理贴图的步骤 创建纹理对象,并为它指定一个纹理 确定纹理如何应用到每个像素上 启用纹理贴图功能 绘制场景,提供纹理坐标和几何图形坐 Tips:纹理坐标必须在RGBA模式下才能使用,在颜色索引模式下是 ...

  7. (转)各种纹理贴图技术

    凹凸贴图(bump mapping)概念 无论是程序员还是美工人员,几乎每个游戏开发者都知道一些3D图形学的知识,因此每个人都或多或少了解 一点bump mapping.Bump mapping是在像 ...

  8. opengl es纹理贴图效果实例

    一.先准备好一张用来贴图的照片 二.纹理效果代码: gl.glEnable(GL10.GL_TEXTURE_2D);// 创建纹理gl.glGenTextures(1, textureids, 0); ...

  9. opengl android 纹理贴图 代码,Android 使用opengl es的纹理贴图白屏问题请教。

    各位大侠好: 我在使用open gl es的做显示的时候,发现一个问题,请各位帮助一下,谢谢. 环境:opengl es 1.x,2D的模式显示纹理图片. 在LG-P990,HTC-C510E上显示附 ...

最新文章

  1. R语言max函数min函数计算各种数据对象最大值最小值实战
  2. 【解析】在高级语言源程序中, 常需要用户定义的标识符为程序中的对象命名,常见的命名对象有()
  3. numpy、cv2等操作图片基本操作
  4. python猜数字游戏快速求解解决方案
  5. python for循环 内存_Python for循环中的内存错误
  6. python比较两个列表不同部分_Python实现比较两个列表(list)范围
  7. MySQL8.0 - 新特性 - 临时表改进 1
  8. visio箭头尾部遮盖方框边线
  9. 川大教师发自白书:一所高校就是一座衙门
  10. Codeforces Edu:双指针 » Step 3 » Practice:A. Looped Playlist
  11. Session 钝化机制
  12. 数据接口-免费版(股票数据API)
  13. 如何测试一个一次性水杯
  14. ps里面怎么插入流程图_Photoshop制作网站流程图详细过程
  15. 下一代云原生应用交付会怎样发展?KubeVela帮大忙。
  16. 报名进行时!邀您一起海外社媒会话跨境直播,实地探访MCN机构
  17. NEON优化:性能优化常见问题QA
  18. 心理励志,激活生命的潜能
  19. 03、滤波器设计——阶跃阻抗低通滤波器
  20. 韩信点兵问题的简单算法(downmoon)

热门文章

  1. 洛谷 P5738歌唱比赛 题解
  2. 易观千帆 | 12月用户体验GX评测:国有行及股份行持续领跑,农信社用户体验关注提升
  3. iOS 自带定位CLLocationManager获取经纬度以及城市名称,并判断是否打开定位权限
  4. C# Chart控件的使用总结
  5. OkHttp原理解析(二)
  6. WordPress知更鸟(Begin)主题评论邮件回复失效的解决办法
  7. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU外设那些事(2)- 百变星君FlexRAM
  8. lighttp支持PHP移植到imx6,FFmpeg移植-迅为IMX6ULL开发板
  9. NBP Lumizone(PS亮度蒙版调色插件)v1.1.001版本更新
  10. “百付宝”带来百度未来格局的真正悬念