OpenGL学习三十:深度缓冲区与掩码

深度缓冲区进行三维混合
多边形的绘图顺序极大地影响了最终的混合效果。为了应对不同深度的图形显示我们要开启深度缓冲区
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值决定哪个物体在前面,不启用深度缓冲区时,绘画顺序决定前后关系

OpenGL学习三十:深度缓冲区与掩码_第1张图片                            OpenGL学习三十:深度缓冲区与掩码_第2张图片

新添加功能,启用深度缓冲区时当按下A键时 球体Z值-6 立方体Z值-5 ;当按下B键时 球体Z值-5 立方体Z值-6
1.I键按下时:左图1(demo 按键I)
2.i键按下时 右图2(demo 按键i)

OpenGL学习三十:深度缓冲区与掩码_第3张图片                              OpenGL学习三十:深度缓冲区与掩码_第4张图片

新添加功能,启用深度缓冲区(D键按下) 在绘制立方体时启用A混合(B键按下)
1.i键按下左图1,
1.I键按下右图2
分析:此时由于启用深度缓冲区,那么Z直决定了物体先后顺序。同时存在混合,可以看出图2,当立体图具体观察点较近时,由于它是透明的,因此可以看到后面的实心球体,有图1可以看处,当实心球体靠近观察点时,实心后面的部分是看不见的,被遮挡的,同时立方体内部是不透明的

OpenGL学习三十:深度缓冲区与掩码_第5张图片                                 OpenGL学习三十:深度缓冲区与掩码_第6张图片

新添加功能,禁用深度缓冲区(d键按下),在绘制立方体是启用A混合(B键按下)
1.i键按下右图1,
1.I键按下右图2

分析,此时由于禁用深度缓冲区,那么绘画顺序决定了物体先后顺序(立方体后画,显示在最前面),可以看出实心球体始终是在后面,前面的立方体整体存在透明度

OpenGL学习三十:深度缓冲区与掩码_第7张图片                              OpenGL学习三十:深度缓冲区与掩码_第8张图片

新添加功能,启用深度缓冲区(D键按下),启用深度缓冲区掩码(M键按下),在绘制立方体是启用A混合(B键按下)

1.i键按下右图1,
1.I键按下右图2

分析:此时由于启用深度缓冲区,那么Z直决定了物体先后顺序,有图1可以看处,当实心球体靠近观察点时,实心后面的部分是看不见的,被遮挡的,同时立方体内部是不透明的, 启动了深度缓冲区掩码因此立方体内部也是可见的。

OpenGL学习三十:深度缓冲区与掩码_第9张图片                             OpenGL学习三十:深度缓冲区与掩码_第10张图片

 

在绘制多个三维图形透明效果是,应把具有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);

 
OpenGL学习三十:深度缓冲区与掩码_第11张图片

 

 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);

 

OpenGL学习三十:深度缓冲区与掩码_第12张图片

 

深度测试
当我们开启深度测试时,距离观察点远的物体如被遮盖着则不会进行绘画,简单的说,当绘制一个图元,会将它的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;
}

 

你可能感兴趣的:(OpenGL)