文章目录
- RenderStage::drawInner
- OSG渲染后台关系图
- OSG的渲染流程
- RenderBin::draw(renderInfo,previous)
- RenderBin::drawImplementation
- RenderLeaf::render
- osg::State::apply(const StateSet*)
- Drawable::draw(RenderInfo& renderInfo)
- Drawable::drawInner(RenderInfo& renderInfo)
- Drawable::drawImplementation
RenderStage::drawInner
void RenderStage::drawInner(osg::RenderInfo& renderInfo,RenderLeaf*& previous, bool& doCopyTexture)
{
struct SubFunc
{
static void applyReadFBO(bool& apply_read_fbo,
const FrameBufferObject* read_fbo, osg::State& state)
{
if (read_fbo->isMultisample())
{
OSG_WARN << "Attempting to read from a"
" multisampled framebuffer object. Set a resolve"
" framebuffer on the RenderStage to fix this." << std::endl;
}
if (apply_read_fbo)
{
// Bind the monosampled FBO to read from
// ogl操作:
//创建一个新的fbo
//遍历设置的_attachments,编译纹理
//ext->glBindFramebuffer(READ_FRAMEBUFFER, fboID);
//调用glDrawBuffers(GLsizei n, const GLenum *bufs);,指定在一个渲染操作中输出到多个颜色缓冲区的目标
//遍历设置的_attachments,添加附件
read_fbo->apply(state, FrameBufferObject::READ_FRAMEBUFFER);
apply_read_fbo = false;
}
}
};
osg::State& state = *renderInfo.getState();
osg::GLExtensions* ext = _fbo.valid() ? state.get<osg::GLExtensions>() : 0;
// 判断显示卡是否支持FBO
bool fbo_supported = ext && ext->isFrameBufferObjectSupported;
// 详见RenderStage::runCameraSetUp
bool using_multiple_render_targets = fbo_supported && _fbo->hasMultipleRenderingTargets();
if (!using_multiple_render_targets)
{
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
if( getDrawBufferApplyMask() )
state.glDrawBuffer(_drawBuffer);
if( getReadBufferApplyMask() )
state.glReadBuffer(_readBuffer);
#endif
}
if (fbo_supported)
{
// ogl操作:
//创建一个新的fbo
//遍历设置的_attachments,编译纹理
//ext->glBindFramebuffer(READ_FRAMEBUFFER, fboID);
//调用glDrawBuffers(GLsizei n, const GLenum *bufs);,指定在一个渲染操作中输出到多个颜色缓冲区的目标
//遍历设置的_attachments,添加附件
_fbo->apply(state);
}
// do the drawing itself.
RenderBin::draw(renderInfo,previous);
if(state.getCheckForGLErrors()!=osg::State::NEVER_CHECK_GL_ERRORS)
{
if (state.checkGLErrors("after RenderBin::draw(..)"))
{
if ( ext )
{
GLenum fbstatus = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
if ( fbstatus != GL_FRAMEBUFFER_COMPLETE_EXT )
{
OSG_NOTICE<<"RenderStage::drawInner(,) FBO status = 0x"<<std::hex<<fbstatus<<std::dec<<std::endl;
}
}
}
}
// 以下是copy纹理,写image,生成mipmap等操作
const FrameBufferObject* read_fbo = fbo_supported ? _fbo.get() : 0;
bool apply_read_fbo = false;
//glBlitFramebuffer用于在帧缓冲对象之间快速复制像素数据
if (fbo_supported && _resolveFbo.valid() && ext->glBlitFramebuffer)
{
GLbitfield blitMask = 0;
bool needToBlitColorBuffers = false;
//find which buffer types should be copied
for (FrameBufferObject::AttachmentMap::const_iterator
it = _resolveFbo->getAttachmentMap().begin(),
end =_resolveFbo->getAttachmentMap().end(); it != end; ++it)
{
switch (it->first)
{
case Camera::DEPTH_BUFFER:
blitMask |= GL_DEPTH_BUFFER_BIT;
break;
case Camera::STENCIL_BUFFER:
blitMask |= GL_STENCIL_BUFFER_BIT;
break;
case Camera::PACKED_DEPTH_STENCIL_BUFFER:
blitMask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
break;
case Camera::COLOR_BUFFER:
blitMask |= GL_COLOR_BUFFER_BIT;
break;
default:
needToBlitColorBuffers = true;
break;
}
}
// Bind the resolve framebuffer to blit into.
_fbo->apply(state, FrameBufferObject::READ_FRAMEBUFFER);
_resolveFbo->apply(state, FrameBufferObject::DRAW_FRAMEBUFFER);// 如果不使用MSFBO则为0
if (blitMask)
{
// Blit to the resolve framebuffer.
// Note that (with nvidia 175.16 windows drivers at least) if the read
// framebuffer is multisampled then the dimension arguments are ignored
// and the whole framebuffer is always copied.
// 将READ_FRAMEBUFFER拷贝到DRAW_FRAMEBUFFER
ext->glBlitFramebuffer(
static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),
static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),
static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),
static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),
blitMask, GL_NEAREST);
}
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)
// 拷贝多传输颜色附件
if (needToBlitColorBuffers)
{
for (FrameBufferObject::AttachmentMap::const_iterator
it = _resolveFbo->getAttachmentMap().begin(),
end =_resolveFbo->getAttachmentMap().end(); it != end; ++it)
{
osg::Camera::BufferComponent attachment = it->first;
if (attachment >=osg::Camera::COLOR_BUFFER0)
{
state.glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));
state.glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));
ext->glBlitFramebuffer(
static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),
static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),
static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),
static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
}
// reset the read and draw buffers? will comment out for now with the assumption that
// the buffers will be set explicitly when needed elsewhere.
// glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
// glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
}
#endif
apply_read_fbo = true;
read_fbo = _resolveFbo.get();
using_multiple_render_targets = read_fbo->hasMultipleRenderingTargets();
}
// now copy the rendered image to attached texture.
if (doCopyTexture)
{
if (read_fbo) SubFunc::applyReadFBO(apply_read_fbo, read_fbo, state);
copyTexture(renderInfo);
}
//如果有设置附件的image,则将附件读入image中
for(std::map< osg::Camera::BufferComponent, Attachment>::const_iterator itr = _bufferAttachmentMap.begin();
itr != _bufferAttachmentMap.end();
++itr)
{
if (itr->second._image.valid())
{
if (read_fbo) SubFunc::applyReadFBO(apply_read_fbo, read_fbo, state);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
if (using_multiple_render_targets)
{
int attachment=itr->first;
if (attachment==osg::Camera::DEPTH_BUFFER || attachment==osg::Camera::STENCIL_BUFFER) {
// assume first buffer rendered to is the one we want
glReadBuffer(read_fbo->getMultipleRenderingTargets()[0]);
} else {
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));
}
} else {
if (_readBuffer != GL_NONE)
{
glReadBuffer(_readBuffer);
}
}
#endif
GLenum pixelFormat = itr->second._image->getPixelFormat();
if (pixelFormat==0) pixelFormat = _imageReadPixelFormat;
if (pixelFormat==0) pixelFormat = GL_RGB;
GLenum dataType = itr->second._image->getDataType();
if (dataType==0) dataType = _imageReadPixelDataType;
if (dataType==0) dataType = GL_UNSIGNED_BYTE;
itr->second._image->readPixels(static_cast<int>(_viewport->x()),
static_cast<int>(_viewport->y()),
static_cast<int>(_viewport->width()),
static_cast<int>(_viewport->height()),
pixelFormat, dataType);
}
}
if (fbo_supported)
{
// 是否需要解除绑定回复默认帧缓冲区
if (getDisableFboAfterRender())
{
// switch off the frame buffer object
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
}
doCopyTexture = true;
}
if (fbo_supported && _camera.valid())
{
// now generate mipmaps if they are required.
const osg::Camera::BufferAttachmentMap& bufferAttachments = _camera->getBufferAttachmentMap();
for(osg::Camera::BufferAttachmentMap::const_iterator itr = bufferAttachments.begin();
itr != bufferAttachments.end();
++itr)
{
if (itr->second._texture.valid() && itr->second._mipMapGeneration)
{
state.setActiveTextureUnit(0);//设置当前纹理单元
state.applyTextureAttribute(0, itr->second._texture.get());
//用于生成指定纹理的多级渐进纹理(Mipmap):void glGenerateMipmap(GLenum target);
//target:GL_TEXTURE_2D,GL_TEXTURE_CUBE_MAP,GL_TEXTURE_3D
ext->glGenerateMipmap(itr->second._texture->getTextureTarget());
}
}
}
}
OSG渲染后台关系图
- 如果我们需要自己创建新的派生自Drawable的对象(就像osgText中所实现的),drawable几何体对象的具体实现在于drawImplementation函数。
- 如果想自己创建一种新的渲染属性(派生自StateAttribute),渲染属性的具现函数为StateAttribute::apply(State&),所有的渲染属性都重写了这一函数,以实现自己的功能。
- OSG渲染后台与用户层的接口是摄像机类(Camera)。场景中至少有一个主摄像机,它关联了一个图形设备(GraphicsContext,通常是窗口),以及一个渲染器(Renderer);我们可以在场景树中(或者别的视图View中,对于复合视景器而言)添加更多的摄像机,它们可以关联相同的或者其它的图形设备,但都会配有单独的渲染器,用以保存该摄像机的筛选设置、显示器设置等信息。
- 场景筛选和绘制的工作由渲染器来完成,而图形设备GraphicsContext则负责根据不同时机的选择,调用渲染器的相关函数。例如在单线程模式中,ViewerBase::renderingTraversals函数依次执行Renderer::cull和Renderer::draw函数(后者通过GraphicsContext::runOperations调用),而在多线程模型中调用者的关系将更加错综复杂。
- OSG渲染后台的调度中心是场景视图(SceneView),它负责保存和执行筛选访问器(CullVisitor)。CullVisitor负责遍历并裁减场景,同时在遍历过程中构建对于场景绘制至关重要的渲染树和状态树;生成的状态树以StateGraph为根节点和各级子节点(其中保存场景树的渲染状态StateSet数据),以RenderLeaf为末端叶节点的内容(其中保存场景树中的几何体Drawable对象);渲染树则以RenderStage为根节点,RenderBin为各级子节点,根据渲染顺序和方法的设定,状态树中的节点和渲染叶(RenderLeaf)被记录到RenderStage和各级RenderBin中;SceneView负责保存和维护状态树和渲染树。
- 绘制场景时,渲染树中的各级节点将取出保存的渲染叶数据,传递给OSG状态机(State),其中OSG状态机(State)是OpenGL状态机制的封装和实现,也是场景绘制的核心元件。状态机取得渲染叶中的几何数据之后,再向根部遍历状态树,取得该几何体绘制相关的所有渲染状态设置,并亲自或者交由StateAttribute派生类完成渲染状态的实际设定,以及场景元素的实际绘制工作。此时用到的就已经是我们耳熟能详的各种OpenGL函数了。
OSG的渲染流程
1、渲染树的作用是遍历各个渲染元(RenderBin),并按照指定的顺序执行其中各个渲染叶的渲染函数(RenderLeaf::render)。
2、状态树保存了从根节点到当前渲染叶的路径,遍历这条路径并收集所有的渲染属性数据,通过StateGraph::moveStateGraph关闭父节点所有状态,并打开当前节点所有状态,即可获得当前渲染叶渲染所需的所有OpenGL状态数据。
3、渲染叶的渲染函数(RenderLeaf::render)负责向状态机(osg::State)传递渲染状态数据,进而由渲染属性类本身完成参数在OpenGL中的注册和加载工作(StateAttribute::apply);渲染叶还负责调用几何体(Drawable)的绘制函数(drawImplementation),传递顶点和索引数据并完成场景的绘制工作。
RenderBin::draw(renderInfo,previous)
void RenderBin::draw(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
{
renderInfo.pushRenderBin(this);
if (_drawCallback.valid())
{
_drawCallback->drawImplementation(this,renderInfo,previous);
}
else drawImplementation(renderInfo,previous);
renderInfo.popRenderBin();
}
RenderBin::drawImplementation
void RenderBin::drawImplementation(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
{
osg::State& state = *renderInfo.getState();
// OSG_NOTICE<<"begin RenderBin::drawImplementation "<<className()<<" sortMode "<<getSortMode()<<std::endl;
unsigned int numToPop = (previous ? StateGraph::numToPop(previous->_parent) : 0);
if (numToPop>1) --numToPop;
unsigned int insertStateSetPosition = state.getStateSetStackSize() - numToPop;
if (_stateset.valid())
{
state.insertStateSet(insertStateSetPosition, _stateset.get());
}
// 遍历所有的子渲染元(RenderBin::_bins),其中渲染顺序号小于0的渲染元将在这里执行它们的RenderBin::draw函数,
// 由于draw函数内部调用了drawImplementation,因此这构成了一个递归调用,直至渲染树遍历至末端节点。
// 在用户程序中,渲染顺序号的设置使用StateSet::setRenderBinDetails函数(RenderBinList的key)。
// draw first set of draw bins.
RenderBinList::iterator rbitr;
for(rbitr = _bins.begin();
rbitr!=_bins.end() && rbitr->first<0;
++rbitr)
{
rbitr->second->draw(renderInfo,previous);
}
// 遍历当前RenderBin所保存的所有渲染叶(RenderBin::_renderLeafList),执行RenderLeaf::render函数,实现场景的绘制。
// 通常只有被设置为“DepthSortedBin”的渲染元会选择保存渲染叶而非状态节点(StateGraph),因为这样便于按照深度值排序对象。
// draw fine grained ordering.
for(RenderLeafList::iterator rlitr= _renderLeafList.begin();
rlitr!= _renderLeafList.end();
++rlitr)
{
RenderLeaf* rl = *rlitr;
rl->render(renderInfo,previous);
previous = rl;
}
bool draw_forward = true; //(_sortMode!=SORT_BY_STATE) || (state.getFrameStamp()->getFrameNumber() % 2)==0;
// 遍历当前RenderBin所保存的所有状态节点(RenderBin::_stateGraphList),
// 获取其中保存的RenderLeaf对象(保存为StateGraph::_leaves),并执行其render函数。
// draw coarse grained ordering.
if (draw_forward)
{
for(StateGraphList::iterator oitr=_stateGraphList.begin();
oitr!=_stateGraphList.end();
++oitr)
{
for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
dw_itr != (*oitr)->_leaves.end();
++dw_itr)
{
RenderLeaf* rl = dw_itr->get();
rl->render(renderInfo,previous);
previous = rl;
}
}
}
else
{
for(StateGraphList::reverse_iterator oitr=_stateGraphList.rbegin();
oitr!=_stateGraphList.rend();
++oitr)
{
for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
dw_itr != (*oitr)->_leaves.end();
++dw_itr)
{
RenderLeaf* rl = dw_itr->get();
rl->render(renderInfo,previous);
previous = rl;
}
}
}
//遍历所有的子渲染元(RenderBin::_bins),其中渲染顺序号大于0的渲染元此时才执行它们的RenderBin::draw函数。
// draw post bins.
for(;
rbitr!=_bins.end();
++rbitr)
{
rbitr->second->draw(renderInfo,previous);
}
if (_stateset.valid())
{
state.removeStateSet(insertStateSetPosition);
// state.apply();
}
// OSG_NOTICE<<"end RenderBin::drawImplementation "<<className()<<std::endl;
}
- 由此可知,渲染树中最先被绘制的将是那些顺序号小于0的末端RenderBin节点,其次则依次是顺序号等于0的末端节点,大于0的末端节点,小于0的倒数第二级节点……而作为渲染树根节点的RenderStage中保存的数据将最后被渲染。
- 渲染树同一层中不可能存在渲染顺序号相同的渲染元,因为使用setRenderBinDetails设置了相同数字参量的StateSet对象被构建成状态节点(StateGraph)之后,将插入到同一个RenderBin中,而不同name则是不同层级的renderbin。
RenderLeaf::render
- 渲染叶RenderLeaf是OSG渲染后台中几何体(Drawable)对象的唯一管理者。
- 而这里的render函数主要负责获取之前保存的Drawable指针,并将它们传递给负责渲染状态处理的State类,以及执行Drawable::draw函数。
void RenderLeaf::render(osg::RenderInfo& renderInfo,RenderLeaf* previous)
{
osg::State& state = *renderInfo.getState();
// don't draw this leaf if the abort中止 rendering flag has been set.
if (state.getAbortRendering())
{
//cout << "early abort"<<endl;
return;
}
if (previous)
{
// apply matrices if required.
state.applyProjectionMatrix(_projection.get());
state.applyModelViewMatrix(_modelview.get());
// 如果当前渲染叶与上一次处理的渲染叶父节点不同,则需要遍历状态树中相应的路径,
// 并更新State状态机中保存的渲染状态数据(采用std::map类型,分别名为_modeMap和_attributeMap)。
// apply state if required.
StateGraph* prev_rg = previous->_parent;
StateGraph* prev_rg_parent = prev_rg->_parent;
StateGraph* rg = _parent;
if (prev_rg_parent!=rg->_parent)
{
// 它负责清除上一次使用的各种渲染状态,再沿着状态树中的路径,依次添加当前渲染叶所需的数据。
// 最后执行函数State::apply(const StateSet*),由OSG状态机处理并执行相应的OpenGL指令。
StateGraph::moveStateGraph(state,prev_rg_parent,rg->_parent);
// send state changes and matrix changes to OpenGL.
state.apply(rg->getStateSet());
}
else if (rg!=prev_rg)
{
// send state changes and matrix changes to OpenGL.
state.apply(rg->getStateSet());
}
// 设置着色器osg内置变量
// if we are using osg::Program which requires OSG's generated uniforms to track
// modelview and projection matrices then apply them now.
if (state.getUseModelViewAndProjectionUniforms()) state.applyModelViewAndProjectionUniformsIfRequired();
// 执行此渲染叶所保存的Drawable对象的draw函数,完成几何体的绘制。
// Geometry对象将在这一函数中(实际上是Drawable::drawImplementation)向状态机传递顶点和索引数据,
// 并交由状态机对象来完成几何数据的绘制。
// draw the drawable
_drawable->draw(renderInfo);
}
else
{
// apply matrices if required.
state.applyProjectionMatrix(_projection.get());
state.applyModelViewMatrix(_modelview.get());
// apply state if required.
StateGraph::moveStateGraph(state,NULL,_parent->_parent);
state.apply(_parent->getStateSet());
// if we are using osg::Program which requires OSG's generated uniforms to track
// modelview and projection matrices then apply them now.
if (state.getUseModelViewAndProjectionUniforms()) state.applyModelViewAndProjectionUniformsIfRequired();
// draw the drawable
_drawable->draw(renderInfo);
}
if (_dynamic)
{
state.decrementDynamicObjectCount();
}
// OSG_NOTICE<<"RenderLeaf "<<_drawable->getName()<<" "<<_depth<<std::endl;
}
osg::State::apply(const StateSet*)
Drawable::draw(RenderInfo& renderInfo)
inline void Drawable::draw(RenderInfo& renderInfo) const
{
State& state = *renderInfo.getState();
bool useVertexArrayObject = state.useVertexArrayObject(_useVertexArrayObject);
if (useVertexArrayObject)
{
unsigned int contextID = renderInfo.getContextID();
VertexArrayState* vas = _vertexArrayStateList[contextID].get();
if (!vas)
{
_vertexArrayStateList[contextID] = vas = createVertexArrayState(renderInfo);
}
else
{
// vas->setRequiresSetArrays(getDataVariance()==osg::Object::DYNAMIC);
}
State::SetCurrentVertexArrayStateProxy setVASProxy(state, vas);
// 但凡是使用ogl核心模式,都要使用vao
state.bindVertexArrayObject(vas);
drawInner(renderInfo);
vas->setRequiresSetArrays(getDataVariance()==osg::Object::DYNAMIC);
return;
}
// TODO, add check against whether VAO is active and supported
if (state.getCurrentVertexArrayState())
{
//OSG_NOTICE<<"state.getCurrentVertexArrayState()->getVertexArrayObject()="<< state.getCurrentVertexArrayState()->getVertexArrayObject()<<std::endl;
state.bindVertexArrayObject(state.getCurrentVertexArrayState());
}
// 使用显示列表
#ifdef OSG_GL_DISPLAYLISTS_AVAILABLE
if (!state.useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects) && _useDisplayList)
{
// get the contextID (user defined ID of 0 upwards) for the
// current OpenGL context.
unsigned int contextID = renderInfo.getContextID();
// get the globj for the current contextID.
GLuint& globj = _globjList[contextID];
if( globj == 0 )
{
// compile the display list
globj = generateDisplayList(contextID, getGLObjectSizeHint());
glNewList( globj, GL_COMPILE );
drawInner(renderInfo);
glEndList();
}
// call the display list
glCallList( globj);
}
else
#endif
{
// if state.previousVertexArrayState() is different than currentVertexArrayState bind current
// OSG_NOTICE<<"Fallback drawInner()........................"<<std::endl;
drawInner(renderInfo);
}
}
#endif
Drawable::drawInner(RenderInfo& renderInfo)
inline void drawInner(RenderInfo& renderInfo) const
{
if (_drawCallback.valid())
_drawCallback->drawImplementation(renderInfo,this);
else
drawImplementation(renderInfo);
}
Drawable::drawImplementation
/** drawImplementation(RenderInfo&) is a pure virtual method for the actual implementation of OpenGL drawing calls, such as vertex arrays and primitives, that
* must be implemented in concrete subclasses of the Drawable base class, examples include osg::Geometry and osg::ShapeDrawable.
* drawImplementation(RenderInfo&) is called from the draw(RenderInfo&) method, with the draw method handling management of OpenGL display lists,
* and drawImplementation(RenderInfo&) handling the actual drawing itself.
* renderInfo : The osg::RenderInfo object that encapsulates the current rendering information including the osg::State OpenGL state for the current graphics context. */
virtual void drawImplementation(RenderInfo& /*renderInfo*/) const {}