openGL中的FBO的一个问题

前几天公司扔给我一个刚跳走的“大牛”的代码,看的实在让我捉急。逻辑非常混乱,代码模块化做的不到位,让人怀疑是否知道什么是面向对象。(应该是所有程序员看别人代码都这样的通病吧,自己的修为尚浅,也许别人看我的也是一头包,哈哈)

正题:

//——————————————————————————————————————————

在使用openGL中的fbo时,很容易遇到“二次混合”的问题。二次混合从本质上来讲是混合顺序错误。

如下图:

这是一个很让人纠结的问题。仅通过调节混合方式是不能真正地解决的。只有适当的取近似结果、事先策划混合顺序,避免出现很严重的问题。

分享我遇到过的一些问题,以及解决方案:

首先是如果不采取任何措施,采用默认混合方式,会出现字体模糊的问题。

这种现象是在图片有像素透明度不为1或0时会出现,因为多次混合的缘故导致最终颜色出现偏差。

解决办法是在绘制FBO时,关闭混合,绘制内容结束后再恢复默认混合。

ofDisableAlphaBlending();    // 关闭混合
bookContent.draw(rtContent);
ofEnableAlphaBlending();    // 打开混合

效果:

但是,

假如在FBO里面出现了多张图片叠加的情况,这种方法就不适用了。

问题如下:

这种时候,

解决办法有两个,一是图片素材不要有(0, 1 )的透明度像素,适用正常混合进行混合,二是采用近似混合方式:

神代码:

//
    mainFbo.begin();
		ofClear(0);
		glEnable(GL_BLEND);
		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

		text1.draw(x,y);

    glDisable		(GL_BLEND);
    mainFbo.end();

/* ... ... */

// 绘制FBO
		glEnable(GL_BLEND);
		glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

		mainFbo.draw(x, y);

		glDisable(GL_BLEND);
		ofEnableAlphaBlending();

  这样的混合方式算是比较折中的方式了,一般来说不会出现问题,(比如三层嵌套就会出问题,而且FBO内部的底色会失真)

FBO套FBO,层层套下来。但是这样效率会很低很低,而且修改混合状态会影响全局混合方式,如果有一处遗忘了恢复状态,会影响其他内容的绘制。尤其是接手别人的项目的时候,如果他们的项目框架设计的不合理,很容易出现各种诡异的问题。。。。。。。。。内心已经在画诅咒圈圈...

总体来说,效果还是不错的。但是如果要做的完美,还是建议做好规划,避免出现这种棘手的情况。

时间: 2024-10-16 15:54:41

openGL中的FBO的一个问题的相关文章

OpenGL中glVertex、显示列表(glCallList)、顶点数组(Vertex array)、VBO及VAO区别

OpenGL中glVertex.显示列表(glCallList).顶点数组(Vertex array).VBO及VAO区别 1.glVertex 最原始的设置顶点方法,在glBegin和glEnd之间使用.OpenGL3.0已经废弃此方法.每个glVertex与GPU进行一次通信,十分低效. glBegin(GL_TRIANGLES); glVertex(0, 0); glVertex(1, 1); glVertex(2, 2); glEnd(); 2.显示列表(glCallList) 每个gl

OpenGL中实现双缓冲技术

在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);.这里将我们惯用的GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用双缓冲而非单缓冲. 2. 调用glutDisplayFunc(display)注册回调函数时, 在回调函数中所有绘制操作完成后调用glutSwapBuffers()交换两个缓冲区指针. 3. 调用

什么是OpenGL中的深度、深度缓存、深度测试?

原文来自http://blog.csdn.net/xiaoquanhuang/article/details/6613705 1)直观理解 深度其实就是该象素点在3d世界中距离摄象机的距离,深度缓存中存储着每个象素点(绘制在屏幕上的)的深度值!深度测试决定了是否绘制较远的象素点(或较近的象素点),通常选用较近的,而较远优先能实现透视的效果!!! 2)Z值(深度值).Z buffer(深度缓存) 下面先讲讲Z坐标.Z坐标和X.Y坐标一样.在变换.裁减和透视除法后,Z的范围为-1.0~1.0.Dep

openGL中的混合

    之前在项目中就使用过混合,但是研究的不深入,近期美术的一个需求让我下决心重新深入的研究了一下混合以及它在cocos2d-x中的使用,在这里分享给大家. 混合(blend,有些翻译书上把它称作混融,以下简称混合),在openGL中,当一个输入的片元通过了所有相关的片元测试,就可以在与颜色缓存中当前的内容通过某种方式进行合并了.最简单的,也是默认的方式,就是直接覆盖已有的值,实际上不能称作是合并.除此之外,我们也可以将帧缓存中已有的颜色与输入的片元颜色进行混合.这是在openGL流程上的定义

OpenGL中的颜色混合功能(一)

我们知道,材料属性和光照参数可以极大地增加图形的逼真度,但除此之外,我们在对现实世界进行建模时,有许多效果是通过混合颜色的方式实现的.透明的物体,像是玻璃水杯,在它后面发射过来的光会与透明物体的颜色混合在一起.这种透明在OpenGL中的实现方式,是通过首先绘制背景物体,然后把前景物体(比如水杯)与颜色缓冲区中已经存在的颜色进行混合而实现的.在这一过程中,颜色的alpha值成分发挥了重要作用. 颜色的混合功能 在一般情况下,OpenGL在渲染时把颜色值存放在颜色缓冲区中,把每个片段(像素)的深度值

OpenGL中创建聚光灯的效果

现在,我们使用如下的数组来指定一个光源的位置: // 指定光源位置的数组 GLfloat lightPos[] = {0.0f, 0.0f, 75.0f, 1.0f}; // 设置光源0的位置 glLightfv(GL_LIGHT0,GL_POSITION,lightPos); lightPos数组的最后一个值在此为1.0,它表示光源的实际位置就在(X,Y,Z)所表示的位置.在默认情况下,光线从这个位置均匀地向四周发射.如果我们把lightPos数组的最后一个值设为0.0,可以使光源看上去像是来

OpenGL中的深度、深度缓存、深度测试及保存成图片

1.深度 所谓深度,就是在openGL坐标系中,像素点Z坐标距离摄像机的距离.摄像机可能放在坐标系的任何位置,那么,就不能简单的说Z数值越大或越小,就是越靠近摄像机. 2.深度缓冲区 深度缓冲区原理就是把一个距离观察平面(近裁剪面)的深度值(或距离)与窗口中的每个像素相关联.      首先,使用glClear(GL_DEPTH_BUFFER_BIT),把所有像素的深度值设置为最大值(一般是远裁剪面).      然后,在场景中以任意次序绘制所有物体.硬件或者软件所执行的图形计算把每一个绘制表面

Opengl中矩阵和perspective/ortho的相互转换

Opengl中矩阵和perspective/ortho的相互转换 定义矩阵 Opengl变换需要用四维矩阵.我们来定义这样的矩阵. +BIT祝威+悄悄在此留下版了个权的信息说: 四维向量 首先,我们定义一个四维向量vec4. 1 /// <summary> 2 /// Represents a four dimensional vector. 3 /// </summary> 4 public struct vec4 5 { 6 public float x; 7 public f

OpenGL中的多重采样

抗锯齿处理的最大优点之一就是它能够使多边形的边缘更为平滑,使渲染效果显得更为逼真和自然.点和直线的抗锯齿处理是得到广泛支持的,但遗憾的是,对多边形的平滑处理并没有在所有平台上都得到实现.并且,即使在可以使用GL_POLYGON_SMOOTH的时候,对整个场景进行抗锯齿处理也没有想象中的那么方便.这是因为,抗锯齿处理是基于混合操作的,这就需要从前到后对所有的图元进行排序,这是十分麻烦的. 在OpenGL中还有一个功能,称为多重采样(multisampling),可以用来解决抗锯齿处理中的这个问题.