0.混合
在正常情况下,opengl渲染时会把颜色值输入到颜色缓冲区中,深度值输入到深度缓冲区中。如果我们关闭深度测试,那么新的颜色值会简单的覆盖在旧的颜色值上。当开启深度测试时,颜色段只有在通过深度测试时,才会覆盖已经存在于颜色缓冲区中的值。
混合,当开启混合时,输入的颜色值将会和已经存在于颜色缓冲区中的颜色进行组合。至于如何组合取决于rgba中的alpha。混合时在场景进行了光栅化并转换为像素之后,但是在最终的像素绘制到帧缓冲区之前发生的。混合时诸如透明化、数字合成、油漆这类技巧的核心。
a.源因子和目标因子、源颜色和目标颜色
源颜色:新片段的颜色值S
目标颜色:当前已经存储的对应像素的颜色值D
源因子:vectorS(Sr,Sg,Sb,Sa)
目标因子:vectorD(Dr,Dg,Db,Da)
则最后计算所得为(S*vectorS+D*vectorD)
b.栗子可以选择两种不同的方式来指定混合因子:glBlendFunc(GLenum S, GLenum D);和glBendFuncSeparate()
下面是glBlendFunc(GLenum S, GLenum D)中S与D的取值表
栗子源于:http://my.oschina.net/sweetdark/blog/169668?fromerr=u57CPqzi
#include"grapg.h" GLfloat lightpos[4]={-100.0f,100.0f,50.0f,1.0f}; GLfloat lightposmirror[4]={-100.0f,-100.0f,50.0f,1.0f}; GLfloat fnolight[] = { 0.0f, 0.0f, 0.0f, 0.0f }; GLfloat flowlight[] = { 0.25f, 0.25f, 0.25f, 1.0f }; GLfloat fbrightlight[] = { 1.0f, 1.0f, 1.0f, 1.0f }; void drawground() { GLfloat fextent=20.0f; GLfloat fstep=0.5f; GLfloat y=0.0f; bool ibounce=false; glShadeModel(GL_FLAT); for(GLfloat istrip=-fextent;istrip<=fextent;istrip+=fstep) { glBegin(GL_TRIANGLE_STRIP); for(GLfloat irun=fextent;irun>=-fextent;irun-=fstep) { GLfloat fcolor; if(ibounce) { fcolor=1.0f; } else { fcolor=0.0f; } glColor4f(fcolor,fcolor,fcolor,0.5f); glVertex3f(istrip,y,irun); glVertex3f(istrip+fstep,y,irun); ibounce=!ibounce; } glEnd(); } } void DrawWorld() { glColor3f(1.0f,1.0f,0.0f); glPushMatrix(); glTranslatef(0.0f,0.5f,-3.5f); glutWireTorus(0.25,0.08,68,37); glPopMatrix(); } void reshape_blend(int w,int h) { if(h == 0) h = 1; glViewport(0, 0, w, h); //视口大小设置 glMatrixMode(GL_PROJECTION); //设置投影 glLoadIdentity(); GLfloat faspect = (GLfloat) w / (GLfloat) h; gluPerspective(35.0f, faspect, 1.0f, 50.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, -0.4f, 0.0f); glutPostRedisplay(); } void setrc_blend() { glClearColor(0.0f,0.0f,0.0f,1.0f); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); glEnable(GL_LIGHTING); glLightModelfv(GL_LIGHT_MODEL_AMBIENT,fnolight);//全局环境光 glLightfv(GL_LIGHT0, GL_AMBIENT, flowlight); glLightfv(GL_LIGHT0,GL_DIFFUSE,fbrightlight); glLightfv(GL_LIGHT0, GL_SPECULAR, fbrightlight); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL);//材质属性设置 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glMateriali(GL_FRONT, GL_SHININESS, 128); } void blend() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glPushMatrix(); glLightfv(GL_LIGHT0,GL_POSITION,lightposmirror);//设置光照位置 glPushMatrix();//绘制镜像 glFrontFace(GL_CW);//因为是镜像所以要反着来 glScalef(1.0f,-1.0f,1.0f); DrawWorld(); glFrontFace(GL_CCW); glPopMatrix(); glDisable(GL_LIGHTING);//画地面时,关闭光源, 地面可见并均匀着色。 glEnable(GL_BLEND);//打开混合 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//设置混合因子 drawground();//画地面 glDisable(GL_BLEND);//关闭混合效果 glEnable(GL_LIGHTING); glPopMatrix(); glLightfv(GL_LIGHT0, GL_POSITION, lightpos);//设置光源在左上角 DrawWorld(); glutSwapBuffers(); } int main_blend() { glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(800, 600); glutCreateWindow("test"); glutDisplayFunc(blend); glutReshapeFunc(reshape_blend); setrc_blend(); glutMainLoop(); return 0; }
反向画个相同物体,参上倒影与背景的混合,就成了镜像。
1.抗锯齿/反走样
说白了就是画图过程中边界上会产生锯齿(像素说到底是个有大小的小方块?),
解决方案:
a.利用与背景混合把锯齿磨平。(和平滑是不是一个道理?)
glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);//alpha值越大,抗锯齿效果更加明显
b.多重采样
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_MULTISAMPLE)//打开多重采样缓冲区 GLint buff,samples; glGetIntegerv(GL_SAMPLE_BUFFERS,&buff);//测试多重采样是否可用 glGetIntegerv(GL_SAMPLES,&samples);//buff==1&&samples>1则可以使用 多重采样 glEnable(GL_MULTISAMPLE);//启用多重采样 }
对于多边形而言,多重采样更好。点线都行
2.雾
a.使用雾
b.雾方程glEnable(GL_FOG);//开启雾效果,以下均是用glfog*设置雾的一些属性 glFogfv(GL_FOG_COLOR,flowLight);//设置雾的颜色 glFogf(GL_FOG_START,5.0f);//设置雾开始于结束 glFogf(GL_FOG_END,30.0f); glFogi(GL_FOG_MODE,GL_LINEAR);//设置雾方程
c.雾坐标
我们不一定要OpenGL计算雾距离,也可以自己设置雾距离。通过手工调用glFogCoordf:void glFogCoordf(GLfoat fFogDistance);
使用雾坐标的前提是,要调用下面的函数更改雾的来源:glFogi(GL_FOG_COORD_SRC, GL_FOG_COORD);
打开OpenGl产生的雾值:glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH);
3.多边形偏移
glEnable(GL_POLYGON_OFFSET_FILL); //... glDisable(GL_POLYGON_OFFSET_FILL);
4.显示列表
a.创建
b.使用theTorus=glGenLists(1); glNewList(theTorus,GL_COMPILE); torus(8,25); glEndList();
c.功用glCallList(theTorus);//显示列表
提高效率
d.适用
状态变量、绘制都行
5.显示列表和抗锯齿的综合栗子
话说抗锯齿,就抗出个这?#include "grapg.h" GLuint theTorus; void torus(int numc,int numt) { glColor4f(0.0,1.0,0.0,0.5); glPointSize(30); glBegin(GL_POINTS); glVertex3f(0.0,0.0,0.0); glEnd(); for(int i=0;i<numc;i++) { glColor4f(0.0,1.0,1.0,0.5); glBegin(GL_QUAD_STRIP); for(int j=0;j<=numt;j++) { for(int k=1;k>=0;k--) { double s=(i+k)%numc+0.5; double t=j%numt; double x=(1+0.1*cos(s*GL_PI*2/numc))*cos(t*GL_PI*2/numt); double y=(1+0.1*cos(s*GL_PI*2/numc))*sin(t*GL_PI*2/numt); double z=0.1*sin(s*GL_PI*2/numc); glVertex3f(x,y,z); } } glEnd(); } } void init_calllist() { theTorus=glGenLists(1); glNewList(theTorus,GL_COMPILE); torus(8,25); glEndList(); glShadeModel(GL_FLAT); glClearColor(0.0,0.0,0.0,0.0); // glEnable(GL_MULTISAMPLE);//启用多重采样 glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_POLYGON_SMOOTH); glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST); glEnable(GL_POINT_SMOOTH); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); } void calllist() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,1.0,1.0); glCallList(theTorus);//显示列表 glFlush(); } void reshape_calllist(int w,int h) { glViewport(0,0,(GLsizei)w,(GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(30,(GLfloat)w/(GLfloat)h,1.0,100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,0,10,0,0,0,0,1,0); } void speciakey_calllist(int key,int x,int y) //处理特殊键按键事件 { if(key==GLUT_KEY_UP) { glRotatef(30.0f,1.0f,0.0f,0.0f); } if(key==GLUT_KEY_DOWN) { glRotatef(30.0f,0.0f,1.0f,0.0f); } if(key==GLUT_KEY_LEFT) { glLoadIdentity(); gluLookAt(0,0,10,0,0,0,0,1,0); } glutPostRedisplay(); } int main_calllist() { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_MULTISAMPLE); glutInitWindowPosition(200, 200); glutInitWindowSize(500, 500); glutCreateWindow("test"); init_calllist(); glutSpecialFunc(speciakey_calllist); //和glutKeyboardFunc一起接受键盘事件。glutSpecialFunc处理的几个特殊键的按键事件 glutReshapeFunc(reshape_calllist); glutDisplayFunc(calllist); glutMainLoop(); return 0; }