基本光照模型
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=ka∗GlobalAmbient
- 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=kd∗LightColor∗max(N⋅L,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=ks∗LightColor∗facing∗(max(N⋅H,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 N⋅L>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+A1∗D+A2∗D21
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;
}