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);       // 退出程序
 
}

opengl曲面贴图相关推荐

  1. OpenGL立方体贴图

    OpenGL 立方贴图 Copyright NVIDIA Corporation, 1999. Commercial publication in written, electronic, or ot ...

  2. OpenGL 立方贴图

    OpenGL 立方贴图 Copyright NVIDIA Corporation, 1999. Commercial publication in written, electronic, or ot ...

  3. OpenGL 位移贴图实例

    OpenGL 位移贴图 先上图,再解答. 按下D键 完整主要的源代码 源代码剖析 先上图,再解答. 按下D键 完整主要的源代码 #include <vmath.h> #include &l ...

  4. OpenGL阴影贴图

    OpenGL阴影贴图 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL/glus ...

  5. OpenGL 光照贴图Lighting maps

    OpenGL光照贴图Lighting maps 光照贴图Lighting maps简介 漫反射贴图 镜面光贴图 采样镜面光贴图 光照贴图Lighting maps简介 在上一节中,我们讨论了让每个物体 ...

  6. C++ Opengl纹理贴图源码

    C++ Opengl纹理贴图源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SDK8.1,三方库 ...

  7. OpenGL 凹凸贴图实例

    OpenGL 凹凸贴图实例 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <sb7.h> #include <vmath.h& ...

  8. android数据球图,Android OpenGL球体贴图

    OpenGL球体贴图的的整个流程就是计算出球体和纹理材质坐标,然后画出球体,按照纹理坐标将bitmap贴上去. 具体方法和上一篇文章画一个球体类似OpenGL绘制球体,只是需要创建材质,并且需要构建一 ...

  9. OpenGL 立方体贴图Cubemaps

    OpenGL立方体贴图Cubemaps 立方体贴图Cubemaps简介 创建立方体贴图 天空盒 加载天空盒 显示天空盒 优化 环境映射 反射 折射 动态环境贴图 立方体贴图Cubemaps简介 我们已 ...

最新文章

  1. OGNL使用方法总结
  2. [机器学习]AutoML --- NNI (Microsoft)
  3. 一台7纳米光刻机月产能有多大,何为能卖上亿美元?
  4. mysql c语言数字转字符串函数_C++_c语言标准库中字符转换函数和数字转换函数,字符转换为数字: #includest - phpStudy...
  5. DnCNN论文阅读笔记【MATLAB】
  6. ecshop每个商品添加去淘宝购买链接
  7. iPhone 12将首次加入屏下指纹?都是为它铺路?
  8. SQL Server 合并复制遇到identity range check报错的解决
  9. 安笙机器人_张翰新戏搭档徐璐!包贝尔要和辛芷蕾演奇幻电影?
  10. java求解LeetCode题目,实现求解数组中的majority element
  11. 【细胞分割】基于matlab GUI阙值+边缘+形态学+种子点图像分割【含Matlab源码 615期】
  12. 如何修改修改服务器风扇转速,DELL服务器手动调整风扇转速
  13. AE自带特效中英文对照表
  14. QT学习笔记(一)——QT基础
  15. 后6位数密码字典生成
  16. 【最优化导论】全局搜索算法
  17. 数据库系统原理学习笔记三(关系数据模型的组成要素)
  18. jQuery动画效果——淡入淡出
  19. MATLAB 2018b 安装教程(图解)Mac Win Linux下均可安装
  20. Ant [BOOK]

热门文章

  1. 〖Linux〗Ubuntu13.10中打开键盘背光灯
  2. 平淡生活:喜羊羊和灰太郎获奖了
  3. 数字加逗号函数PHP函数,php实现数字格式化,数字每三位加逗号的功能函数
  4. 3ds Max,Maya用户转Blender的方案“同快捷键或同操作方案”
  5. css3南瓜幽灵动画代码
  6. 怎样进服务器手机版视频文件,手机播放云服务器中的视频文件
  7. 暴雪游戏之路的成功与失败 原来大神也犯错
  8. 能和小米比性价比的手环内部是啥样?
  9. 2022-2027年中国网络租车平台行业市场调研及未来发展趋势预测报告
  10. COMSOL光电案列应用实操教学: