OpenGL光照

基本光照模型

OpenGL中有四种光照模型

  • 放射光(自发光)     e m i s s i v e emissive emissive
  • 环境光     a m b i e n t ambient ambient
  • 漫反射光      d i f f u s e diffuse diffuse
  • 镜面反射光    s p e c u l a r specular specular

基本光照模型
   S u r f a c e C o l o r = e m i s s i v e + a m b i e n t + d i f f u s e + s p e c u l a r SurfaceColor = emissive + ambient + diffuse + specular SurfaceColor=emissive+ambient+diffuse+specular
表面颜色 = 放射光+环境光+漫反射光+镜面反射光

下面我将以一个标准球体来演示各个光照的效果
在这里插入图片描述

1.放射光

e m i s s i v e = k e emissive = k_e emissive=ke

  • k e k_e ke材质的放射系数(颜色)
    在这里插入图片描述
    上图为 k e = ( 0 , 0.2 , 0.1 , 1 ) k_e = (0,0.2,0.1,1) ke=(0,0.2,0.1,1)
	GLfloat green[] = { 0.0f,0.2f,0.1f,1.0f };
	glMaterialfv(GL_FRONT, GL_EMISSION, green);

2.环境光

- a m b i e n t = k a ∗ G l o b a l A m b i e n t ambient = k_a *GlobalAmbient ambient=kaGlobalAmbient

  • k a k_a ka材质的环境光反射系数
  • G l o b a l A m b i e n t GlobalAmbient GlobalAmbient 全局环境光颜色
    在这里插入图片描述
    k a = ( 0.5 , 0.5 , 0.5 , 1 ) k_a = (0.5,0.5,0.5,1) ka=(0.5,0.5,0.5,1)
    G l o b a l A m b i e n t = ( 0.3 , 0.3 , 0.3 , 1.0 ) GlobalAmbient = (0.3,0.3,0.3,1.0) GlobalAmbient=(0.3,0.3,0.3,1.0)
	GLfloat gray[] = {0.5f, 0.5f, 0.5f, 1.0f};
	glMaterialfv(GL_FRONT, GL_AMBIENT, gray);

3.漫反射光

d i f f u s e = k d ∗ L i g h t C o l o r ∗ m a x ( N ⋅ L , 0 ) diffuse = k_d*LightColor*max(N \cdot L,0 ) diffuse=kdLightColormax(NL,0)

  • k a k_a ka 材质漫反射系数
  • L i g h t C o l o r LightColor LightColor 漫反射光照颜色
  • N N N 规范化的表面法向量
  • L L L 规范化的指向光源的向量
    在这里插入图片描述
    k d = ( 0.7 , 0.6 , 0.1 , 1 ) k_d = (0.7,0.6,0.1,1) kd=(0.7,0.6,0.1,1)
    L i g h t C o l o r = ( 0.7 , 0.7 , 0.7 , 1 ) LightColor = (0.7,0.7,0.7,1) LightColor=(0.7,0.7,0.7,1)
	GLfloat yellow[] = { 0.7f,0.6f,0.1f,1.0f };
	glMaterialfv(GL_FRONT, GL_DIFFUSE , yellow);

4.镜面反射光

s p e c u l a r = k s ∗ L i g h t C o l o r ∗ f a c i n g ∗ ( m a x ( N ⋅ H , 0 ) ) s h i n i n e s s specular = k_s*LightColor*facing*(max(N \cdot H,0))^{shininess} specular=ksLightColorfacing(max(NH,0))shininess

  • k s k_s ks材质的镜面反射系数
  • L i g h t C o l o r LightColor LightColor 镜面反射光颜色
  • N N N 规范化表面法向量
  • V V V规范化指向视点向量
  • H H H规范化 N N N V V V的中间向量
  • f a c i n g facing facing 为1若 N ⋅ L > 0 N \cdot L >0 NL>0 ,否则为0
  • s h i n i n e s s shininess shininess 材质的光泽系数
    在这里插入图片描述
    k s = ( 1 , 1 , 1 , 1 ) k_s = (1,1,1,1) ks=(1,1,1,1)
    L i g h t C o l o r = ( 0.5 , 0.5 , 0.5 , 1 ) LightColor = (0.5,0.5,0.5,1) LightColor=(0.5,0.5,0.5,1)
    s h i n i n e s s = 10 shininess = 10 shininess=10
	GLfloat white[] = { 1.0f,1.0f,1.0f,1.0f };
	glMaterialfv(GL_FRONT, GL_SPECULAR, white);
	glMaterialf(GL_FRONT, GL_SHININESS, 10.0f);

光源类型

OpenGL中光源分为三类

  • 平行光
  • 点光源
  • 聚光灯

1.平行光

在这里插入图片描述
L i g h t P o s i t i o n = ( 1 , 0 , 0 , 1 ) LightPosition = (1,0,0,1) LightPosition=(1,0,0,1)
注意第四项为1,代表一个向量(1,0,0)的平行光源

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	GLfloat ambient[] = { .3f,.3f,.3f,1.f };
	GLfloat diffuse[] = { .7f,.7f,.7f,1.f };
	GLfloat specular[] = { .5f,.5f,.5f,1.f };

	glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, specular);

	GLfloat position[] = { 1.0f,0.0f,0.f,1.f };
	glLightfv(GL_LIGHT0, GL_POSITION, position);

其中衰减系数
a t t e n u a t i o n = 1 A 0 + A 1 ∗ D + A 2 ∗ D 2 attenuation = \frac{1}{A_0 + A_1*D + A_2*D^2} attenuation=A0+A1D+A2D21
A 0 A_0 A0 为常量系数
A 1 A_1 A1 为线性系数
A 2 A_2 A2 为平方系数
D D D 为光源到目标距离

	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1);
	glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0);
	glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0);

2.点光源

在这里插入图片描述
L i g h t P o s i t i o n = ( 1 , 0 , 0 , 0 ) LightPosition = (1,0,0,0) LightPosition=(1,0,0,0)
注意第四项为0,代表一个位置在(1,0,0)处的点光源

3.聚光灯

在这里插入图片描述

代码

球体绘制


void sphere_entry(int du, int dv){

	float gu = 3.1415926535 / du , gv = 2.0*3.1415926535 / (dv-1);

	float x, y, z ,r ;
	float p1[3], p2[3],p3[3],p4[3],v1[3],v2[3],v3[3],a;

	glPushMatrix();
#define MAKE_R(z2) sqrt(1.0 - (z2))
#define MAKE_Z(z_step) cos((z_step) *gu)
#define MAKE_Y(x_step,r) (r)*sin((x_step)* gv)
#define MAKE_X(x_step,r) (r)*cos((x_step)* gv)
	// 球体
	glBegin(GL_QUADS);
	for (int z_step = 0 ; z_step < du; ++z_step) {
		for (int x_step = 0; x_step < dv; ++x_step) {

			z = MAKE_Z(z_step);
			r = MAKE_R(z*z);
			x = MAKE_X(x_step, r);
			y = MAKE_Y(x_step, r);
			p1[0] = x;
			p1[1] = y;
			p1[2] = z;

			z = MAKE_Z(z_step+1);
			r = MAKE_R(z*z);
			x = MAKE_X(x_step, r);
			y = MAKE_Y(x_step, r);
			p2[0] = x;
			p2[1] = y;
			p2[2] = z;

			z = MAKE_Z(z_step + 1);
			r = MAKE_R(z*z);
			x = MAKE_X(x_step + 1,r);
			y = MAKE_Y(x_step+1, r);
			p3[0] = x;
			p3[1] = y;
			p3[2] = z;

			z = MAKE_Z(z_step);
			r = MAKE_R(z*z);
			x = MAKE_X(x_step + 1,r);
			y = MAKE_Y(x_step + 1, r);
			p4[0] = x;
			p4[1] = y;
			p4[2] = z;

			v1[0] = p2[0] - p1[0];
			v1[1] = p2[1] - p1[1];
			v1[2] = p2[2] - p1[2];
			 
			// 极点矫正
			if (z_step == du - 1) {
				v2[0] = p4[0] - p2[0];
				v2[1] = p4[1] - p2[1];
				v2[2] = p4[2] - p2[2];
			}
			else {
				v2[0] = p3[0] - p2[0];
				v2[1] = p3[1] - p2[1];
				v2[2] = p3[2] - p2[2];
			}

			// 向量积
			v3[0] = (v1[1] * v2[2]) - (v2[1] * v1[2]);
			v3[1] = (v1[2] * v2[0]) - (v2[2] * v1[0]);
			v3[2] = (v1[0] * v2[1]) - (v2[0] * v1[1]);

			// 单位化
			a = 1.0/ sqrt(v3[0] * v3[0] + v3[1] * v3[1] + v3[2] * v3[2]);

			glNormal3f(v3[0] * a, v3[1] * a, v3[2] * a);

			glVertex3f(p1[0], p1[1], p1[2]);
			glVertex3f(p2[0], p2[1], p2[2]);
			glVertex3f(p3[0], p3[1], p3[2]);
			glVertex3f(p4[0], p4[1], p4[2]);

		}

	}

	glEnd();
#undef MAKE_Y
#undef MAKE_Z
#undef MAKE_X
#undef MAKE_R
	glPopMatrix();
}

渲染



float angle;

void changed_size(int w, int h) {
	// 修改视窗size
	glViewport(0, 0, w, h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(45.0f, double(w) / double(h), 1.0f, 1000.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	gluLookAt(0.0f, 0.0f, 5.0f,
		0.0f, 0.0f, 0.0f,
		0.0f, 1.0f, 0.0f);
}

// 初始化渲染环境
void init_render_context() {

	// 蓝色背景
	glClearColor(0.f, 0.f, .3f, 1.f);

	angle = 0.0f;
	
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	glEnable(GL_CULL_FACE);

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	GLfloat ambient[] = { .3f,.3f,.3f,1.f };
	GLfloat diffuse[] = { .7f,.7f,.7f,1.f };
	GLfloat specular[] = { .5f,.5f,.5f,1.f };

	glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, specular);

	GLfloat position[] = { 2.0f,2.0f,2.f,1.f };
	glLightfv(GL_LIGHT0, GL_POSITION, position);

	//glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1);
	//glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0);
	//glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0);

	const char* renderer = (const char*)glGetString(GL_RENDERER);
	const char* version = (const char*)glGetString(GL_VERSION);
	
	char title[0x256];
	memset(title, 0, 0x256);

	strcpy_s(title, "OpenGL");
	if (renderer != nullptr) {
		strcat_s(title, " | R - ");
		strcat_s(title, renderer);
	}
	if (version != nullptr) {
		strcat_s(title, " | V - ");
		strcat_s(title, version);
		strcat_s(title, " |");
	}

	glutSetWindowTitle(title);
}

// 渲染
void render(void) {

	// 清除颜色缓冲、深度缓冲、模板缓冲
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -4.0f);
	glRotatef(angle, 0.0f, 1.0f, 1.0f);

	GLfloat green[] = { 0.0f,0.2f,0.1f,1.0f };
	GLfloat yellow[] = { 0.7f,0.6f,0.1f,1.0f };
	GLfloat white[] = { 1.0f,1.0f,1.0f,1.0f };
	GLfloat gray[] = {0.2f, 0.2f, 0.2f, 1.0f};

	// 自发光
	//glMaterialfv(GL_FRONT, GL_EMISSION, green);
	// 环境光
	glMaterialfv(GL_FRONT, GL_AMBIENT, gray);
	// 漫反射光
	glMaterialfv(GL_FRONT, GL_DIFFUSE , yellow);
	// 镜面反射光
	glMaterialfv(GL_FRONT, GL_SPECULAR, white);
	glMaterialf(GL_FRONT, GL_SHININESS, 10.0f);

	sphere_entry(72,144);

	angle += .02f;
	angle = angle > 360.0f ? 0.0f : angle;

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

int main(int argc, char**argv) {

	gltSetWorkingDirectory(*argv);

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
	glutInitWindowSize(800, 600);
	glutCreateWindow("OpenGL");
	glutReshapeFunc(changed_size);
	glutDisplayFunc(render);
	glutIdleFunc(render);

	GLenum err = glewInit();
	if (GLEW_OK != err) {
		std::cerr << "GLEW Error : " << glewGetErrorString(err) << std::endl;
		return 1;
	}

	init_render_context();

	glutMainLoop();

	return 0;
}
  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值