0评论

OpenGL消隐与光照

文章来自https://blog.csdn.net/sinat_31601333/article/details/53558669 2019-03-12 34浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

1.设置材料的颜色

OpenGL的光照模型根据材料反射的红、绿和蓝光的比例来模拟它的颜色。和光一样,材料也具有不同的环境、散射和镜面颜色,它们决定了材料对红、绿和蓝光的反射率。材料的环境反射属性与每种入射光的环境光成分组合,散射反射属性与入射光的散射成分组合,镜面反射属性和入射光的镜面成分组合。环境和散射属性定义了材料的颜色,它们一般很相似。

使用的函数是glMaterial*():
void glMaterial{if} (GLenumface, GLenumpname, GLfloatparam);
void glMaterial{if}v (GLenumface, GLenumpname, constGLfloat *params);

face可以是GL_FRONT,GL_BACK或GL_FRONT_AND BACK,表示物体的哪些面应该接受光照。pname表示设置的特定材料属性。param提供了具体的属性值。

我们设置桌面和四条桌腿的材料如下:
void Draw_Table() // This function draws a triangle with RGB colors
{
    //定义变量
    GLfloat specular[] = { 0.6f,0.6f,0.6f,1.0f };
    GLfloat color1[] = { 0.85f,0.65f,0.2f,1.0f };//金黄色
    GLfloat color2[] = { 1.0f,0.0f,0.0f };
    GLfloat color3[] = { 0.0f,1.0f,0.0f };
    GLfloat color4[] = { 1.0f,1.0f,0.0f };
    GLfloat color5[] = { 0.0f,1.0f,1.0f };
    GLfloat color6[] = { 0.0f,0.0f,1.0f };
    //茶壶
    glPushMatrix();
    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);//设置镜面颜色
    glMateriali(GL_FRONT, GL_SHININESS, 50);//设置镜面指数
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);//材料的环境和散射颜色
    glTranslatef(0, 0, 4+1);
    glRotatef(90, 1, 0, 0);
    glutSolidTeapot(1);
    glPopMatrix();
    //桌面
    glPushMatrix();
    glMaterialfv(GL_FRONT, GL_SPECULAR, color2);//设置镜面颜色
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);//材料的环境和散射颜色
    glTranslatef(0, 0, 3.5);
    glScalef(5, 4, 1);
    glutSolidCube(1.0);
    glPopMatrix();
    //四条腿
    glPushMatrix();
    glMaterialfv(GL_FRONT, GL_SPECULAR, color3);//设置镜面颜色
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color3);//材料的环境和散射颜色
    glTranslatef(1.5, 1, 1.5);
    Draw_Leg();
    glPopMatrix(); 
    glPushMatrix();
    glMaterialfv(GL_FRONT, GL_SPECULAR, color4);//设置镜面颜色
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color4);//材料的环境和散射颜色
    glTranslatef(-1.5, 1, 1.5);
    Draw_Leg();
    glPopMatrix(); 
    glPushMatrix();
    glMaterialfv(GL_FRONT, GL_SPECULAR, color5);//设置镜面颜色
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color5);//材料的环境和散射颜色
    glTranslatef(1.5, -1, 1.5);
    Draw_Leg();
    glPopMatrix();
    glPushMatrix();
    glMaterialfv(GL_FRONT, GL_SPECULAR, color6);//设置镜面颜色
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color6);//材料的环境和散射颜色
    glTranslatef(-1.5, -1, 1.5);
    Draw_Leg();
    glPopMatrix();
}

2.光源位置及颜色设置

首先使用定义全局变量来控制光源的颜色和位置:
bool light_flag = false;//环境光颜色
GLfloat color[] = { 1.0, 1.0, 1.0, 1.0 }; // 定义颜色  
//环境光位置
GLfloat light_x = 0.0f;
GLfloat light_y = 0.0f;
GLfloat light_z = 0.0f;

在redraw函数中对光源进行设置:
GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };//定义环境光颜色:白色
GLfloat light_pos[] = { 5.0 + light_x,5.0 + light_y,5.0 + light_z,1 };
//是否改变光照颜色
    if (light_flag)
        color[1] = color[3] = 0.0f;
    else
        color[1] = color[3] = 1.0f;
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);//0号光源的位置
    glLightfv(GL_LIGHT0, GL_SMOOTH, white);//设置环境光颜色
    glLightfv(GL_LIGHT0, GL_DIFFUSE, white);                     //设置漫射光成分 
    glLightfv(GL_LIGHT0, GL_AMBIENT, color);   //设置第0号光源多次反射后的光照颜色(环境光颜色)
    glEnable(GL_LIGHT0);//开启0号光源

3.聚光灯

可以对位置性光源的形状加以限制,使它的发射范围限于一个椎体之内,就像一个聚光灯一样。为了创建聚光灯,需要确定光锥的发射范围。为了指定光锥轴和光锥边缘之间的角度,可以使用GL_SPOT_CUTOFF参数。光锥的最大角度是这个值的两倍。

定义全局变量控制聚光灯方向和照射角度:
//聚光灯
GLfloat spot_x = 0.0f;
GLfloat spot_y = 0.0f;
GLfloat spot_z = 0.0f;
GLfloat Angle = 5.0f;//聚光灯角度

在redraw中设置聚光灯位置、颜色以及角度等等:
glLightfv(GL_LIGHT1, GL_AMBIENT, color);    //设置环境光成分
    glLightfv(GL_LIGHT1, GL_SPECULAR, white);                 //设置镜面光成分
    glLightfv(GL_LIGHT1, GL_DIFFUSE, white);                     //设置漫射光成分 
    glLightfv(GL_LIGHT1, GL_POSITION, spot_pos);
    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, Angle);            //裁减角度
    glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_angle);          //光源方向
    glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.);                    //聚集度
    glEnable(GL_LIGHT1);//开启1号光源

实验结果与分析:

main.cpp
// glutEx1.cpp : 定义控制台应用程序的入口点。
//
#include <stdlib.h>
#include "glut.h"
float fTranslate;
float fRotate;
float fScale     = 1.0f;	// set inital scale value to 1.0f
bool bPersp = false;
bool bAnim = false;
bool bWire = false;
bool light_flag = false;//环境光颜色
GLfloat color[] = { 1.0, 1.0, 1.0, 1.0 }; // 定义颜色   
int wHeight = 0;
int wWidth = 0;
//环境光
GLfloat light_x = 0.0f;
GLfloat light_y = 0.0f;
GLfloat light_z = 0.0f;
//聚光灯
GLfloat spot_x = 0.0f;
GLfloat spot_y = 0.0f;
GLfloat spot_z = 0.0f;
GLfloat Angle = 5.0f;//聚光灯角度
void Draw_Leg();
void Draw_Table() // This function draws a triangle with RGB colors
{
	//定义变量
	GLfloat specular[] = { 0.6f,0.6f,0.6f,1.0f };
	GLfloat color1[] = { 0.85f,0.65f,0.2f,1.0f };//金黄色
	GLfloat color2[] = { 1.0f,0.0f,0.0f };
	GLfloat color3[] = { 0.0f,1.0f,0.0f };
	GLfloat color4[] = { 1.0f,1.0f,0.0f };
	GLfloat color5[] = { 0.0f,1.0f,1.0f };
	GLfloat color6[] = { 0.0f,0.0f,1.0f };
	//茶壶
	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, specular);//设置镜面颜色
	glMateriali(GL_FRONT, GL_SHININESS, 50);//设置镜面指数
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);//材料的环境和散射颜色
	glTranslatef(0, 0, 4+1);
	glRotatef(90, 1, 0, 0);
	glutSolidTeapot(1);
	glPopMatrix();
	//桌面
	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, color2);//设置镜面颜色
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);//材料的环境和散射颜色
	glTranslatef(0, 0, 3.5);
	glScalef(5, 4, 1);
	glutSolidCube(1.0);
	glPopMatrix();
	//四条腿
	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, color3);//设置镜面颜色
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color3);//材料的环境和散射颜色
	glTranslatef(1.5, 1, 1.5);
	Draw_Leg();
	glPopMatrix();
	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, color4);//设置镜面颜色
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color4);//材料的环境和散射颜色
	glTranslatef(-1.5, 1, 1.5);
	Draw_Leg();
	glPopMatrix();
	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, color5);//设置镜面颜色
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color5);//材料的环境和散射颜色
	glTranslatef(1.5, -1, 1.5);
	Draw_Leg();
	glPopMatrix();
	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, color6);//设置镜面颜色
	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color6);//材料的环境和散射颜色
	glTranslatef(-1.5, -1, 1.5);
	Draw_Leg();
	glPopMatrix();
}
void Draw_Leg()
{
	glScalef(1, 1, 3);
	glutSolidCube(1.0);
}
void updateView(int width, int height)
{
	glViewport(0,0,width,height);						// Reset The Current Viewport
	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix
	float whRatio = (GLfloat)width/(GLfloat)height;
	if (bPersp) {
		gluPerspective(45.0f, whRatio,0.1f,100.0f);
		//glFrustum(-3, 3, -3, 3, 3,100);
	} else {
		glOrtho(-3 ,3, -3, 3,-100,100);
	}
	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
}
void reshape(int width, int height)
{
	if (height==0)										// Prevent A Divide By Zero By
	{
		height=1;										// Making Height Equal One
	}
	wHeight = height;
	wWidth = width;
	updateView(wHeight, wWidth);
}
void idle()
{
	glutPostRedisplay();
}
float eye[] = {0, 0, 8};
float center[] = {0, 0, 0};
void key(unsigned char k, int x, int y)
{
	switch(k)
	{
	case 27://ESC
	case 'q': {exit(0); break; }//quit
	case 'p': {bPersp = !bPersp; break; }//显示模式
	case ' ': {bAnim = !bAnim; break;}//旋转
	case 'o': {bWire = !bWire; break;}//线框
	case 'd': {//右
		eye[0] -= 0.2f;
		center[0] -= 0.2f;
		break;
			  }
	case 'a': {//左
		eye[0] += 0.2f;
		center[0] += 0.2f;
		break;
			  }
	case 'w': {//上
		eye[1] -= 0.2f;
		center[1] -= 0.2f;
		break;
			  }
	case 's': {//下
		eye[1] += 0.2f;
		center[1] += 0.2f;
		break;
			  }
	case 'z': {//前
		eye[2] -= 0.2f;
		center[2] -= 0.2f;
		break;
			  }
	case 'c': {//后
		eye[2] += 0.2f;
		center[2] += 0.2f;
		break;
			  }
	case 'j': {//环境光左
		light_x += 0.2f;
		break;
	}
	case 'l': {//环境光右
		light_x -= 0.2f;
		break;
	}
	case 'i': {//环境光上
		light_y += 0.2f;
		break;
	}
	case 'k': {//环境光下
		light_y -= 0.2f;
		break;
	}
	case 'n': {//环境光前
		light_z += 0.2f;
		break;
	}
	case ',': {//环境光后
		light_z -= 0.2f;
		break;
	}
	case 'u': {//环境光颜色切换
		light_flag = !light_flag;
		break;
	}
	case 'f': {//聚光灯左移
		spot_x -= 0.05f;
		break;
	}
	case 'h': {
		spot_x += 0.05f;
		break;
	}
	case 't': {
		spot_y -= 0.05f;
		break;
	}
	case 'g': {
		spot_y += 0.05f;
		break;
	}
	case 'v': {//聚光灯前移
		spot_z += 0.05f;
		break;
	}
	case 'b': {//聚光灯后移
		spot_z -= 0.05f;
		break;
	}
	case 'r': {//角度变大
		if (Angle <= 89.0f)
			Angle += 0.2f;
		break;
	}
	case 'y': {
		if (Angle >= 1.0f)
			Angle -= 0.2f;
		break;
	}
}
	updateView(wHeight, wWidth);
}
void redraw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();									// Reset The Current Modelview Matrix
	gluLookAt(eye[0], eye[1], eye[2],
		center[0], center[1], center[2],
		0, 1, 0);				// 场景(0,0,0)的视点中心 (0,5,50),Y轴向上
	if (bWire) {
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	else {
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
	glEnable(GL_DEPTH_TEST);//开启深度测试
	glEnable(GL_LIGHTING);//开启光照模式
	GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };//定义环境光颜色:白色
	GLfloat light_pos[] = { 5.0 + light_x,5.0 + light_y,5.0 + light_z,1 };
	//定义聚光灯位置
	GLfloat spot_pos[] = { 0.0f,5.0f,0.0f,1.0f };
	//定义聚光灯照射方向
	GLfloat spot_angle[] = { 0.0f + spot_x,-1.0f + spot_y,0.0f + spot_z };
	//是否改变光照颜色
	if (light_flag)
		color[1] = color[3] = 0.0f;
	else
		color[1] = color[3] = 1.0f;
	glLightfv(GL_LIGHT0, GL_POSITION, light_pos);//0号光源的位置
	glLightfv(GL_LIGHT0, GL_SMOOTH, white);//设置环境光颜色
	glLightfv(GL_LIGHT0, GL_DIFFUSE, white);                     //设置漫射光成分  
	glLightfv(GL_LIGHT0, GL_AMBIENT, color);   //设置第0号光源多次反射后的光照颜色(环境光颜色)
	glEnable(GL_LIGHT0);//开启0号光源
	glLightfv(GL_LIGHT1, GL_AMBIENT, color);    //设置环境光成分
	glLightfv(GL_LIGHT1, GL_SPECULAR, white);                 //设置镜面光成分
	glLightfv(GL_LIGHT1, GL_DIFFUSE, white);                     //设置漫射光成分
	glLightfv(GL_LIGHT1, GL_POSITION, spot_pos);
	glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, Angle);            //裁减角度
	glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_angle);          //光源方向
	glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.);                    //聚集度
	glEnable(GL_LIGHT1);//开启1号光源
	//	glTranslatef(0.0f, 0.0f,-6.0f);			// Place the triangle at Center
	glRotatef(fRotate, 0, 1.0f, 0);			// Rotate around Y axis
	glRotatef(-90, 1, 0, 0);
	glScalef(0.2, 0.2, 0.2);
	Draw_Table();						// Draw triangle
	if (bAnim) fRotate    += 0.5f;
	glutSwapBuffers();
}
int main (int argc,  char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
	glutInitWindowSize(480,480);
	int windowHandle = glutCreateWindow("Simple GLUT App");
	glutDisplayFunc(redraw);
	glutReshapeFunc(reshape);	
	glutKeyboardFunc(key);
	glutIdleFunc(idle);
	glutMainLoop();
	return 0;
}