积累系统性知识
积聚技术精华
  首页    个人中心    撰写积文    建立课题    订立目标    整理积文    管理课题    管理目标    技能Get    代码积累 
OpenGL曲面纹理贴图技术--波浪的模拟
error997 (error997)    2014-11-20 21:09:50      目标    课题
   OpenGL曲面纹理贴图技术--波浪的模拟
    学过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);       // 退出程序
}


   


转自 http://blog.csdn.net/y___y/article/details/1429863
(+0)技能Get

建议楼主:搜索关键字 |参考其他资源 |回复 |追问
  error997(error997):   个人中心    课题    目标    代码积累