在《OpenGL--天空盒》为基础模板来实现。把SkyBox.h,SkyBox.cpp复制过来,由于不用 CBMPLoader(天空盒的bmp图太大,用jpg),对这两个文件略着修改.
SkyBox.h:
//2,天空盒实现类
//SkyBox.h 开始
#ifndef __SKYBOX_H__
#define __SKYBOX_H__
#include <stdio.h>
//#include "CBMPLoader.h"
#include "Vector.h"
#include "Camera.h"
#define GL_CLAMP_TO_EDGE 0x812F
int BuildTexture(char *szPathName, GLuint &texid);//这个函数在其它cpp上
/* 天空盒类 */
class CSkyBox
{
public:
/* 构造函数 */
CSkyBox();
~CSkyBox();
/* 初始化 */
bool Init();
/* 渲染天空 */
void CreateSkyBox(float x, float y, float z,
float width, float height,
float length);
private:
GLuint m_texture[6]; /*< 天空盒纹理 */
};
#endif ///__SKYBOX_H__
//SkyBox.h 结束
SkyBox.cpp:
#include "SkyBox.h"
CSkyBox::CSkyBox()
{
}
CSkyBox::~CSkyBox()
{
/* 删除纹理对象及其占用的内存 */
for(int i =0 ;i< 6; i++)
{
//m_texture[i].FreeImage();
glDeleteTextures(1,&m_texture[i]);
}
}
/* 天空盒初始化 */
bool CSkyBox::Init()
{
char filename[128] ; /*< 用来保存文件名 */
char *bmpName[] = { "back","front","bottom","top","left","right"};
for(int i=0; i< 6; i++)
{
sprintf(filename,"%s",bmpName[i]);//注意路径??把你的jpg文件放在相应文件夹中
strcat(filename,".jpg");//bmp
//if(!m_texture[i].LoadBitmap(filename)) /*< 载入位图文件 */
if(!BuildTexture(filename, m_texture[i]))
{
//MessageBox(NULL, (LPCWSTR)"装载位图文件失败!", (LPCWSTR)"错误", MB_OK); /*< 如果载入失败则弹出对话框 * 这句乱码用下句 */
MessageBox(NULL, TEXT("装载位图文件失败!"), TEXT("错误"), MB_OK); /*< 如果载入失败则弹出对话框 */
exit(0);
}
//glGenTextures(1, &m_texture[i].ID); /*< 生成一个纹理对象名称 */
//glBindTexture(GL_TEXTURE_2D, m_texture[i].ID); /*< 创建纹理对象 */
///* 控制滤波: */
///*
// 其中GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T通常可设置为GL_REPEAT或GL_CLAMP两种方式。
// 当待填充的多边形大于纹理的时候,GL_REPEAT表示多余的部分用重复的方式填充;GL_CLAMP表示多余的部分用相连边缘的相邻像素填充。
// 在实际绘制中,我们一般采用GL_CLAMP_EDGE来处理,这就消除了接缝处的细线,增强了天空盒的真实感。
//*/
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
///* 创建纹理 */
//gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, m_texture[i].imageWidth,
// m_texture[i].imageHeight, GL_RGB, GL_UNSIGNED_BYTE,
// m_texture[i].image);
}
return true;
}
/* 构造天空盒 */
void CSkyBox::CreateSkyBox(float x, float y, float z,
float box_width, float box_height,
float box_length)
{
//定义地面网格
const unsigned int MAP_WIDTH = 1024;
const unsigned int CELL_WIDTH = 16;
const unsigned int MAP = MAP_WIDTH * CELL_WIDTH / 2;
/* 获得场景中光照状态 */
GLboolean lp;
glGetBooleanv(GL_LIGHTING,&lp);
/* 计算天空盒长 宽 高 */
float width = MAP * box_width/8;
float height = MAP * box_height/8;
float length = MAP * box_length/8;
/* 计算天空盒中心位置 */
x = x+ MAP/8 - width / 2;
y = y+ MAP/24 - height / 2;
z = z+ MAP/8 - length / 2;
glDisable(GL_LIGHTING); /*< 关闭光照 */
/* 开始绘制 */
glPushMatrix();
glTranslatef(-x,-y,-z);
/* 绘制背面 */
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glBegin(GL_QUADS);
/* 指定纹理坐标和顶点坐标 */
glTexCoord2f(1.0f, 0.0f); glVertex3f(x + width, y, z);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x + width, y + height, z);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + height, z);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, z);
glEnd();
/* 绘制前面 */
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glBegin(GL_QUADS);
/* 指定纹理坐标和顶点坐标 */
glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y, z + length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height, z + length);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z + length);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y, z + length);
glEnd();
/* 绘制底面 */
//glBindTexture(GL_TEXTURE_2D, m_texture[2]);
//glBegin(GL_QUADS);
// /* 指定纹理坐标和顶点坐标 */
// glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y, z);
// glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y, z + length);
// glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y, z + length);
// glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y, z);
//glEnd();
/* 绘制顶面 */
glBindTexture(GL_TEXTURE_2D, m_texture[3]);
glBegin(GL_QUADS);
/* 指定纹理坐标和顶点坐标 */
glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y + height, z + length);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y + height, z + length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height, z);
glEnd();
/* 绘制左面 */
glBindTexture(GL_TEXTURE_2D, m_texture[4]);
glBegin(GL_QUADS);
/* 指定纹理坐标和顶点坐标 */
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height, z);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + height, z + length);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, z + length);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y, z);
glEnd();
/* 绘制右面 */
glBindTexture(GL_TEXTURE_2D, m_texture[5]);
glBegin(GL_QUADS);
/* 指定纹理坐标和顶点坐标 */
glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y, z);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x + width, y, z + length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x + width, y + height, z + length);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z);
glEnd();
glPopMatrix(); /* 绘制结束 */
if(lp) /* 恢复光照状态 */
glEnable(GL_LIGHTING);
}
主cpp:
在void display(void)中,相对于天空盒,要加以平移和缩放:
#include <stdio.h>
//1,主程序:
#include<gl/glut.h>
#include<gl/glu.h>
#include<gl/gl.h>
#include "motionModel.h"
#include "Camera.h"
#include "SkyBox.h"
/** 定义光源的属性值 */
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; /**< 环境光参数 */
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; /**< 漫射光参数 */
GLfloat LightSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; /**< 镜面光参数 */
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f }; /**< 光源位置 */
Camera m_Camera;
CSkyBox m_SkyBox;
bool LoadTexture();
void init(void)
{
/* 用户自定义的初始化过程 */
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
/* 启用纹理 */
glEnable(GL_TEXTURE_2D);
/** 载入纹理 */
//if (!LoadTexture())
// MessageBox(NULL, (LPCWSTR)"载入纹理失败!", (LPCWSTR)"错误", MB_OK);
ModelInit();
/* 初始化天空 */
if (!m_SkyBox.Init())
{
//MessageBox(NULL, (LPCWSTR)"初始化天空失败!", (LPCWSTR)"错误", MB_OK);
MessageBox(NULL, L"初始化天空失败!", L"错误", MB_OK);
exit(0);
}
/** 设置光源的属性值 */
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); /**< 设置环境光 */
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); /**< 设置漫射光 */
glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular); /**< 设置漫射光 */
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); /**< 设置光源位置 */
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);
/* 设置摄像机 */
m_Camera.setCamera(500, 35, 400, 501, 35, 400, 0, 1, 0);
//m_Camera.setCamera(0.0f, 1.5f, 6.0f, 0.0f, 1.5f, 0.0f, 0.0f, 1.0f, 0.0f);
m_Camera.setViewByMouse();
}
void display(void)
{
/* 用户自定义的绘制过程 */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
/* 放置摄像机 */
m_Camera.setLook();
/* 绘制天空 */
m_SkyBox.CreateSkyBox(0, 0, 0, 1.0, 0.5, 1.0);
//DrawGrid2();
//DrawBox();
glPushAttrib(GL_CURRENT_BIT); /**< 保存当前属性 */
glPushMatrix();
//由于相对于天空盒所以要加以平移和缩放
glTranslatef(600.0f, 22.0f, 600.0f);//平移:表示将当前图形向x轴平移5,向y轴平移-2,向z轴平移-10
glScalef(12.0f, 12.0f, 12.0f);//缩放:表示将当前图形沿x,y,z轴分别放大为原来的12倍
drawAllModel();//绘制所有模型
glPopMatrix();
glPopAttrib();
glFlush(); /*< 强制执行所有的OpenGL命令 */
}
void ChangeSize(int width, int height)
{
glViewport(0, 0, width, height); /*< 重新设置视口 */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 4000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void motion(int x, int y)
{
m_Camera.setViewByMouse();
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
case '1':
m_Camera.setSpeed(0.2f);
break;
case '2':
m_Camera.setSpeed(1.0f);
break;
case 'w':
m_Camera.moveCamera(m_Camera.getSpeed());
break;
case 's':
m_Camera.moveCamera(-m_Camera.getSpeed());
break;
case 'a':
m_Camera.yawCamera(-m_Camera.getSpeed());
break;
case 'd':
m_Camera.yawCamera(m_Camera.getSpeed());
break;
}
glutPostRedisplay();
printf("key::%d\n", key);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB);
glutInitWindowSize(800, 600);
glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) >> 1) - 400, (GetSystemMetrics(SM_CYSCREEN) >> 1) - 300);
glutCreateWindow("天空盒");
init();
glutReshapeFunc(ChangeSize);
glutDisplayFunc(display);
glutMotionFunc(motion);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
效果图:
由于该博文并没有天空盒图。如需要更好的请自己另找。
附天空图,分别是"back","front","bottom","top","left","right":
好,全文完。