OpenGL部分知识小总结
光照:
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
创建光源:
glLightf(GLenum light, GLenum pname, GLfloat param);
pname参数:
GL_AMBIENT——环境光
GL_DIFFUSE——散射光强度,LIGHT0默认为白色,其他为黑色
GL_SPECULAR——镜面强度,LIGHT0默认为白色,其他为黑色
GL_POSITION——光源位置
GL_SPOT_DIRECTION——聚光灯方向
GL_SPOT_EXPONENT——聚光指数
GL_SPOT_CUTOFF——聚光灯切角
GL_CONSTANT_ATTENUATION——常数衰减因子
GL_LINEAR_ATTENUATION——线性衰减因子
GL_QUADRATIC_ATTENUATION——二次衰减因子
光照模型:
glLightModel*()描述了光照模型的参数.
pname参数:
GL_LIGHT_MODEL_AMBIENT: 整个场景的环境光的RGBA参数
GL_LIGHT_MODEL_LOCAL_VIEWER: 镜面反射角度如何计算,GL_FALSE把观察点放到无限远处
GL_LIGHT_MODEL_TWO_SIDE: 单面还是双面光照
GL_LIGHT_MODEL_COLOR_CONTROL: 镜面颜色的计算是否从环境和散射颜色中分离出来
材质属性:
glMaterialf(GLenum face, GLenum pname, GLfloat param);
pname参数:
GL_AMBIENT: 材料的环境颜色
GL_DIFFUSE: 材料的散射颜色
GL_AMBIENT_AND_DIFFUSE
GL_SPECULAR: 材料的镜面颜色
GL_SHININESS: 镜面指数 [0.0, 128.0],值越大,亮点越小、越亮
GL_EMISSION: 材料的发射颜色, eg:模拟台灯
GL_COLOR_INDEXES: 环境、散射和镜面颜色索引
为了减少材料属性所带来的开销,可以使用glColorMaterial(GLenum face, GLenum mode);
face: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK. mode: GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR
然后使用glColor3f()指定颜色
如果想更改单个材料参数的值,可以使用glColorMaterial(),如果想更改多个材料参数的值,可以使用glMaterial*().
混合:
glEnable(GL_BLEND);
glBlendFunc(GLenum sfactor, GLenum dfactor);
混合因子:
GL_ZERO
GL_ONE
GL_SRC_COLOR
GL_ONE_MINUS_SRC_COLOR
GL_DST_COLOR
GL_ONE_MINUS_DST_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
GL_CONSTANT_COLOR
GL_ONE_MINUS_CONSTANT_COLOR
GL_CONSTANT_ALPHA
GL_ONE_MINUS_CONSTANT_ALPHA
GL_SRC_ALPHA_SATURATE
如果使用了GL_*CONSTANT*混合,就需要使用glBlendColor(r,g,b,a)指定一种常量颜色
抗锯齿:
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); //最好的透视修正
对点和直线进行抗锯齿处理:
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_SMOOTH);
RGB模式下抗锯齿需要启用混合功能glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
使用多重采用对几何图元进行抗锯齿处理:
多重采样特别适合对多边形的边缘进行抗锯齿处理,因为此时不需要进行排序,如果使用alpha值对多边形进行抗锯齿处理,
半透明的物体的绘图顺序将会影响最终的颜色。
在应用程序中增加多重采样功能:
1)、获取一个支持多重采样的窗口: glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);;
2)、打开窗口之后,需要验证一下多重采样功能是否可用,如果查询状态变量GL_SAMPLE_BUFFERS返回的值是1,并且GL_SMAPLES
返回的值大于1,就可以采用多重采样功能:
GLint bufs, smaples;
glGetIntegerv(GL_SAMPLE_BUFFERS, &bufs);
glGetIntegerv(GL_SAMPLES, &samples);
3)、启用多重采样功能:
glEnable(GL_MULTISAMPLE);
雾:
glFogi(GL_FOG_MODE, GL_EXP2); //设定雾的模式
glFogfv(GL_FOG_COLOR, fogColor); //设定雾的颜色
glFogf(GL_FOG_DENSITY, 0.35); //设定雾的密度
glHint(GL_FOG_HINT,GL_DONT_CARE); //设定雾的渲染方式
glFogf(GL_FOG_START, 1.0); //设定雾的开始位置
glFogf(GL_FOG_END, 5.0); //设定雾的结束位置
点参数:
有时,我们相对那些看上去像圆或球体的物体进行渲染,但是又不想使用效率较低的多边形近似模拟。例如,飞机靠近跑道上的
路灯时,路灯变得越来越大、越来越亮,或者想模拟液滴。可以使用微粒系统模拟这些现象。
点参数根据点和观察者的距离,对点的大小和亮度进行衰减。使用glPointParameterf*()指定衰减方程式的参数和alpha.
glPointParameterf(GLenum pname, Glfloat param);
glPointParameterf(GLenum pname, const TYPE* param);
pname: GL_POINT_DISTANCE_ATTENUATION, param:(a,b,c)数组-常数、线性、二次衰减系数
GL_POINT_SIZE_MIN OR GL_POINT_SIZE_MAX, param表示最小值or最大值
...
为了使用点参数得到圆点而不是方块点,需要启用点抗锯齿功能:
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
多边形偏移:
如果想着重显示实心物体的边缘,需要使用多边形偏移
启用多边形偏移:
glEnable(GL_POLYGON_OFFSET_FILL); //GL_POLYGON_OFFSET_LINE , GL_POLYGON_OFFSET_POINT
还需要使用glPolygonMode()设置当前的多边形光栅化方法
eg:
#include <GL/glut.h> #include <stdio.h> #include <stdlib.h> #ifdef GL_VERSION_1_1 GLuint list; GLint spinx = 0; GLint spiny = 0; GLfloat tdist = 0.0; GLfloat polyfactor = 1.0; GLfloat polyunits = 1.0; void display (void) { GLfloat gray[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 }; glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix (); glTranslatef (0.0, 0.0, tdist); glRotatef ((GLfloat) spinx, 1.0, 0.0, 0.0); glRotatef ((GLfloat) spiny, 0.0, 1.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray); glMaterialfv(GL_FRONT, GL_SPECULAR, black); glMaterialf(GL_FRONT, GL_SHININESS, 0.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_POLYGON_OFFSET_FILL); (polyfactor, polyunits); glCallList (list); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glColor3f (1.0, 1.0, 1.0); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glCallList (list); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPopMatrix (); glFlush (); } void gfxinit (void) { 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 }; GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat global_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; glClearColor (0.0, 0.0, 0.0, 1.0); list = glGenLists(1); glNewList (list, GL_COMPILE); glutSolidSphere(1.0, 20, 12); glEndList (); glEnable(GL_DEPTH_TEST); glLightfv (GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv (GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv (GL_LIGHT0, GL_POSITION, light_position); glLightModelfv (GL_LIGHT_MODEL_AMBIENT, global_ambient); } void reshape(int width, int height) { glViewport (0, 0, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective(45.0, (GLdouble)width/(GLdouble)height, 1.0, 10.0); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } void mouse(int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: switch (state) { case GLUT_DOWN: spinx = (spinx + 5) % 360; glutPostRedisplay(); break; default: break; } break; case GLUT_MIDDLE_BUTTON: switch (state) { case GLUT_DOWN: spiny = (spiny + 5) % 360; glutPostRedisplay(); break; default: break; } break; case GLUT_RIGHT_BUTTON: switch (state) { case GLUT_UP: exit(0); break; default: break; } break; default: break; } } void keyboard (unsigned char key, int x, int y) { switch (key) { case 't': if (tdist < 4.0) { tdist = (tdist + 0.5); glutPostRedisplay(); } break; case 'T': if (tdist > -5.0) { tdist = (tdist - 0.5); glutPostRedisplay(); } break; case 'F': polyfactor = polyfactor + 0.1; printf ("polyfactor is %f\n", polyfactor); glutPostRedisplay(); break; case 'f': polyfactor = polyfactor - 0.1; printf ("polyfactor is %f\n", polyfactor); glutPostRedisplay(); break; case 'U': polyunits = polyunits + 1.0; printf ("polyunits is %f\n", polyunits); glutPostRedisplay(); break; case 'u': polyunits = polyunits - 1.0; printf ("polyunits is %f\n", polyunits); glutPostRedisplay(); break; default: break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutCreateWindow(argv[0]); glutReshapeFunc(reshape); glutDisplayFunc(display); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); gfxinit(); glutMainLoop(); return 0; } #else int main(int argc, char** argv) { fprintf (stderr, "This program demonstrates a feature which is not in OpenGL Version 1.0.\n"); fprintf (stderr, "If your implementation of OpenGL Version 1.0 has the right extensions,\n"); fprintf (stderr, "you may be able to modify this program to make it run.\n"); return 0; } #endif
显示列表:
glGenLists(GLsizei range); //产生若干个未使用的索引值,用作glNewList的第一个参数
glNewList(GLuint list, GLenum mode); //mode一般用GL_COMPILE,只编译,不执行,相反GL_COMPILE_AND_EXECUTE
glEndList();
glCallList(GLuint list); //调用显示列表
创建显示列表时,只有表达式的值存储在显示列表中,如果数组中的值发生了变化,显示列表中的值不会发生变化。
并不是所有的OpenGL函数都可以存储在显示列表中并执行,例如设置状态的函数和提取状态值的函数就无法存储在显示列表中,当在创建
显示列表时调用了这些函数时, 它们会立即执行。
显示列表可嵌套.
执行多个显示列表:
可以连续执行多个显示列表,但必须把显示列表索引放在一个数组中并调用glCallLists(),glListBase(GLuint base)指定初始偏移量,
它将与glCallLists()中的显示列表索引相加,显示列表基址对glCallList()和glNewList()没有效果。
glCallLists(GLsizei n, GLenum type, const GLvoid *lists);