深度缓冲区进行三维混合
多边形的绘图顺序极大地影响了最终的混合效果。为了应对不同深度的图形显示我们要开启深度缓冲区
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; }
相关推荐
OpenGL模板缓冲区是一种图形处理技术,常用于实现复杂的遮罩效果和高级...总的来说,这个源代码示例是一个很好的学习工具,可以帮助开发者掌握OpenGL模板缓冲区的使用,并激发他们在3D图形编程中实现创新效果的灵感。
首先,蒙板缓冲区类似于深度缓冲区,都是进行逐像素测试。但它更侧重于提供一种条件机制,根据当前像素蒙板缓冲区的值来决定是否接受或拒绝片段。当蒙板测试、深度测试或两者都通过时,系统会执行特定的操作。例如,...
- **功能描述**:控制深度缓冲区写入时的掩码。 **glStencilMask**: 设置模板写掩码。 - **功能描述**:控制模板缓冲区写入时的掩码。 **glAlphaFunc**: 设置Alpha测试函数。 - **功能描述**:用于定义Alpha测试的...
- **功能**: 控制深度缓冲区的写入掩码,决定深度缓冲区是否可以被写入。 **32. glDepthRange** - **功能**: 设置深度值映射范围,用于将片段的深度值映射到指定范围内。 **33. glDrawArrays** - **功能**: 使用...
**`glDepthMask`**:设置深度缓冲区写掩码。 **`glStencilMask`**:设置模板缓冲区写掩码。 **`glAlphaFunc`**:设置Alpha测试函数。 **`glStencilFunc`**:设置模板测试函数。 **`glStencilOp`**:设置模板测试...
在处理蒙版时,我们需要关注的颜色缓冲区(Color Buffer)、深度缓冲区(Depth Buffer)以及模板缓冲区(Stencil Buffer)。 颜色缓冲区存储最终像素的颜色值,而深度缓冲区用于进行遮挡测试,确保近处的物体遮挡住...
然后,设置必要的OpenGL上下文属性,比如颜色深度、深度缓冲、模板缓冲等。 2. 绑定模板缓冲:在OpenGL上下文中,使用`glEnable(GL_STENCIL_TEST)`开启模板测试,并使用`glStencilFunc()`和`glStencilOp()`函数设置...
当渲染新像素时,OpenGL会将这个掩码与当前模板缓冲区的值进行比较。根据比较结果,你可以选择允许或拒绝该像素的渲染。这在创建复杂的遮罩效果、多边形剔除或者实现分层渲染等方面非常有用。 在描述中提到的“红宝...
- **`glDepthMask`**与**`glStencilMask`**:控制深度和模板缓冲区的写入掩码。 #### Alpha与模板测试 - **`glAlphaFunc`**:设置基于Alpha值的测试条件。 - **`glStencilFunc`**与**`glStencilOp`**:设置模板测试...
片段着色器在获取数据后,通过内建的varying变量和专用的片段着色器输入变量,完成最终片段颜色的计算,并输出到帧缓冲区。 了解OpenGL可编程管道及其与GLSL的关系对于深入理解图形渲染过程至关重要,它为开发者...
蒙板,也称为模板缓冲,是一个附加的像素缓冲区,用于存储每个像素的模板值。这个模板值可以用来控制像素是否应该被绘制。通过设置不同的模板测试条件,我们可以决定哪些像素应该被渲染,哪些不应该。在OpenGLES 2.0...
模板缓冲区是一个与颜色和深度缓冲区同等大小的额外缓冲,可以用来存储每个像素的整数值,这些值可以被用来作为渲染决策的一部分。 开启模板测试非常简单,只需调用`glEnable(GL_STENCIL_TEST)`。然后,我们可以...
该结构体包含多个参数,用于定义颜色模式(RGB/RGBA或颜色索引模式)、缓冲区类型(单缓冲或多缓冲)、颜色深度、累加和模板缓冲区的位数等属性。 例如,在Win32环境下,常见的像素格式设定如下: ```c++ static ...
2. **清除操作(Buffer Clearing)**:在渲染过程中,缓冲区的清除是常见的操作,如清空颜色缓冲区或深度缓冲区,以便在新的帧开始时有一个干净的起始状态。 3. **指定值(Specified Values)**:在清除缓冲区时,...
- 设置深度缓冲区的清除深度值。 14. **`glClearStencil`** - 设置模板缓冲区的清除值。 15. **`glClipPlane`** - 定义裁剪平面,用于高级几何裁剪。 16. **`glColor`** - 设置当前颜色,用于后续绘制操作的...
**用途**:设置深度掩码,控制深度缓冲区是否可以被写入。 - **`void stencilMask(uint mask)`** - **参数**: - `mask`:无符号整型值,指定哪些模板缓冲位可以被写入。 **用途**:设置模板掩码,控制模板...
这部分通常涉及到像素格式描述符(PIXELFORMATDESCRIPTOR)的设置,包括颜色深度、缓冲区类型等参数。 - **创建OpenGL渲染窗口**: 通过MFC创建窗口,并将其与OpenGL关联起来。这一步骤包括设置窗口属性、创建渲染上...
这个函数定义了源颜色(来自绘制的对象)和目的地颜色(已存在于帧缓冲区的颜色)如何相加混合。源和目标的参数可以是多种预定义常量,如GL_ONE、GL_ZERO、GL_SRC_COLOR、GL_DST_COLOR等,这些常量代表了不同的权重...