OpenGL中有四种光照模型
基本光照模型
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
表面颜色 = 放射光+环境光+漫反射光+镜面反射光
e m i s s i v e = k e emissive = k_e emissive=ke
GLfloat green[] = { 0.0f,0.2f,0.1f,1.0f };
glMaterialfv(GL_FRONT, GL_EMISSION, green);
- 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
GLfloat gray[] = {0.5f, 0.5f, 0.5f, 1.0f};
glMaterialfv(GL_FRONT, GL_AMBIENT, gray);
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)
GLfloat yellow[] = { 0.7f,0.6f,0.1f,1.0f };
glMaterialfv(GL_FRONT, GL_DIFFUSE , yellow);
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
GLfloat white[] = { 1.0f,1.0f,1.0f,1.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, white);
glMaterialf(GL_FRONT, GL_SHININESS, 10.0f);
OpenGL中光源分为三类
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);
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)处的点光源
球体绘制
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;
}