(此节内容对应NEHE教程第23课)
把环境纹理包裹在你的3D模型上,让它看起来象反射了周围的场景一样。
球体环境映射是一个创建快速金属反射效果的方法
首先,你需要一幅球体环境映射图,用来把它映射到球体上。在Photoshop中打开一幅图并选择所有的像素,创建它的一个复制。
接着,我们把图像变为2的幂次方大小,一般为128x128或256x256。
最后使用扭曲(distort)滤镜,并应用球体效果。然后把它保存为Reflect.bmp文件。
如右图上面的为背景的图片,下面为经过球面滤镜处理过的,用于进行球面贴图的纹理
对于球面映射往往我们希望背景图片是不变的,前面球面是可以转动的,因此适当的PUSH 与POP 视图模型 可以带到效果
原始图片 处理后图片 合成后效果
#include "header.h"
int part1;
int part2;
int p1=0;
int p2=1;
GLfloat xrot;
GLfloat yrot;
GLfloat xspeed;
GLfloat yspeed;
GLfloat z=-10.0f;
GLUquadricObj *quadratic;
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 filter;
GLuint texture[6];
GLuint object=1;
AUX_RGBImageRec *LoadBMP(char *Filename)
{
FILE *File=NULL;
if (!Filename)
{
return NULL;
}
File=fopen(Filename,"r");
if (File)
{
fclose(File);
return auxDIBImageLoad(Filename);
}
return NULL;
}
int loop=0;
int LoadGLTextures()
{
int Status=FALSE;
AUX_RGBImageRec *TextureImage[2];
memset(TextureImage,0,sizeof(void *)*2);
if ((TextureImage[0]=LoadBMP("Data/BG.bmp")) &&
(TextureImage[1]=LoadBMP("Data/Reflect.bmp")))
{
Status=TRUE;
glGenTextures(6, &texture[0]);
for ( loop=0; loop<2; loop++)
{
// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[loop]); // Gen Tex 0 and 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);
// Create Linear Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[loop+2]); // Gen Tex 2 and 3 4
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);
// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[loop+4]); // Gen Tex 4 and 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<2; loop++)
{
if (TextureImage[loop])
{
if (TextureImage[loop]->data)
{
free(TextureImage[loop]->data);
}
free(TextureImage[loop]);
}
}
}
return Status;
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
if (height==0)
{
height=1;
}
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int InitGL(void)
{
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);
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
glEnable(GL_LIGHT1);
quadratic=gluNewQuadric();
gluQuadricNormals(quadratic, GLU_SMOOTH);
gluQuadricTexture(quadratic, GL_TRUE);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
return TRUE;
}
void glDrawCube()
{
glBegin(GL_QUADS);
// Front Face
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);
// Back Face
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);
// Top Face
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);
// Bottom Face
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);
// Right Face
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);
// Left Face
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();
}
void DrawGLScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,z);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_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);
glBindTexture(GL_TEXTURE_2D, texture[filter*2]);
glPushMatrix();
glTranslatef(0.0f, 0.0f, -24.0f);
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-13.3f, -10.0f, 10.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 13.3f, -10.0f, 10.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 13.3f, 10.0f, 10.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-13.3f, 10.0f, 10.0f);
glEnd();
glPopMatrix();
xrot+=xspeed;
yrot+=yspeed;
glFlush();
}
void rotate()
{
glutPostRedisplay();
}
void keyboard(unsigned char key,int x,int y)
{
switch (key)
{
case 'L':
glEnable(GL_LIGHTING);
glutPostRedisplay();
break;
case 'l':
glDisable(GL_LIGHTING);
glutPostRedisplay();
break;
case ' ':
object++;
if(object>5)
object=0;
glutPostRedisplay();
break;
case 'F':
filter+=1;
if (filter>2)
{
filter=0;
}
glutPostRedisplay();
break;
case 'W':
yspeed+=0.01f;
glutIdleFunc(rotate);
break;
case 'S':
yspeed-=0.01f;
glutIdleFunc(rotate);
break;
case 'A':
xspeed+=0.01f;
glutIdleFunc(rotate);
break;
case 'D':
xspeed-=0.01f;
glutIdleFunc(rotate);
break;
case 'Z':
z-=0.01f;
glutIdleFunc(rotate);
break;
case 'X':
z+=0.01f;
glutIdleFunc(rotate);
break;
case 'R':
glutIdleFunc(NULL);
break;
}
}
int main(int argc,char **argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(800,600);
glutInitWindowPosition(100,100);
glutCreateWindow("球面映射");
InitGL();
glutDisplayFunc(DrawGLScene);
glutKeyboardFunc(keyboard);
glutReshapeFunc(ReSizeGLScene);
glutMainLoop();
}