`
tiankefeng0520
  • 浏览: 146740 次
  • 性别: Icon_minigender_1
  • 来自: 长春
社区版块
存档分类
最新评论

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值决定哪个物体在前面,不启用深度缓冲区时,绘画顺序决定前后关系

                           

新添加功能,启用深度缓冲区时当按下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;
}

 

  • 大小: 10.4 KB
  • 大小: 11.2 KB
  • 大小: 13.1 KB
  • 大小: 9.6 KB
  • 大小: 8.3 KB
  • 大小: 11.3 KB
  • 大小: 11 KB
  • 大小: 13.3 KB
  • 大小: 9.9 KB
  • 大小: 13.1 KB
  • 大小: 15.9 KB
  • 大小: 14.8 KB
分享到:
评论

相关推荐

    OpenGL模板缓冲区应用示例源代码

    OpenGL模板缓冲区是一种图形处理技术,常用于实现复杂的遮罩效果和高级...总的来说,这个源代码示例是一个很好的学习工具,可以帮助开发者掌握OpenGL模板缓冲区的使用,并激发他们在3D图形编程中实现创新效果的灵感。

    OpenGL中蒙板缓冲区的妙用.pdf

    首先,蒙板缓冲区类似于深度缓冲区,都是进行逐像素测试。但它更侧重于提供一种条件机制,根据当前像素蒙板缓冲区的值来决定是否接受或拒绝片段。当蒙板测试、深度测试或两者都通过时,系统会执行特定的操作。例如,...

    OpenGL 常见函数功能查询

    - **功能描述**:控制深度缓冲区写入时的掩码。 **glStencilMask**: 设置模板写掩码。 - **功能描述**:控制模板缓冲区写入时的掩码。 **glAlphaFunc**: 设置Alpha测试函数。 - **功能描述**:用于定义Alpha测试的...

    opengl函数大全

    - **功能**: 控制深度缓冲区的写入掩码,决定深度缓冲区是否可以被写入。 **32. glDepthRange** - **功能**: 设置深度值映射范围,用于将片段的深度值映射到指定范围内。 **33. glDrawArrays** - **功能**: 使用...

    OpenGL常见函数表

    **`glDepthMask`**:设置深度缓冲区写掩码。 **`glStencilMask`**:设置模板缓冲区写掩码。 **`glAlphaFunc`**:设置Alpha测试函数。 **`glStencilFunc`**:设置模板测试函数。 **`glStencilOp`**:设置模板测试...

    OpenGL蒙版实例

    在处理蒙版时,我们需要关注的颜色缓冲区(Color Buffer)、深度缓冲区(Depth Buffer)以及模板缓冲区(Stencil Buffer)。 颜色缓冲区存储最终像素的颜色值,而深度缓冲区用于进行遮挡测试,确保近处的物体遮挡住...

    Opengl 模板

    然后,设置必要的OpenGL上下文属性,比如颜色深度、深度缓冲、模板缓冲等。 2. 绑定模板缓冲:在OpenGL上下文中,使用`glEnable(GL_STENCIL_TEST)`开启模板测试,并使用`glStencilFunc()`和`glStencilOp()`函数设置...

    opengl clip cap

    当渲染新像素时,OpenGL会将这个掩码与当前模板缓冲区的值进行比较。根据比较结果,你可以选择允许或拒绝该像素的渲染。这在创建复杂的遮罩效果、多边形剔除或者实现分层渲染等方面非常有用。 在描述中提到的“红宝...

    OpenGL 函数

    - **`glDepthMask`**与**`glStencilMask`**:控制深度和模板缓冲区的写入掩码。 #### Alpha与模板测试 - **`glAlphaFunc`**:设置基于Alpha值的测试条件。 - **`glStencilFunc`**与**`glStencilOp`**:设置模板测试...

    OpenGL 可编程管道

    片段着色器在获取数据后,通过内建的varying变量和专用的片段着色器输入变量,完成最终片段颜色的计算,并输出到帧缓冲区。 了解OpenGL可编程管道及其与GLSL的关系对于深入理解图形渲染过程至关重要,它为开发者...

    OpenGLES demo - 16. 蒙板 Stencil

    蒙板,也称为模板缓冲,是一个附加的像素缓冲区,用于存储每个像素的模板值。这个模板值可以用来控制像素是否应该被绘制。通过设置不同的模板测试条件,我们可以决定哪些像素应该被渲染,哪些不应该。在OpenGLES 2.0...

    LearnOpenGL(十六)之模板测试

    模板缓冲区是一个与颜色和深度缓冲区同等大小的额外缓冲,可以用来存储每个像素的整数值,这些值可以被用来作为渲染决策的一部分。 开启模板测试非常简单,只需调用`glEnable(GL_STENCIL_TEST)`。然后,我们可以...

    在VisualC_6_0环境下利用OpenGL实现模型的动态观察

    该结构体包含多个参数,用于定义颜色模式(RGB/RGBA或颜色索引模式)、缓冲区类型(单缓冲或多缓冲)、颜色深度、累加和模板缓冲区的位数等属性。 例如,在Win32环境下,常见的像素格式设定如下: ```c++ static ...

    sp_clear.rar_The Given

    2. **清除操作(Buffer Clearing)**:在渲染过程中,缓冲区的清除是常见的操作,如清空颜色缓冲区或深度缓冲区,以便在新的帧开始时有一个干净的起始状态。 3. **指定值(Specified Values)**:在清除缓冲区时,...

    OpenGL 函数库

    - 设置深度缓冲区的清除深度值。 14. **`glClearStencil`** - 设置模板缓冲区的清除值。 15. **`glClipPlane`** - 定义裁剪平面,用于高级几何裁剪。 16. **`glColor`** - 设置当前颜色,用于后续绘制操作的...

    webgl-reference-card-1_0

    **用途**:设置深度掩码,控制深度缓冲区是否可以被写入。 - **`void stencilMask(uint mask)`** - **参数**: - `mask`:无符号整型值,指定哪些模板缓冲位可以被写入。 **用途**:设置模板掩码,控制模板...

    深入浅出MFC(侯俊杰)

    这部分通常涉及到像素格式描述符(PIXELFORMATDESCRIPTOR)的设置,包括颜色深度、缓冲区类型等参数。 - **创建OpenGL渲染窗口**: 通过MFC创建窗口,并将其与OpenGL关联起来。这一步骤包括设置窗口属性、创建渲染上...

    OpenGL混合

    这个函数定义了源颜色(来自绘制的对象)和目的地颜色(已存在于帧缓冲区的颜色)如何相加混合。源和目标的参数可以是多种预定义常量,如GL_ONE、GL_ZERO、GL_SRC_COLOR、GL_DST_COLOR等,这些常量代表了不同的权重...

Global site tag (gtag.js) - Google Analytics