一、实验目的
理解消隐的概念、原理;掌握几种常用的消隐算法的思想;能够编程实现经典的面消隐算法,如Z-buffer算法、画家算法等,以加深对消隐算法的理解和掌握。理解计算机图形学中有关着色、光照、材质、纹理处理的编程原理;加深学生对几何变换、投影变换以及观察变换的理解,并提高学生利用图形软件包绘制图形的能力;能够综合运用本课程所学的有关知识,编写具有一定真实感效果的三维物体程序。
二、实验要求
1.理解OpenGL中消隐的实现。
2.理解深度缓存和帧缓存的作用。
3.理解光源的设置、光照函数的含义。
4.增加纹理处理。
1.遮挡
#include<GL/glut.h>
enum{FILL,WIRE};
enum{SPHERE=1,CONE,WALLS};
int rendermode = FILL;
GLUquadricObj* sphere, * cone, * base;
static GLfloat lightpos[] = { 50.f,50.f,-320.f,1.f };
static GLfloat wall_mat[] = { 0.8f,0.8f,0.8f,1.f };
static GLfloat sphere_mat[] = { 1.0f,0.2f,0.2f,1.f };
static GLfloat cone_mat[] = { 0.2f,1.0f,0.2f,1.f };
void Initial();
void Display();
void menu(int );
void drawscene();
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("遮挡");
glutDisplayFunc(Display);
glutCreateMenu(menu);
glutAddMenuEntry("Solid Fill", FILL);//把FILL这个位置的参数传入到menu函数中
glutAddMenuEntry("Wireframe", WIRE);
glutAttachMenu(GLUT_RIGHT_BUTTON);//按右键显示菜单
Initial();//必要的其他初始化函数
glutMainLoop();//进入循环
return 0;
}
void Initial() {
glMatrixMode(GL_PROJECTION);
glFrustum(-100.0, 100.0, -100.0, 100.0, 320.0, 640.0);//透视显示:左右下上近远
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);//打开深度缓冲设置
glDepthFunc(GL_LEQUAL);//判断遮挡关系时,离视点近的遮挡离视点远的物体。GL-NEVER不判断,GL_ALWAYS,GL_LESS,GL_LEQUAL
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
glNewList(SPHERE, GL_COMPILE);
sphere = gluNewQuadric();//创建一个对象
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
gluSphere(sphere, 50.f, 40, 40);//让该对象画球,参数:球体,半径,经度分割线,纬度分割线
gluDeleteQuadric(sphere);//释放对象
glEndList();
glNewList(CONE, GL_COMPILE);
cone = gluNewQuadric();
base = gluNewQuadric();
glPushMatrix();
glRotatef(-90.f, 1.f, 0.f, 0.f);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
gluQuadricOrientation(base, GLU_INSIDE);
gluDisk(base, 0., 40., 20, 1);//碟盘(圆锥的底,如果画圆柱需要两个底)参数:对象,内环半径,外环半径,分割线,同心圆线
gluCylinder(cone, 40., 0., 120., 20, 20);//圆锥,参数:对象,下半径,上半径,高,经度分割线,纬度分割线
glPopMatrix();
gluDeleteQuadric(cone);
gluDeleteQuadric(base);
glEndList();
//WALLS
glNewList(WALLS,GL_COMPILE);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
glBegin(GL_QUADS);
glNormal3f(0.f, 1.f, 0.f);
glVertex3f(-100.f, -100.f, -320.f);
glVertex3f(100.f, -100.f, -320.f);
glVertex3f(100.f, -100.f, -520.f);
glVertex3f(-100.f, -100.f, -520.f);
//left wall
glNormal3f(1.f, 0.f, 0.f);
glVertex3f(-100.f, -100.f, -320.f);
glVertex3f(-100.f, -100.f, -520.f);
glVertex3f(-100.f, 100.f, -520.f);
glVertex3f(-100.f, 100.f, -320.f);
//right wall
glNormal3f(-1.f, 0.f, 0.f);
glVertex3f(100.f, -100.f, -320.f);
glVertex3f(100.f, 100.f, -320.f);
glVertex3f(100.f, 100.f, -520.f);
glVertex3f(100.f, -100.f, -520.f);
//ceiling
glNormal3f(0.f, -1.f, 0.f);
glVertex3f(-100.f, 100.f, -320.f);
glVertex3f(-100.f, 100.f, -520.f);
glVertex3f(100.f, 100.f, -520.f);
glVertex3f(100.f, 100.f, -320.f);
//back wall
glNormal3f(0.f, 0.f, 1.f);
glVertex3f(-100.f, -100.f, -520.f);
glVertex3f(100.f, -100.f, -520.f);
glVertex3f(100.f, 100.f, -520.f);
glVertex3f(-100.f, 100.f, -520.f);
glEnd();
glEndList();
}
void menu(int selection) {
rendermode = selection;
glutPostRedisplay();
}
void drawscene() {
glCallList(WALLS);
glPushMatrix();
glTranslatef(-20.f, -40.f, -400.f);
glCallList(SPHERE);
glPopMatrix();
glPushMatrix();
glTranslatef(40.f, -100.f, -420.f);
glCallList(CONE);
glPopMatrix();
glPushMatrix();
glTranslatef(-40.f, -40.f, -400.f);
glCallList(CONE);
glPopMatrix();
}
void Display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
switch (rendermode)
{
case FILL:
drawscene(); break;
case WIRE:
glDisable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//GL_POINTS,GL_FILL
glColor4f(0.0, 0.0, 0.0, 1.0);
drawscene();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LIGHTING);
break;
default:
break;
}
glFlush();
}
2.光源
(1)运行下列程序,理解光源的设置、光照函数的含义以及参数的含义。
(2)添加一个其他颜色的光源,使用“w、s、a、d”键控制光源的移动,体会多光源的效果,如图1所示。
#include<GL/glut.h>
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static GLfloat xRot1 = 0.0f;
static GLfloat yRot1 = 0.0f;
void Initial() {
GLfloat light_diffuse[] = { 1.0,1.0,1.0,1.0 };
GLfloat light_ambient[] = { 0.0,0.5,0.5,1.0 };
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);//设置环境光颜色
GLfloat light1_diffuse[] = { 1.0,1.0,1.0,1.0 };
GLfloat light1_ambient[] = { 0.0,0.5,0.5,1.0 };
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);//设置环境光颜色
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);//启动光源LIGHT0
glEnable(GL_LIGHT1);//启动光源LIGHT1
glEnable(GL_DEPTH_TEST);//深度测试
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
void ChangeSize(int w, int h)
{
if (h == 0) h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0f, (GLfloat)w / (GLfloat)h, 1.0f, 20.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLfloat light0_position[] = { 0.0f,0.0f,1.5f,1.0f };//最后一个参数1.0指前面设置的点位置,0.0为无限远处
GLfloat light1_position[] = { 0.0f,0.0f,1.5f,1.0f };
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -5.0f);
glRotated(yRot, 0.0f, 1.0f, 0.0f);
glRotated(xRot, 1.0f, 0.0f, 0.0f);
//设置光源的位置
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glTranslatef(0.0f, 0.0f, 1.5f);
//绘制一个黄色的光球
glDisable(GL_LIGHTING);
glColor3f(1.0f, 1.0f, 0.0f);
glutSolidSphere(0.1f, 50.0f, 50.0f);
glEnable(GL_LIGHTING);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -5.0f);
glRotated(yRot1, 0.0f, 1.0f, 0.0f);
glRotated(xRot1, 1.0f, 0.0f, 0.0f);
//设置光源的位置
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glTranslatef(0.0f, 0.0f, 1.5f);
//绘制一个红色的光球
glDisable(GL_LIGHTING);
glColor3f(1.0f, 0.0f, 0.0f);
glutSolidSphere(0.1f, 50.0f, 50.0f);
glEnable(GL_LIGHTING);
glLoadIdentity();
//设置材质属性
GLfloat mat_diffuse[] = { 0.0f,0.5f,1.0f,1.0f };
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glTranslatef(0.0f, 0.0f, -5.0f);
glutSolidTorus(0.275, 0.85, 50, 50);
glLoadIdentity();
glutSwapBuffers();
}
void Keys(unsigned char key, int x, int y) {
switch (key)
{
case 'i':xRot -= 5.0f; break;
case 'k':xRot += 5.0f; break;
case 'j':yRot -= 5.0f; break;
case 'l':yRot += 5.0f; break;
case 'w':xRot1 -= 5.0f; break;
case 's':xRot1 += 5.0f; break;
case 'a':yRot1 -= 5.0f; break;
case 'd':yRot1 += 5.0f; break;
default:
break;
}
if (key > 356.0f)
xRot = 0.0f;
if (key < -1.0f)
xRot = 355.0f;
if (key > 356.0f)
yRot = 0.0f;
if (key < -1.0f)
yRot = 355.0f;
if (key > 356.0f)
xRot1 = 0.0f;
if (key < -1.0f)
xRot1 = 355.0f;
if (key > 356.0f)
yRot1 = 0.0f;
if (key < -1.0f)
yRot1 = 355.0f;
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
//初始化工具包
glutInit(&argc, argv);
//设置显示模式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
//窗口设置
glutInitWindowPosition(100, 100);
glutInitWindowSize(400, 400);
glutCreateWindow("光源");
//调用绘图函数,回调函数,不断监听
glutReshapeFunc(ChangeSize);
glutDisplayFunc(Display);
glutKeyboardFunc(Keys);
Initial();//必要的其他初始化函数
glutMainLoop();//进入循环
return 0;
}
3.彩虹
使用一维纹理映射,绘制一段七色彩虹,如图2所示。
#include<GL/glut.h>
#include <math.h>
#ifndef M_pI
#define M_PI 3.141592649
#endif
static GLubyte roygbiv_image[8][3] = {
{0x3f,0x00,0x3f},//深蓝紫色
{0x7f,0x00,0x7f},//蓝紫色
{0xbf,0x00,0xbf},//靛蓝
{0x00,0x00,0xff},//蓝色
{0x00,0xff,0x00},//绿色
{0xff,0xff,0x00},//黄色
{0xff,0x7f,0x00},//橙色
{0xff,0x00,0x00},//红色
};
void ChangeSize(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (float)width / (float)height, 0.1, 1000.0);
glMatrixMode(GL_MODELVIEW);
}
void Initial() {
glClearColor(0.3, 0.8, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//最基本的执行纹理映射的步骤
//1.定义纹理,2.控制纹理,3.说明纹理映射的方式,4.绘制场景
//1.定义纹理
glTexImage1D(GL_TEXTURE_1D, 0, 3, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, roygbiv_image);
//2.控制纹理,设定纹理如何对应屏幕像素,实现纹理缩放纹理重复
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//3.说明纹理映射方式
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
//表示使用最靠近使用纹理像素的四个纹素的加权平均值
//定义一维纹理,颜色分量为RGB
//宽度为8,边界为0,使用无符号整数
//定义纹理环境参数,使用纹理图像
}
void Display() {
GLfloat x, y, z, th;
//draw ground
glDisable(GL_TEXTURE_1D);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glPushMatrix();
glRotatef(10.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0, -40.0, -100.0);
glColor3f(0.0, 0.8, 0.0);
glBegin(GL_POLYGON);
for (th = 0.0; th < (2.0 * M_PI); th += (0.03125 * M_PI)) {
x = cos(th) * 200.0;
z = sin(th) * 200.0;
glVertex3f(x, 0.0, z);
}
glEnd();
//draw rainbow
glEnable(GL_TEXTURE_1D);
glBegin(GL_QUAD_STRIP);//共享四边形
for (th = 0.0; th < (2.0 * M_PI); th += (0.03125 * M_PI)) {
x = cos(th) * 50.0;
y = sin(th) * 50.0;
z = -50.0;
glTexCoord1f(0.0);
glVertex3f(x, y, z);
x = cos(th) * 55.0;
y = sin(th) * 55.0;
z = -50.0;
glTexCoord1f(1.0);
glVertex3f(x, y, z);
}
glEnd();
glPopMatrix();
glFlush();
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(792, 753);
glutCreateWindow("彩虹");
//调用绘图函数,回调函数,不断监听
glutReshapeFunc(ChangeSize);
glutDisplayFunc(Display);
Initial();//必要的其他初始化函数
glutMainLoop();//进入循环
return 0;
}
4.纹理
使用图片纹理绘制不同花纹的茶壶,如图3所示。
链接: 图片在线转bmp格式.
将bmp格式文件放在工程目录中
#include <stdio.h>
#include <windows.h>
#include <GL/glut.h>
//读纹理函数:
#define BITMAP_ID 0x4D42
#define TEX_NUM 4
GLuint Texture[TEX_NUM];
char *TextureName[] = {
"teapot1.BMP",
"teapot2.BMP",
"teapot3.BMP",
"teapot4.BMP",
};
// 读纹理函数
// 纹理标示符数组,保存两个纹理的标示符
// 描述: 通过指针,返回filename 指定的bitmap文件中数据。
// 同时也返回bitmap信息头.(不支持-bit位图)
unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; // 文件指针
BITMAPFILEHEADER bitmapFileHeader; // bitmap文件头
unsigned char *bitmapImage; // bitmap图像数据
int imageIdx = 0; // 图像位置索引
unsigned char tempRGB; // 交换变量
// 以“二进制+读”模式打开文件filename
filePtr = fopen(filename,"rb");
if (filePtr == NULL) return NULL;
// 读入bitmap文件图
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// 验证是否为bitmap文件
if (bitmapFileHeader.bfType != BITMAP_ID) {
fprintf(stderr, "Error in LoadBitmapFile: the file is not a bitmap file\n");
return NULL;
}
// 读入bitmap信息头
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// 将文件指针移至bitmap数据
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// 为装载图像数据创建足够的内存
bitmapImage = new unsigned char[bitmapInfoHeader->biSizeImage];
// 验证内存是否创建成功
if (!bitmapImage) {
fprintf(stderr, "Error in LoadBitmapFile: memory error\n");
return NULL;
}
// 读入bitmap图像数据
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
// 确认读入成功
if (bitmapImage == NULL) {
fprintf(stderr, "Error in LoadBitmapFile: memory error\n");
return NULL;
}
//由于bitmap中保存的格式是BGR,下面交换R和B的值,得到RGB格式
for (imageIdx = 0; imageIdx < (bitmapInfoHeader->biSizeImage); imageIdx += 3) {
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
// 关闭bitmap图像文件
fclose(filePtr);
return bitmapImage;
}
//加载纹理的函数:
void texload(int i, char *filename)
{
BITMAPINFOHEADER bitmapInfoHeader; // bitmap信息头
unsigned char* bitmapData; // 纹理数据
bitmapData = LoadBitmapFile(filename, &bitmapInfoHeader);
glBindTexture(GL_TEXTURE_2D, Texture[i]);
// 指定当前纹理的放大/缩小过滤方式
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, //mipmap层次(通常为,表示最上层)
GL_RGB, //我们希望该纹理有红、绿、蓝数据
bitmapInfoHeader.biWidth, //纹理宽带,必须是n,若有边框+2
bitmapInfoHeader.biHeight, //纹理高度,必须是n,若有边框+2
0, //边框(0=无边框, 1=有边框)
GL_RGB, //bitmap数据的格式
GL_UNSIGNED_BYTE, //每个颜色数据的类型
bitmapData); //bitmap数据指针
}
//绘制茶壶
GLint GenTeapotList()
{
GLint lid = glGenLists(1);
glNewList(lid, GL_COMPILE);
GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_diffuse[] = { 0.55, 0.55, 0.55, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 90.0 };
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glutSolidTeapot(0.5);
glEndList();
return lid;
}
//定义纹理的函数:
void init(void) //
{
glEnable(GL_DEPTH_TEST);//打开深度测试
//定义光源
GLfloat position1[] = { 1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, position1);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//定义纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(TEX_NUM, Texture);
for (int i = 0; i < TEX_NUM; i++) {
texload(i, TextureName[i]);
glBindTexture(GL_TEXTURE_2D, Texture[i]);
//设置像素存储模式控制所读取的图像数据的行对齐方式.
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
glDisable(GL_TEXTURE_2D);
}
void display(void)
{
glClearColor(0.85f, 0.85f, 0.85f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture[0]); //选择纹理图案
glCallList(GenTeapotList());
glFlush();
}
void reshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv); //初始化工具包
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); //设置显示模式
glutInitWindowPosition(0, 0); //设置窗口在屏幕上的位置
glutInitWindowSize(500, 500); //设置窗口的大小
glutCreateWindow("纹理"); //打开屏幕窗口
glutReshapeFunc(reshape);
glutDisplayFunc(display); //调用绘图函数
init(); //必要的其他初始化函数
glutMainLoop(); //进入循环
return 0;
}