opengl曲面贴图

    技术2026-04-15  1

    opengl 曲面贴图

    opengl 2011-02-12 15:31:16 阅读5 评论1   字号: 订阅

    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的位图以供加载纹理)

     

     

    // glqm.cpp : Defines the entry point for the application.//

    #include "stdafx.h"

    #include <windows.h>  // Windows的头文件

    #include <stdio.h>  // 标准输入/输出库的头文件

    #include <math.h>

    #include <GL/glew.h>#pragma comment (lib, "glew32.lib")

    #include <GL/glut.h>#pragma comment (lib, "winmm.lib")   /* link with Windows MultiMedia lib */#pragma comment (lib, "opengl32.lib")  /* link with Microsoft OpenGL lib */#pragma comment (lib, "glu32.lib")  /* link with OpenGL Utility lib */#pragma comment (lib, "glut32.lib")  /* link with Win32 GLUT lib */

    #include <GL/glaux.h>#pragma comment (lib, "glaux.lib")

    #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];

    struct _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(5000);    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;  // 选择窗口模式                           }                          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));        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);       // 退出程序 }

    最新回复(0)