NeHe OpenGL教程 第二十三课:球面映射
前言
声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改。对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢。
NeHe OpenGL第二十三课:球面映射

球面映射:
这一个将教会你如何把环境纹理包裹在你的3D模型上,让它看起来象反射了周围的场景一样。
球体环境映射是一个创建快速金属反射效果的方法,但它并不像真实世界里那么精确!我们从18课的代码开始来创建这个教程,教你如何创建这种效果。
在我们开始之间,看一下红宝书中的介绍。它定义球体环境映射为一幅位于无限远的图像,把它映射到球面上。
在Photoshop中创建一幅球体环境映射图。
首先,你需要一幅球体环境映射图,用来把它映射到球体上。在Photoshop中打开一幅图并选择所有的像素,创建它的一个复制。
接着,我们把图像变为2的幂次方大小,一般为128x128或256x256。
最后使用扭曲(distort)滤镜,并应用球体效果。然后把它保存为*.bmp文件。
我们并没有添加任何全局变量,只是把纹理组的大小变为6,以保存6幅纹理。
GLuint texture[6]; // 保存6幅纹理
下面我们要做的就是载入这些纹理
int LoadGLTextures()
{
int Status=FALSE;
AUX_RGBImageRec *TextureImage[2]; // 创建纹理的保存空间
memset(TextureImage,0,sizeof(void *)*2); // 清空为0
// 载入*.bmp图像
if ((TextureImage[0]=LoadBMP("Data/BG.bmp")) && // 背景图
(TextureImage[1]=LoadBMP("Data/Reflect.bmp"))) // 反射图(球形纹理图)
{
Status=TRUE;
glGenTextures(6, &texture[0]); // 创建6个纹理
for (int loop=0; loop<=1; loop++)
{
// 创建临近点过滤纹理图
glBindTexture(GL_TEXTURE_2D, texture[loop]); // 创建纹理0和1
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[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
// 创建线形过滤纹理图
glBindTexture(GL_TEXTURE_2D, texture[loop+2]); // 创建纹理2,3
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[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
// 创建线形Mipmap纹理图
glBindTexture(GL_TEXTURE_2D, texture[loop+4]); // 创建纹理4,5
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[loop]->sizeX, TextureImage[loop]->sizeY,
GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
}
for (loop=0; loop<=1; loop++)
{
if (TextureImage[loop]) // 如果图像存在则清除
{
if (TextureImage[loop]->data)
{
free(TextureImage[loop]->data);
}
free(TextureImage[loop]);
}
}
}
return Status;
}
我们对立方体的绘制代码做了一些小的改动,把法线的范围从[-1,1]缩放到[-0.5,0.5]。如果法向量太大的话,会产生一些块状效果,影响视觉效果。
GLvoid glDrawCube()
{
glBegin(GL_QUADS);
// 前面
glNormal3f( 0.0f, 0.0f, 0.5f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// 背面
glNormal3f( 0.0f, 0.0f,-0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// 上面
glNormal3f( 0.0f, 0.5f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// 下面
glNormal3f( 0.0f,-0.5f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// 右面
glNormal3f( 0.5f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// 左面
glNormal3f(-0.5f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}
在初始化OpenGL中,我们添加一些新的函数来使用球体纹理映射。
下面的代码让OpenGL自动为我们计算使用球体映射时,顶点的纹理坐标。
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // 设置s方向的纹理自动生成
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // 设置t方向的纹理自动生成
我们几乎完成了所有的工作!接下来要做的就是就是绘制渲染,我删除了一些二次几何体,因为它们的视觉效果并不好。当然我们需要OpenGL为这些几何体自动生成坐标,接着选择球体映射纹理并绘制几何体。最后把
OpenGL状态设置正常模式。
int DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // 重置视口
glTranslatef(0.0f,0.0f,z);
glEnable(GL_TEXTURE_GEN_S); // 自动生成s方向纹理坐标
glEnable(GL_TEXTURE_GEN_T); // 自动生成t方向纹理坐标
glBindTexture(GL_TEXTURE_2D, texture[filter+(filter+1)]); // 绑定纹理
glPushMatrix();
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
switch(object)
{
case 0:
glDrawCube();
break;
case 1:
glTranslatef(0.0f,0.0f,-1.5f); // 创建圆柱
gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);
break;
case 2:
gluSphere(quadratic,1.3f,32,32); // 创建球
break;
case 3:
glTranslatef(0.0f,0.0f,-1.5f); // 创建圆锥
gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);
break;
};
glPopMatrix();
glDisable(GL_TEXTURE_GEN_S); // 禁止自动生成纹理坐标
glDisable(GL_TEXTURE_GEN_T);
xrot+=xspeed;
yrot+=yspeed;
return TRUE; // 成功返回
}
最后我们使用空格来切换各个不同的几何体
if (keys[' '] && !sp)
{
sp=TRUE;
object++;
if(object>3)
object=0;
}
原文及其个版本源代码下载:
NeHe OpenGL教程 第二十三课:球面映射的更多相关文章
- NeHe OpenGL教程 第二十课:蒙板
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第十三课:图像字体
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十七课:影子
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十一课:线的游戏
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十二课:凹凸映射
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十八课:贝塞尔曲面
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十六课:反射
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十九课:Blt函数
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十五课:变形
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
随机推荐
- Wireshark抓包实例分析TCP重复ACK与乱序
转载请在文首保留原文出处: EMC 中文支持论坛https://community.emc.com/go/chinese 介绍 TCP 的一大常见问题在于重复 ACK 与快速重传.这一现象的发生也是由 ...
- C#绘图双缓冲
C#绘图双缓冲 C#双缓冲解释: 简单说就是当我们在进行画图操作时,系统并不是直接把内容呈现到屏幕上,而是先在内存中保存,然后一次性把结果输出来,如果没用双缓冲的话,你会发现在画图过程中屏幕会闪的很厉 ...
- eclipse启动不了,让查看.metadata/.log
方法一: 下面是workspace E:\kuaipan\work\J2EE_workspace\.metadata\.plugins\org.eclipse.core.resources\.proj ...
- oracle更新统计信息以及解锁统计信息
begin dbms_stats.unlock_table_stats(ownname => 'DM_MPAY', tabname => 'PLAT_INFO');end; begin d ...
- 【转】Python numpy库的nonzero函数用法
当使用布尔数组直接作为下标对象或者元组下标对象中有布尔数组时,都相当于用nonzero()将布尔数组转换成一组整数数组,然后使用整数数组进行下标运算. nonzeros(a) 返回数组a中值不为零的元 ...
- easyui datagrid 表格组件列属性formatter和styler使用方法
明确单元格DOM结构 要想弄清楚formatter和styler属性是怎么工作的,首先要弄清楚datagrid组件内容单元格的DOM接口,注意,这里指的是内容单元格,不包括标题单元格,标题单元格的结构 ...
- Linux-Load blance
在实际应用中,在Web服务器集群之前总会有一台负载均衡服务器,负载均衡设备的任务就是作为Web服务器流量的入口,挑选最合适的一台Web服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转 ...
- Appium查找元素
记录一些需要记忆的查找元素的内容: 1. driver.findElement(By.name("DELETE"); //We can use the DELETE text ...
- Kindle 实用技巧
1.Kindle Mate:可以连接kindle导出生词本,笔记,注释,超级棒. 2.把PDF发送到Kindle的时候,邮件主题写convert,这样系统会自动把PDF转换成适合Kindle阅读的格式 ...
- no ocijdbc11 in java.library.path linux
no ocijdbc11 in java.library.path linux vi /etc/profile export ORACLE_HOME=/oracle/database/oracle/p ...