深度缓冲区进行三维混合
多边形的绘图顺序极大地影响了最终的混合效果。为了应对不同深度的图形显示我们要开启深度缓冲区
glEnable(GL_DEPTH_TEST);
对已开启深度缓冲区的图形来说,如果一个不透明的物理如果举例观察点较近,那么它所遮挡的部分就不会进行绘制
对于存在透明度的图形来说要复杂一些,如果一个透明的物体靠近距离观察点较近。那么它所遮挡的部分也是需要绘制的
对于透明的图形绘制需要设置深度缓冲区的可读性
glDepthMask(GL_TRUE|GL_FALSE)
GL_TRUE:代表深度缓冲区为可读写
GL_FALSE:代表深度缓冲区为只读
对于透明的3D图形绘制需要设置深度缓冲区步骤为:
1.glDepthMask(GL_FALSE)
2.绘制透明图形
3.glDepthMask(GL_TRUE)
以下对混合的深度理解
接下来通过实例说明 启用深度缓冲区,设置深度缓冲区掩码,以及三维图形混合的技巧
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer glLoadIdentity(); glEnable(GL_DEPTH_TEST); //glDisable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, texture[filter]); glPushMatrix(); glTranslatef(1.2f,0.5f,sphere); glColor4f(1,1,0,1); glutSolidSphere (0.8, 32, 32); glPopMatrix(); glEnable(GL_TEXTURE_2D); //glEnable(GL_BLEND); //glDepthMask(GL_FALSE); glPushMatrix(); glTranslatef(0.0f,0.0f,quadz); glColor4f(1.0f, 1.0f, 1.0f, 0.5f); glBegin(GL_QUADS); ............. glEnd(); glPopMatrix(); //glDepthMask(GL_TRUE); //glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D)
通过上面的代码可以看出,这里我先绘制了一个球体,然后绘制了一个立方体,球体的Z值-5,立方体Z值为-6,由此可知球体距离观察点更近一些
1.当启用深度缓冲区时效果见右图1(D键按下)
2.当未启用深度缓冲区时效果见右图2(d键按下)
(黑色加粗字体为是否启用缓冲区的)
对比可知当我们启用深度缓冲区时Z值决定哪个物体在前面,不启用深度缓冲区时,绘画顺序决定前后关系
新添加功能,启用深度缓冲区时当按下A键时 球体Z值-6 立方体Z值-5 ;当按下B键时 球体Z值-5 立方体Z值-6
1.I键按下时:左图1(demo 按键I)
2.i键按下时 右图2(demo 按键i)
新添加功能,启用深度缓冲区(D键按下) 在绘制立方体时启用A混合(B键按下)
1.i键按下左图1,
1.I键按下右图2
分析:此时由于启用深度缓冲区,那么Z直决定了物体先后顺序。同时存在混合,可以看出图2,当立体图具体观察点较近时,由于它是透明的,因此可以看到后面的实心球体,有图1可以看处,当实心球体靠近观察点时,实心后面的部分是看不见的,被遮挡的,同时立方体内部是不透明的
新添加功能,禁用深度缓冲区(d键按下),在绘制立方体是启用A混合(B键按下)
1.i键按下右图1,
1.I键按下右图2
分析,此时由于禁用深度缓冲区,那么绘画顺序决定了物体先后顺序(立方体后画,显示在最前面),可以看出实心球体始终是在后面,前面的立方体整体存在透明度
新添加功能,启用深度缓冲区(D键按下),启用深度缓冲区掩码(M键按下),在绘制立方体是启用A混合(B键按下)
1.i键按下右图1,
1.I键按下右图2
分析:此时由于启用深度缓冲区,那么Z直决定了物体先后顺序,有图1可以看处,当实心球体靠近观察点时,实心后面的部分是看不见的,被遮挡的,同时立方体内部是不透明的, 启动了深度缓冲区掩码因此立方体内部也是可见的。
在绘制多个三维图形透明效果是,应把具有A的物体后画,先画实心物体。
对于以下等等内容不属于矩阵内容,因此PUSH POP 对此无用,
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, texture[filter]);
深度缓冲区掩码的理解
glDepthMask();
通过启用深度测试 glEnable(GL_DEPTH_TEST); 可以控制多个物体间先后顺序,如果近观察点的物体是不透的那么它所遮盖的物体也不会绘制。但是假如这俩个物体时立体时,比如是立方体,立方体6个面,是有先后顺序的,如前,后面,假如立方体存在透明度,我们希望的是透过立方体的前面能看到立方体的后面,由于混合式针对物体间,立方体6个面之间不能存在混合,所以我们看到的效果是立方体前面遮盖住了立方体后面(由于启用深度测试,后面Z值在后,因此不会绘画)如果此时我们关闭GL_DEPTH_TEST,就会让立方体的每个面都进行绘画,哪怕他们的Z序是被遮挡的。 glDepthMask();就是解决这个问题,它相当于在立方体之间调用了glEnable/glDisable(GL_DEPTH_TEST),(GL_DEPTH_TEST不能再begin end 之间调用,不起作用) 下面两段代码的作用是一样的
glDisable(GL_DEPTH_TEST); glBegin(GL_QUADS); glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); glBegin(GL_QUADS); // Back Face glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glEnd(); glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE); glBegin(GL_QUADS); glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Back Face glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glEnd(); glDepthMask(GL_TRUE);
深度测试
当我们开启深度测试时,距离观察点远的物体如被遮盖着则不会进行绘画,简单的说,当绘制一个图元,会将它的Z值存储到深度缓冲区,当绘制下一个图元时,源片断的Z值和深度缓冲区的对应的值比较如果小于则不被替换,简单的说就是不会被绘画,这个“小于”的规则是可以更改。比如我们科室设置为”大于“
void glDepthFunc(Glenum func)
func:GL_NEVER 从来不能通过
GL_ALWAYS 永远可以通过(默认值)
GL_LESS 小于参考值可以通过
GL_LEQUAL 小于或者等于可以通过
GL_EQUAL 等于通过
GL_GEQUAL 大于等于通过
GL_GREATER 大于通过
GL_NOTEQUAL 不等于通过
#include "header.h" bool light; bool blend; bool mask; static int maxZ=-5; static int minZ=-6; int quadz=-6; int sphere=-5; GLuint texture[1]; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); AUX_RGBImageRec *LoadBMP(char *Filename) { FILE *File=NULL; if (!Filename) { return NULL; } File=fopen(Filename,"r"); if (File) { fclose(File); return auxDIBImageLoad(Filename); } return NULL; } int LoadGLTextures() { int Status=FALSE; AUX_RGBImageRec *TextureImage[1]; memset(TextureImage,0,sizeof(void *)*1); if (TextureImage[0]=LoadBMP("Data/glass.bmp")) { Status=TRUE; glGenTextures(1, &texture[0]); // Create Nearest Filtered Texture glBindTexture(GL_TEXTURE_2D, texture[0]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); } if (TextureImage[0]) { if (TextureImage[0]->data) { free(TextureImage[0]->data); } free(TextureImage[0]); } return Status; } void ReSizeGLScene(GLsizei width, GLsizei height) { if (height==0) { height=1; } glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Calculate The Aspect Ratio Of The Window gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int InitGL(GLvoid) { if (!LoadGLTextures()) { return FALSE; } glShadeModel(GL_SMOOTH); glClearColor(0.0f,0.0f, 0.0f, 1.0f); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return TRUE; } void DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glTranslatef(1.2f,0.5f,sphere); glColor4f(1,1,0,1); glutSolidSphere (0.8, 32, 32); glPopMatrix(); if (blend) { glEnable(GL_BLEND); } if (mask) { glDepthMask(GL_FALSE); } glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[0]); glPushMatrix(); glColor4f(1.0f, 1.0f, 1.0f, 0.5f); glTranslatef(0.0f,0.0f,quadz); glBegin(GL_QUADS); glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Back Face glNormal3f( 0.0f, 0.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Face glNormal3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Bottom Face glNormal3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Right face glNormal3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Left Face glNormal3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); glEnd(); glPopMatrix(); glDisable(GL_TEXTURE_2D); if (mask) { glDepthMask(GL_TRUE); } if (blend) { glDisable(GL_BLEND); } glFlush(); } void keyboard (unsigned char key, int x, int y) { switch (key) { case 'i': sphere=maxZ; quadz=minZ; break; case 'I': sphere=minZ; quadz=maxZ; break; case 'd': glDisable(GL_DEPTH_TEST); break; case 'D': glEnable(GL_DEPTH_TEST); break; case 'B': blend=true; break; case 'b': blend=false; break; case 'M': mask=true; break; case 'm': mask=false; break; } glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutCreateWindow("深度缓冲区与掩码"); glutReshapeFunc(ReSizeGLScene); glutDisplayFunc(DrawGLScene); glutKeyboardFunc(keyboard); InitGL(); glutMainLoop(); return 0; }