Exercise 5:alpha混合
要求:
1. 绘制若干个透明和非透明茶壶,并体现出它们之间正确的混合效果;
考察目的:
1. OpenGL中alpha混合的使用;
2. 混合绘制透明和不透明物体的正确方法;
3. 运算符的重载和基本STL的使用;
by/scu xx
#include <iostream>
#include <gl\glew.h>
#include <glut.h>
#pragma comment(lib,"glew32.lib")
using namespace std;
bool isRotatef; // 控制要旋转整个视图
bool isLightOpen; //定义光源是否打开的bool值
GLfloat LightPosition[] = {4.0f, 4.0f, 6.0f, 1.0f}; //点光源的位置
static int mousePosX = 0, mousePosY = 0, tempX, tempY;
bool isMosDownMove=false;//鼠标按下移动时的判断变量
void createLight()
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
GLfloat LightAmbient[]= { 0.0f, 0.5f, 0.5f, 1.0f }; //环境光参数
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; //漫射光参数(由参数可知识最亮的漫射光)
GLfloat LightSpecular[]= { 0.5f, 0.5f, 0.0f, 1.0f }; //镜面光参数
//指定光源属性,3个参数决定了它所指定的哪个光源的属性、具体的属性以及该属性的预想值
glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpecular);
}
void init(void)
{
glClearColor(0.7f, 0.7f, 0.7f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
isLightOpen = true; //光源开启
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
if (GLEW_OK != glewInit()) {
cout << "Fail to initialize GLEW!\n";
exit(1);
}
createLight();
isRotatef = true; //默认移动鼠标旋转整个视图
}
void display(void)
{
GLfloat mat_emission1[] = { 0.8, 0.8, 0.8, 1.0 };
GLfloat mat_diffuse1[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_emission2[] = { 0.0, 0.8, 0.8, 0.6 };
GLfloat mat_diffuse2[] = { 0.0, 0.3, 0.3, 0.6 };
GLfloat mat_emission3[] = { 0.4, 0.4, 0.0, 0.4 };
GLfloat mat_diffuse3[] = { 0.6, 0.6, 0.0, 0.4 };
GLfloat mat_emission4[] = { 0.75, 0.75, 0.0, 0.5 };
GLfloat mat_diffuse4[] = { 0.4, 0.0, 0.4, 0.5 };
GLfloat mat_emission5[] = { 0.9, 0.9, 0.0, 0.6 };
GLfloat mat_diffuse5[] = { 0.0, 0.0, 0.0, 0.6 };
GLfloat mat_emission6[] = { 0.0, 0.6, 0.6, 1.0 };
GLfloat mat_diffuse6[] = { 0.0, 0.0, 0.0, 1.0 };
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//进行视图变换前调用下面两个函数,接下来的变换函数将影响模型变换矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//3组参数:指定了观察点的位置,定义照相机瞄准的参考点,提示哪个方向是朝上的(3个为一组)
//设置照相机的位置 b
gluLookAt(0.0f, 0.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0);
//通过平移与旋转按照预想的方式移动观察点
//glTranslatef(0.0f, 0.0f, 0.0f);
/*************************************点光源的处理***********************************************/
//复制一份当前矩阵,并把这份复制添加到堆栈的顶部(记住自己的位置)
glPushMatrix();
glTranslatef(LightPosition[0], LightPosition[1], LightPosition[2]);
glDisable(GL_LIGHTING); //使用glColor3f需要禁用光照
if (isLightOpen)
{
glColor3f(1.0f, 0.0f, 1.0f); //打开时颜色变亮
}
else
{
glColor3f(0.0f, 0.0f, 0.0f); //关闭时颜色变暗
}
//用于渲染一个球体 函数原型void glutSolidSphere(GLdouble radius , GLint slices , GLint stacks);
//radius球体的半径
//slices以Z轴上线段为直径分布的圆周线的条数(将Z轴看成地球的地轴,类似于经线)
//stacks围绕在Z轴周围的线的条数(类似于地球上纬线)
//一般而言, 后两个参数赋予较大的值, 渲染花费的时间要长, 效果更逼真
glutSolidSphere(0.1, 10.0, 10.0);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
glPopMatrix(); //丢弃堆栈顶部的那个矩阵(回到原来的位置)
if (isRotatef) //判断是否需要旋转视图
{
glRotatef((GLfloat) mousePosX, -1.0, 0.0, 0.0);
glRotatef((GLfloat) mousePosY, 0.0, -1.0, 0.0);
}
/****************************************茶壶1************************************************/
glPushMatrix();
glTranslatef(-4.0f, 0.0f, 0.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse1);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);//控制深度缓冲区是否可写
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//选择源混合因子与目标混合因子
glutSolidTeapot(0.8);//显示一个茶壶,参数为茶壶的大小
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
/****************************************茶壶2************************************************/
glPushMatrix();
glTranslatef(0.0f, 3.0f, -2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission2);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse2);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
/****************************************茶壶3************************************************/
glPushMatrix();
glTranslatef(4.0f, 0.0f, 0.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission3);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse3);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
/****************************************茶壶4************************************************/
glPushMatrix();
glTranslatef(0.0f, -3.0f, 2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission4);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse4);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
/****************************************茶壶5************************************************/
glPushMatrix();
glTranslatef(-8.0f, -3.0f, 2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission5);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse5);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
/****************************************茶壶6************************************************/
glPushMatrix();
glTranslatef(8.0f, -3.0f, 2.0f);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission6);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse6);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutSolidTeapot(0.8);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h)
{
float aspect = (float) w/((h)?h:1); //平截头体的纵横比,也就是宽度除以高度,(h)?h:1意思是若h=0,则h=1
glViewport(0,0, w, h);
//进行投影变换前调用下面两个函数,接下来的变换函数将影响投影矩阵
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, aspect, 1.0f, 100.0f);
glViewport(0,0,w,h);
glMatrixMode(GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'o': //打开/关闭 光源
isLightOpen = !isLightOpen;
if (!isLightOpen)
{
glDisable(GL_LIGHT0);
}
else
{
glEnable(GL_LIGHT0);
}
break;
case 27: //退出程序
exit(0);
break;
}
}
void mouse(int button, int state, int x, int z)
{
switch(button)
{
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
{
tempX = x;
tempY = z;
isMosDownMove = true; //鼠标移动时需要用到的判断变量
}
else
{
isMosDownMove = false;
}
break;
}
}
void motion(int x, int z)
{
if(isMosDownMove)
{
mousePosY = (mousePosY + (x - tempX))%360;
mousePosX = (mousePosX + (z - tempY))%360;
tempX = x;
tempY = z;
glutPostRedisplay();
}
}
void animate(void)
{
//刷新屏幕
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
glutInitWindowSize(800, 600);
glutInitWindowPosition(100,100);
glutCreateWindow("Teaports");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutIdleFunc(animate);
glutMainLoop();
return 0;
}
运行结果: