10.1、真实感图形基本概念
以上内容中,真实感图形绘制的四大步骤前两步在前面的章节已经详细介绍过,这里不再重复,第三步OpenGL将自动完成所有消隐过程,第四步下面几节详述。另外,部分复杂光照模型应用将在后续章节里介绍。
#include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); void myinit(void) { GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); } void CALLBACK display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); auxSolidSphere(1.0); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 500, 500); auxInitWindow ("Simple Lighting"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); }以上程序运行结果是显示一个具有灰色光影的球。其中函数myinit()中包含了关键的设定光源位置、启动光照等几句,而其它程序语言几乎与以前的没有多大区别,但效果却完全不一样。下面几个小节将详细介绍有关函数的用法。
图10-1 带光影的灰色球体 |
void glLight{if}[v](GLenum light , GLenum pname, TYPE param)创建具有某种特性的光源。其中第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7。第二个参数pname指定光源特性,这个参数的辅助信息见表10-1所示。最后一个参数设置相应的光源特性值。
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light_position);其中light_position是一个指针,指向定义的光源位置齐次坐标数组。其它几个光源特性都为缺省值。同样,我们也可用类似的方式定义光源的其他几个特性值,例如:
GLfloat light_ambient [] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat light_diffuse [] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; glLightfv(GL_LIGHT0, GL_AMBIENT , light_ambient ); glLightfv(GL_LIGHT0, GL_DIFFUSE , light_diffuse ); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);10.2.4 启动光照
glEnable(GL_LIGHTING);若使光照无效,则调用gDisable(GL_LIGHTING)可关闭当前光照。然后,必须使所定义的每个光源有效,例light0.c中只用了一个光源,即:
glEnable(GL_LIGHT0);
其它光源类似,只是光源号不同而已。
void glShadeModel(GLenum mode);函数参数为GL_FLAT或GL_SMOOTH,分别表示平面明暗处理和光滑明暗处理。
图10-2 Gouraud明暗处理 |
#include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void object(void); void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); /* GL_SMOOTH is actually the default shading model. */ void myinit (void) { glShadeModel (GL_SMOOTH); } void object(void) { glBegin (GL_POLYGON); glColor3f (1.0, 0.0, 0.0); glVertex2f (4.0, 4.0); glColor3f(1.0,1.0,1.0); glVertex2f (12.0, 4.0); glColor3f(0.0,0.0,1.0); glVertex2f (12.0, 12.0); glColor3f(0.0,1.0,0.0); glVertex2f (4.0, 12.0); glEnd (); } void CALLBACK display(void) { glClear (GL_COLOR_BUFFER_BIT); object (); glFlush (); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) gluOrtho2D (0.0, 16.0, 0.0, 16.0 * (GLfloat) h/(GLfloat) w); else gluOrtho2D (0.0, 16.0 * (GLfloat) w/(GLfloat) h, 0.0, 16.0); glMatrixMode(GL_MODELVIEW); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 500, 500); auxInitWindow ("Smooth Shading"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); }以上程序运行结果是在屏幕上显示一个色彩连续变化的三角形。这个程序是用的RGBA显示模式,若改用颜色表模式,则颜色内插实际上是颜色表的内插,因此呈现的颜色可能不连续。网友不妨自己试试。
图10-3 高氏明暗处理的正方形 |
void glMaterial{if}[v](GLenum face,GLenum pname,TYPE param);定义光照计算中用到的当前材质。face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体的哪一个面上;pname说明一个特定的材质;param是材质的具体数值,若函数为向量形式,则param是一组值的指针,反之为参数值本身。非向量形式仅用于设置GL_SHINESS。pname参数值具体内容见表10-1。另外,参数GL_AMBIENT_AND_DIFFUSE表示可以用相同的 RGB值设置环境光颜色和漫反射光颜色。
#include "glos.h" #include <GL/gl.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); void myinit(void) { /* 设置材质的各种光的颜色成分反射比率 */ GLfloat mat_ambient[]={0.8,0.8,0.8,1.0}; GLfloat mat_diffuse[]={0.8,0.0,0.8,1.0}; /* 紫色 */ GLfloat mat_specular[] = { 1.0, 0.0, 1.0, 1.0 }; /* 亮紫色 */ GLfloat mat_shininess[] = { 50.0 }; GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); } void CALLBACK display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); auxSolidSphere(1.0); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH16); auxInitPosition (0, 0, 500, 500); auxInitWindow ("Lighting_1 "); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); }以上程序运行结果是一个紫色的球。在函数myinit()中定义了球的材质颜色,光源的定义仍延用light0.c中的,而light.c物体的光源定义为缺省形式。从例子中明显地看出,物体的材质颜色定义与光源颜色定义几乎一样,物体反射到眼中的颜色与二者都有关系,具体关系请看下一小节。
#include "glos.h" #include <GL/gl.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); void myinit(void) { GLfloat mat_ambient[]= { 0.8, 0.8, 0.8, 1.0 }; GLfloat mat_diffuse[]= { 0.8, 0.0, 0.8, 1.0 }; /* 紫色 */ GLfloat mat_specular[] = { 1.0, 0.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; GLfloat light_diffuse[]= { 0.0, 0.0, 1.0, 1.0}; /* 蓝色 */ GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); } void CALLBACK display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); auxSolidSphere(1.0); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH16); auxInitPosition (0, 0, 500, 500); auxInitWindow ("Lighting_2 "); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); }
图10-4 光照蓝色球(高光为红色) |
#include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); /* 初始化z-buffer、光源和光照模型,在此不具体定义材质。*/ void myinit(void) { GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat position[] = { 0.0, 3.0, 2.0, 0.0 }; GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 1.0 }; glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_POSITION, position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glClearColor(0.0, 0.1, 0.1, 0.0); } void CALLBACK display(void) { GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 }; GLfloat mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 }; GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat no_shininess[] = { 0.0 }; GLfloat low_shininess[] = { 5.0 }; GLfloat high_shininess[] = { 100.0 }; GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0}; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 第一行第一列绘制的球仅有漫反射光而无环境光和镜面光。*/ glPushMatrix(); glTranslatef (-3.75, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第一行第二列绘制的球有漫反射光和镜面光,并有低高光,而无环境光 。*/ glPushMatrix(); glTranslatef (-1.25, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第一行第三列绘制的球有漫反射光和镜面光,并有很亮的高光,而无环境光 。*/ glPushMatrix(); glTranslatef (1.25, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第一行第四列绘制的球有漫反射光和辐射光,而无环境和镜面反射光。*/ glPushMatrix(); glTranslatef (3.75, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); auxSolidSphere(1.0); glPopMatrix(); /* 第二行第一列绘制的球有漫反射光和环境光,而镜面反射光。*/ glPushMatrix(); glTranslatef (-3.75, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第二行第二列绘制的球有漫反射光、环境光和镜面光,且有低高光。*/ glPushMatrix(); glTranslatef (-1.25, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第二行第三列绘制的球有漫反射光、环境光和镜面光,且有很亮的高光。*/ glPushMatrix(); glTranslatef (1.25, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第二行第四列绘制的球有漫反射光、环境光和辐射光,而无镜面光。*/ glPushMatrix(); glTranslatef (3.75, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); auxSolidSphere(1.0); glPopMatrix(); /* 第三行第一列绘制的球有漫反射光和有颜色的环境光,而无镜面光。*/ glPushMatrix(); glTranslatef (-3.75, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第三行第二列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有低高光。*/ glPushMatrix(); glTranslatef (-1.25, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第三行第三列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有很亮的高光。*/ glPushMatrix(); glTranslatef (1.25, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); auxSolidSphere(1.0); glPopMatrix(); /* 第三行第四列绘制的球有漫反射光和有颜色的环境光以及辐射光,而无镜面光。*/ glPushMatrix(); glTranslatef (3.75, -3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); auxSolidSphere(1.0); glPopMatrix(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= (h * 2)) glOrtho (-6.0, 6.0, -3.0*((GLfloat)h*2)/(GLfloat)w, 3.0*((GLfloat)h*2)/(GLfloat)w, -10.0, 10.0); else glOrtho (-6.0*(GLfloat)w/((GLfloat)h*2), 6.0*(GLfloat)w/((GLfloat)h*2), -3.0, 3.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGBA); auxInitPosition (0, 0, 600, 450); auxInitWindow ("Material"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); }
图10-5 多种光和材质的变化效果 |
void glColorMaterial(GLenum face,GLenum mode);函数参数face指定面,值有GL_FRONT、GL_BACK或GL_FRONT_AND_BACK(缺省值)。mode指定材质成分,值有 GL_AMBIENT、GL_DIFFUSE、GL_AMBIENT_AND_DIFFUSE(缺省值)、GL_SPECULAR或 GLEMISSION。
glColorMaterial(GL_FRONT,GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glColor3f(0.3,0.5,0.7); /* draw some objects here. */ glcolor3f(0.0,1.0,0.0); /* draw other objects here.*/ glDisable(GL_COLOR_MATERIAL);当需要改变场景中大部分方面的单个材质时,最好调用glColorMaterial();当需要修改不止一个材质参数时,最好调用glMaterial*()。注意,当不需要颜色材质时一定要关闭它,以避免相应的开销。下面来看一个颜色材质的具体应用例子:
#include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); void myinit(void) { GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glColorMaterial(GL_FRONT, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); } void CALLBACK display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* draw one yellow ball */ glLoadIdentity(); glTranslatef(-0.7,0.0,0.0); glColor3f(1.0,1.0,0.0); auxSolidSphere(0.5); /* draw one red cone */ glLoadIdentity(); glRotatef(-65.0,1.0,0.0,0.0); glTranslatef(0.7,0.0,0.0); glColor3f(1.0,0.0,0.0); auxSolidCone(0.4,0.6); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void main(void) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16); auxInitPosition (0, 0, 500, 500); auxInitWindow ("ColorMaterial Mode"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); }
图10-6 漫反射材质改变 |