[OpenGL] 茶壶与光照

OpenGL可以设置至少8种光源,它们的标号为GL_LIGHT0,GL_LIGHT1,GL_LIGHT2……。在这里我们使用了两种光源,一种是环境光,另一种是聚光灯。

在设置光照时,我们需要考虑这样三种光:环境反射光、镜面反射光、漫反射光。在Phong光照模型中,就是通过这三种分量的取值来模拟真实光照的。其中,环境反射光是光源多次反射后的光,可以理解为背景光,镜面反射和漫反射反映了物体表面的粗糙/光滑程度,两者的和是一定的。

在OpenGL中,如果我们想要使用光源,需要输入以下语句开启光照模式:

glEnable(GL_LIGHTING); //开启光照模式

对于一个光源,我们首先需要确定它的位置,这个光源可以是点光源,也可以是平行光源,我们写如下函数,如果是点光源,第四个参数为1,前三个参数代表光源位置;如果是平行光源,第四个参数是0,前三个参数表示方向。其中light_pos是一个数组。

在本次试验中,我们采用的是点光源。

glLightfv(GL_LIGHT0,GL_POSITION,
light_pos);//设置第0号光源的光照位置

同时,设置漫反射、镜面反射、环境反射的颜色参数:

glLightfv(GL_LIGHT0,GL_SPECULAR,
color);//设置镜面反射光照

glLightfv(GL_LIGHT0,GL_DIFFUSE,
color); //设置漫射光成分

glLightfv(GL_LIGHT0,GL_AMBIENT,
color);  //设置第0号光源多次反射后的光照颜色(环境光颜色)

在本次实验中,我们把环境光设为指定的颜色(在这里,我们选择了白色和绿色),而镜面反射光和漫反射光都设置为白色。

使用如下函数,开启灯光:

glEnable(GL_LIGHT0);//开启第0号光源

 

      聚光灯我们另外使用GL_LIGHT1光源。除了基本的三种光,还包含了其他属性,分别是裁剪角度、光源方向和聚集度:

glLightf(GL_LIGHT1,GL_SPOT_CUTOFF,
spotangle);            //裁减角度

glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,
lightDir);         //光源方向

glLightf(GL_LIGHT1,GL_SPOT_EXPONENT,
2.);                   //聚集度

对于聚光灯,我们设置和环境光一样。

在设置完了基本的光照后,我们来关注物体的材质,这里的材质并不是指我们理解意义上的材质,而是物体在不同光照下反射的颜色。我们知道,物体的显示效果和光照有着很大的关联,比如在黑暗中,我们看到的物体就是黑色的。我们所看到的物体颜色是由灯光以及物体反射颜色共同决定的。

glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,
color);

glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,
color);

glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,
color);

其中,第一个参数代表了操作对象的正面还是反面,参数包括GL_FRONT、GL_BACK、GL_FRONT_AND_BACK;第二个参数代表了材质的颜色是在什么光照下表现的;第三个参数是光照下材质的颜色。

对于茶壶,我们设置镜面指数为50,镜面反射为0.6f, 0.6f, 0.6f,漫反射为0.85f, 0.65f, 0.2f。

对于桌面和腿,我们把镜面反射和漫反射的颜色设为相同的指定颜色。

实验数据记录和处理 

(数据设置仅供参考)

目前桌子腿的效果不太真实,但是实验要求中也只要求了一种颜色,所以没有做过多优化。如果有好的数据设置,也可以分享一下。


环境反射


漫反射


镜面反射


白色环境光/聚光灯


(1,1,1)


(1,1,1)


(1,1,1)


绿色环境光/聚光灯


(0,1,0)


(1,1,1)


(1,1,1)


茶壶


/


(0.6, 0.6, 0.6)


(0.85, 0.65, 0.2)


桌面


/


(1,0,0)


(1,0,0)


桌脚1


/


(0,1,0)


(0,1,0)


桌脚2


/


(1,1,0)


(1,1,0)


桌脚3


/


(0,1,1)


(0,1,1)


桌脚4


(0,0,1)


(0,0,1)

// glutEx1.cpp : 定义控制台应用程序的入口点。
//

#include <stdlib.h>
#include "glut.h"
#include <stdio.h>

float fTranslate;
float fRotate;
float fScale     = 1.0f;
float color_b = 1.0f;

bool bPersp = false;
bool bAnim = false;
bool bWire = false;
bool isWhite = true;

int wHeight = 0;
int wWidth = 0;

GLfloat color[] = { 1.0, 1.0, 1.0, 1.0 }; // 定义颜色  

float eye[] = { 0, 0, 8 };
float center[] = { 0, 0, 0 };

GLfloat spotangle = 5.0f; //角度

//环境光位置
GLfloat light_x = 0.0f;
GLfloat light_y = 0.0f;
GLfloat light_z = 0.0f;

//聚光灯方向
GLfloat dir_x = 0.0f;
GLfloat dir_y = 0.0f;
GLfloat dir_z = 0.0f;

void Draw_Leg();

void Draw_Triangle() // This function draws a triangle with RGB colors
{

	GLfloat mat_specular[] = { 0.6f, 0.6f, 0.6f, 1.0f };
	GLfloat mat_diffuse0[] = { 0.85f, 0.65f, 0.2f, 1.0f };
	GLfloat mat_diffuse1[] = { 1.0f, 0.0f, 0.0f };
	GLfloat mat_diffuse2[] = { 0.0f, 1.0f, 0.0f };
	GLfloat mat_diffuse3[] = { 1.0f, 1.0f, 0.0f };
	GLfloat mat_diffuse4[] = { 0.0f, 1.0f, 1.0f };
 	GLfloat mat_diffuse5[] = { 0.0f, 0.0f, 1.0f };

	//画茶壶
	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);// 设置多边形正面的镜面反射属性
	glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 50);// 指定镜面指数
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse0); //设置多边形正面漫反射属性
	glTranslatef(0, 0, 4+1);
	glRotatef(90, 1, 0, 0);
	glutSolidTeapot(1);
	glPopMatrix();

	//画桌面 

	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_diffuse1);// 设置多边形正面的镜面反射属性
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse1);//设置多边形正面漫反射属性
	glTranslatef(0, 0, 3.5);
	glScalef(5, 4, 1);
	glutSolidCube(1.0);
	glPopMatrix();

	//画四条腿  

	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_diffuse2);// 设置多边形正面的镜面反射属性
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse2);//设置多边形正面漫反射属性
	glTranslatef(1.5, 1, 1.5);
	Draw_Leg();
	glPopMatrix();

	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_diffuse3);// 设置多边形正面的镜面反射属性
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse3);//设置多边形正面漫反射属性
	glTranslatef(-1.5, 1, 1.5);
	Draw_Leg();
	glPopMatrix();

	glPushMatrix();
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_diffuse4);// 设置多边形正面的镜面反射属性
	glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse4);//设置多边形正面漫反射属性
	glTranslatef(1.5, -1, 1.5);
	Draw_Leg();
	glPopMatrix();

	glPushMatrix();
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_diffuse5);// 设置多边形正面的镜面反射属性
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse5);//设置多边形正面漫反射属性
	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);//设置视窗大小

	glMatrixMode(GL_PROJECTION);//设置矩阵模式为投影
	glLoadIdentity();	//初始化矩阵为单位矩阵    

	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);	 //设置矩阵模式为模型
}

void reshape(int width, int height)
{
	if (height==0)		//如果高度为0
	{
		height=1;	//让高度为1(避免出现分母为0的现象)
	}

	wHeight = height;
	wWidth = width;

	updateView(wHeight, wWidth); //更新视角
}

void idle()
{
	glutPostRedisplay(); //调用当前绘制函数
}

void key(unsigned char k, int x, int y)
{
	switch (k)
	{
	case 27:
	case 'q': {exit(0); break; }
	case 'p': {bPersp = !bPersp; break; }

	case ' ': {bAnim = !bAnim; break; }
	case 'o': {bWire = !bWire; break; }

	case 'a': { //整体左移
		eye[0] += 0.2f;
		center[0] += 0.2f;
		break;
	}
	case 'd': {//整体右移
		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 = light_x - 0.2f;
		break;
	}
	case 'l': {//环境光右移
		light_x = light_x + 0.2f;
		break;
	}
	case 'i': {//环境光上移
		light_y = light_y + 0.2f;
		break;
	}
	case 'k': {//环境光下移
		light_y = light_y - 0.2f;
		break;
	}
	case 'n': {//环境光前移
		light_z = light_z + 0.2f;
		break;
	}
	case 'm': {//环境光后移
		light_z = light_z - 0.2f;
		break;
	}
	case 'r': {//环境光颜色切换
		isWhite = !isWhite;
		break;
	}
	case 'f': {//聚光灯左移
		dir_x = dir_x - 0.05f;
		break;
	}
	case 'h': {//聚光灯右移
		dir_x = dir_x + 0.05f;
		break;
	}
	case 't':{//聚光灯上移
		dir_y = dir_y - 0.05f;
		break;
	}
	case 'g':{//聚光灯下移
		dir_y = dir_y + 0.05f;
		break;
	}
	case 'v': {//聚光灯后移
		dir_z = dir_z - 0.05f;
		break;
	}
	case 'b': {//聚光灯前移
		dir_z = dir_z + 0.05f;
		break;
	}
	case 'x': { //聚光灯角度变大
		if (spotangle <= 89.0f) {
			spotangle = spotangle + 0.2f;
		}
		break;
	}
	case 'y': { //聚光灯角度变小
		if (spotangle >= 1.0f) {
			spotangle = spotangle - 0.2f;
		}
		break;
	}
	}

	updateView(wHeight, wWidth);
}

void redraw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //清除颜色缓存和深度缓存
	glLoadIdentity(); //初始化矩阵为单位矩阵  

	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 specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat light_pos[] = {5.0 + light_x ,5.0 + light_y,5.0 + light_z,1}; //定义环境光位置
	GLfloat light_pos1[] = { 0.0f, 5.0f, 0.0f, 1.0f }; //定义聚光灯位置
	GLfloat lightDir[] = { 0.0f + dir_x ,-1.0f + dir_y ,0.0f + dir_z }; //角度
	GLfloat white[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //定义白色

	if (isWhite) {
		color[0] = 1.0f, color[1] = 1.0f, color[2] = 1.0f, color[3] = 1.0f;
	}
	else {
		color[0] = 0.0f, color[1] = 1.0f, color[2] = 0.0f, color[3] = 1.0f;
	}

	glLightfv(GL_LIGHT0, GL_POSITION, light_pos); //设置第0号光源的光照位置
	glLightfv(GL_LIGHT0, GL_SPECULAR, 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, light_pos1);
	glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, spotangle);             //裁减角度
	glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, lightDir);          //光源方向
	glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.);                    //聚集度

	glEnable(GL_LIGHT1);

	glRotatef(fRotate, 0, 1.0f, 0);	//旋转
	glRotatef(-90, 1, 0, 0); //旋转
	glScalef(0.2, 0.2, 0.2);  //缩放
	Draw_Triangle();	//绘制场景

	if (bAnim) fRotate    += 0.5f; //旋转因子改变

	glutSwapBuffers(); //交换缓冲区
}

int main (int argc,  char *argv[])
{
	glutInit(&argc, argv);//对glut的初始化
	glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
	//初始化显示模式:RGB颜色模型,深度测试,双缓冲
	glutInitWindowSize(480,480);//设置窗口大小
	int windowHandle = glutCreateWindow("Simple GLUT App");//设置窗口标题 

	glutDisplayFunc(redraw); //注册绘制回调函数
	glutReshapeFunc(reshape);	//注册重绘回调函数
	glutKeyboardFunc(key); //注册按键回调函数
	glutIdleFunc(idle);//注册全局回调函数:空闲时调用 

	glutMainLoop();  // glut事件处理循环
	return 0;
}
时间: 2024-11-09 17:19:04

[OpenGL] 茶壶与光照的相关文章

OpenGL学习(五) 光照与材质

OpenGL中的光照     环境光:在环境中进行了充分的散射,无法分辨其方向的光. 散射光:来自某个方向. 镜面光:来自一个特定的方向,并且倾向于从表面某个特定的方向反射. 除了以上三种光外,材料可能具有一种发射颜色,它模拟那些源自某个物体的光. 为了实现明暗效果,必须启用光照计算,而且每种光源也必须被启用.对于单个光源,我们可以这样做: glEnable(GL_LIGHTING); glEnable(GL_LIGHT0) 注:一旦光照被启用,glColor*()指定的颜色值将不再使用. 指定

OpenGL中启用光照前的准备——指定法线

我们在使用光源时,除了强度和颜色之外,还需要指定光源的位置和方向,并且这些光源的位置和方向将会极大地影响场景的外观. OpenGL至少支持8种独立的光源.当我们指定一个光源时,便要告诉OpenGL这个光源的位置以及它的照射方向.光源经常向四周照射,但也可以向一个方向照射.无论在哪种情况下,对于我们所绘制的任何物体,来自任何光源的光线(除了纯粹的环境光源之外)都将根据一个角度撞击组成这个物体的多边形的表面.为了计算围绕多边形表面的着色效果,OpenGL必须能够计算光线与多边形表面之间的角度. 设想

OpenGL中的光照与材料

在OpenGL光照模型中,除非一个物体自己会发光,否则它将受到3种不同类型的光的照射,这3种不同类型的光分别是:环境光(ambient).散射光(diffuse)和镜面光(specular).作为现实世界中光照的抽象,这3种类型的光允许我们模拟和控制光照在物体表面上所产生的效果. 环境光(ambient) 环境光并不来自任何特定的方向.由环境光所照射的物体在所有方向的表面都是均匀照亮的.在OpenGL中,这种光照类型实际上模拟了环境中源自所有光源的散光. 散射光(diffuse) OpenGL中

OPENGL学习笔记——光照

1.隐藏表面消除 隐藏表面消除就是消除实心物体被其他物体所遮挡住的部分,最简单的方法就是使用深度缓冲区. 深度缓冲区的原理是把一个距离观察平面(通常是近侧裁剪平面)的深度值与窗口中的每一个像素相关联.首先使用glClear()函数,把所有像素的深度值设置为最大可能的距离,然后在场景中以任意顺序绘制所有的物体. 深度缓冲区测试可能会影响应用程序的性能,隐藏表面消除丢弃了一些信息,而不是将它们用来绘图,因此会稍稍提高性能,但是深度缓冲区会大大影响性能,用"软件"实现的深度缓冲区(用处理器内

OpenGL中设置光照的镜面反射效果

在上一篇笔记中,我们记述了光线的方向与多边形表面的角度计算关系,除此之外,我们还有光源的位置需要指定.我们在ChangeSize函数的内部指定光源的位置: // 指定光源的位置 GLfloat lightPos[] = {-50.0f, 50.0f, 100.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_POSITION, lightPos); 在此,lightPos数组包含了光源的坐标位置.这个数组的最后一个值是1.0,表示指定的坐标是光源的位置:如果这个数组的最后一个

Linux OpenGL 实践篇-6 光照

经典光照模型 经典光照模型通过单独计算光源成分得到综合光照效果,然后添加到物体表面特定点,这些成分包括:环境光.漫反射光.镜面光. 环境光:是指不是来特定方向的光,在经典光照模型中基本是个常量. 漫反射光:是散射在各个方向上均匀的表面特定光源.物体表面通过光照照亮,即使这个表面没有将光源直接反射到你的眼睛中.漫反射与眼睛的方向没有关系,但与光源的方向有关,当表面直接面向光源的时候会表现的亮一些,而倾斜的时候则暗一些,因为在现实中倾斜的表面接受的光要少一些.在经典光照模型中,我们使用表面的法向量来

OpenGL三维与光照

1 #include<windows.h> 2 #include<gl/glut.h> 3 #include<gl/gl.h> 4 #include<gl/glu.h> 5 6 //参数指定正方形的位置和大小 7 GLfloat x1=100.0f; 8 GLfloat y1=150.0f; 9 GLsizei rsize=50; 10 11 //正方形运动变化的步长 12 GLfloat xstep=1.0f; 13 GLfloat ystep=1.0f;

清华版CG 实验7 OpenGL光照

一.实验目的: 了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效果. 二.实验内容: (1)下载并运行Nate Robin教学程序包中的lightmaterial程序,试验不同的光照与材质系数: (2)运行示范代码1,了解光照与材质函数使用. 三.实验原理: 为在场景中增加光照,需要执行以下步骤: (1) 设置一个或多个光源,设定它的有关属性: (2) 选择一种光照模型: (3) 设置物体的材料属性. 具体见教材第8章8.6节用OpenGL生成真实感图形的相关内容.

在OpenGL中给场景添加光照

为了在OpenGL中使用光照计算,我们需要调用glEnable方法,并用GL_LIGHTING作为参数.这个调用告诉OpenGL在确定场景中每个顶点的颜色时使用光照参数和材料属性.当然,如果我们没有指定任何光照参数和材料属性,那么物体仍将会保持为黑暗的无光照状态. // 启用光照 glEnable(GL_LIGHTING); 一.设置环境光 OpenGL提供了一个全局光源,它只发射环境光.这种光源很有用,它可以照射没有被其它光源直接照射的物体的背面,并且如果场景看上去太暗,可以调节这种全局环境光