|
该例子演示了运动模糊的效果。
以下内容是转自网上的:
原理:
引用内容
对于运动画面,将当前帧画面与上一帧画面进行alpha融合,以产生出残影——运动模糊效果。
通过使用累积缓存来完成这项工作。
OpenGL提供一个累积缓存,可以用来存储当前指定的颜色缓存里面的内容,并进行一定的运算操作。
通过函数glAccum可以对累积缓存进行操作。
glAccum介绍如下:
引用内容
void glAccum(GLenum op, GLfloat value)
op值用于指定操作类型,包括:
GL_ACCUM 从指定的颜色缓存里面读取像素数据,将其像素值(R, G, B, A)乘以value的结果加上累积缓存里面的值以后再保存到累积缓存;
GL_LOAD 从指定的颜色缓存里面读取像素数据,将其像素值乘以value的结果直接保存到累积缓存;
GL_ADD 将累积缓存里面的像素值与value相加以后保存到累积缓存;
GL_MULT 将累积缓存里面的像素值与value相乘以后保存到累积缓存;
GL_RETURN 将累积缓存里面的像素值乘以value以后保存到指定的颜色缓存;
在这个例子中,用到了GL_MULT、GL_ACCUM、GL_RETURN。
在主程序中osg:isplaySettings::instance()->setMinimumNumAccumBits(8,8,8,8);设置了积累缓冲区各位数。
然后,osgViewer::Viewer::Windows windows;
viewer.getWindows(windows);
for
(osgViewer::Viewer::Windows::iterator itr = windows.begin();
itr !=
windows.end();
++itr)
{
(*itr)->add(new MotionBlurOperation
(persistence));
}在视景体中每个图形窗体都添加了MotionBlurOperation类,MotionBlurOperation继承Operation,在virtual void operator () (osg::Object* object)方
法中如果是第一次渲染,则清楚积累缓冲区的值,glClearColor(0, 0, 0, 0);
glClear(GL_ACCUM_BUFFER_BIT);
之后,glAccum(GL_MULT, s);
glAccum(GL_ACCUM, 1 - s);
glAccum(GL_RETURN, 1.0f);通过这三个函数计算。
我们一个一个的进行说明,首先,glAccum(GL_MULT, s);积累缓冲区中的值乘以s,结果写进积累缓冲区中,glAccum(GL_ACCUM, 1 - s);然后,颜色缓冲区中的值乘以1-s,结果写入积累缓冲区中,最后,glAccum(GL_RETURN, 1.0f);把积累缓存区中的值乘以1,写入颜色缓存区中,完成运动模糊的效果,这里可以看出积累缓冲区中的值只有一份,是每一帧不同比率的一个累计,也就是说第一帧的累计效果也是存在的,只是随着帧数的增加,第一帧的影像比率趋近于0了。这几个函数中不难得出,s值越大,前几帧的效果存在的时间越长,运动模糊效果越明显,如果s趋近于1,程序将很长时间是黑屏,因为glClearColor(0, 0, 0, 0);glClear(GL_ACCUM_BUFFER_BIT);积累缓冲区颜色值为黑色,s趋近于1,第一帧的影像非常大,所以很长时间一直为最初的颜色——黑色。
这里必须要深入研究一下,glAccum应用的时刻,以上的说明中可以看出,glAccum应该是一帧中颜色缓冲区中的值计算完之后应用,在这个例子中用了otionBlurOperation,
MotionBlurOperation继承Operation。我们就看看Operation是做什么的。到了Operation的定义,说它是实现图形操作的基类,子类必须重写virtual void operator () (Object*) = 0;方法,实现相应的功能。在GraphicsContext类中typedef std::list< ref_ptr<Operation> > GraphicsOperationQueue; GraphicsOperationQueue _operations;定义了一个Operation类型的一个链表,这个链表又在什么地方应用的了?还回到GraphicsContext::runOperations()中,记得上一篇osgmemorytest例子中,提到过GraphicsContext::runOperations(),在这里实现(*(camera->getRenderer()))(this);渲染工作。这一次我们又找的了这个函数,(*_currentOperation)(this);遍历_operations这个链表,然后执行每个Operation中的operator () (Object*)方法,从runOperations()这个函数中,我们知道了osg的渲染过程,先进行渲染,然后在执行_operations中的操作。
我们回到例子中,MotionBlurOperation这个类,把它加入到了所有的图形上下文中osgViewer::Viewer::Windows windows; viewer.getWindows(windows);
for
(osgViewer::Viewer::Windows::iterator itr = windows.begin();
itr !=
windows.end();
++itr)
{
(*itr)->add(new MotionBlurOperation
(persistence));
},glAccum函数执行的时候正好和我们之前所判断的一样,先渲染,渲染后对颜色缓存区中的值进行累积。
对这个例子和积累缓冲区总算有了一些理解,但这里还存在一个问题,如果想只对场景中的某个部分做运动模糊应该如何处理???比如有一个足球场,一个运动中的足球,只对这个足球进行运动模糊处理,如何去做???
这个问题自己还没有去验证,自己想的一个大概方法是,相同位置的的两个相机,一个关注足球之外的场景,不做运动模糊处理;另外一个只关注足球,做运动模糊处理,然后,两幅场景融合为一个场景。 |
|