OpenGL曲面纹理贴图技术--波浪的模拟(转 作者 Y_Y)
学过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 sf( double x, double y)
... {
return cos(sqrt(x*x+y*y)+t);
}
2.创建纹理(NeHe)
不清楚的可参考NeHe的教程,清楚地可跳过本节。
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.曲面纹理贴图的关键
曲面纹理贴图的关键就是把曲面分成小块(本文采用四边形),纹理贴图也要相对应的分成小块,然后相
对应的把纹理贴到相对应的曲面小块。注意一定要相对应,连顶点都要相对应。
先将曲面分割,并存储其分割的顶点。
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!改变相位即可。
搞定,曲面纹理贴图技术就这么简单。
完整的代码(运行前,先在创建Data文件夹,并放一张256×256的位图以供加载纹理)
#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)相关推荐
- OpenGL:纹理贴图
纹理贴图是在栅格化的模型表面上覆盖图像的技术.它是为渲染场景添加真实感的最基本和最重要的方法之一.硬件也为纹理贴图提供了硬件支持,使得它具备实现实时的照片级真实感的超高性能.纹理单元是专为纹理设计的硬 ...
- OpenGL立方体纹理贴图
OpenGL正方体纹理贴图 0. 写在最前面 1. 正方体顶点属性构建 2. 绑定多个VAO.VBO 3. 创建多个纹理 4. 渲染循环 5. 实现代码 6. 多个立方体纹理贴图 0. 写在最前面 要 ...
- openCV读入图片,openGL实现纹理贴图
本文结合结合openCV,openGL的优点,实现混合编程. (1)OpenCV提供图形处理和计算机视觉方面的通用算法,读入二维图片很方便: (2)OpenGL是跨平台的图形程序接口,它用于二维,三维 ...
- 纹理窗口Qt+OpenGL之纹理贴图
上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助.今天在这里和大家一起学习一下纹理窗口 NeNe的代码中是加载到了一个正方体当中,代码很长.其实单纯的想要纹理贴图是很便利的.具体的纹理贴图技巧在 ...
- 手把手教会OpenGL之纹理贴图、包含纹理载入、纹理过滤、边界处理、纹理参数设置(入门级别案例,棋盘)
一.OpenGL中纹理的加载(对glTexImage2D函数的使用) 二.纹理过滤(glTexParameteri参数中的GL_TEXTURE_MAG_FILTER与 GL_TEXTURE_MIN_F ...
- Opengl实现纹理贴图
纹理贴图的步骤 创建纹理对象,并为它指定一个纹理 确定纹理如何应用到每个像素上 启用纹理贴图功能 绘制场景,提供纹理坐标和几何图形坐 Tips:纹理坐标必须在RGBA模式下才能使用,在颜色索引模式下是 ...
- (转)各种纹理贴图技术
凹凸贴图(bump mapping)概念 无论是程序员还是美工人员,几乎每个游戏开发者都知道一些3D图形学的知识,因此每个人都或多或少了解 一点bump mapping.Bump mapping是在像 ...
- opengl es纹理贴图效果实例
一.先准备好一张用来贴图的照片 二.纹理效果代码: gl.glEnable(GL10.GL_TEXTURE_2D);// 创建纹理gl.glGenTextures(1, textureids, 0); ...
- opengl android 纹理贴图 代码,Android 使用opengl es的纹理贴图白屏问题请教。
各位大侠好: 我在使用open gl es的做显示的时候,发现一个问题,请各位帮助一下,谢谢. 环境:opengl es 1.x,2D的模式显示纹理图片. 在LG-P990,HTC-C510E上显示附 ...
最新文章
- R语言max函数min函数计算各种数据对象最大值最小值实战
- 【解析】在高级语言源程序中, 常需要用户定义的标识符为程序中的对象命名,常见的命名对象有()
- numpy、cv2等操作图片基本操作
- python猜数字游戏快速求解解决方案
- python for循环 内存_Python for循环中的内存错误
- python比较两个列表不同部分_Python实现比较两个列表(list)范围
- MySQL8.0 - 新特性 - 临时表改进 1
- visio箭头尾部遮盖方框边线
- 川大教师发自白书:一所高校就是一座衙门
- Codeforces Edu:双指针 » Step 3 » Practice:A. Looped Playlist
- Session 钝化机制
- 数据接口-免费版(股票数据API)
- 如何测试一个一次性水杯
- ps里面怎么插入流程图_Photoshop制作网站流程图详细过程
- 下一代云原生应用交付会怎样发展?KubeVela帮大忙。
- 报名进行时!邀您一起海外社媒会话跨境直播,实地探访MCN机构
- NEON优化:性能优化常见问题QA
- 心理励志,激活生命的潜能
- 03、滤波器设计——阶跃阻抗低通滤波器
- 韩信点兵问题的简单算法(downmoon)
热门文章
- 洛谷 P5738歌唱比赛 题解
- 易观千帆 | 12月用户体验GX评测:国有行及股份行持续领跑,农信社用户体验关注提升
- iOS 自带定位CLLocationManager获取经纬度以及城市名称,并判断是否打开定位权限
- C# Chart控件的使用总结
- OkHttp原理解析(二)
- WordPress知更鸟(Begin)主题评论邮件回复失效的解决办法
- 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU外设那些事(2)- 百变星君FlexRAM
- lighttp支持PHP移植到imx6,FFmpeg移植-迅为IMX6ULL开发板
- NBP Lumizone(PS亮度蒙版调色插件)v1.1.001版本更新
- “百付宝”带来百度未来格局的真正悬念