标签:
上面是一个Composition资源.在解析时,主要是使用CompositionPass,CompositionTargetPass,CompositionTechnique,Compositor,而在渲染时,使用RenderSystemOperation,TargetOperation,CompositorInstance,CompositionChain.管理Composition用CompositionManage.
一次渲染环境设置,包含基本渲染设置,根据PassType不同,生成不同的RenderSystemOperation,主要有如下几种:RSClearOperation, RSStencilOperation, RSSetSchemeOperation, RSRestoreSchemeOperation, RSQuadOperation, RenderSystemOperation.下面以opengl的API举例.
当PassType为PT_CLEAR,对应RSClearOperation,用到的属性为mClearBuffers, mClearColour, mClearDepth, mClearStencil.在opengl中,对应操作FFP的API是glClear(color|depth,stencil).
enum PassType { PT_CLEAR, /// Clear target to one colour PT_STENCIL, /// Set stencil operation PT_RENDERSCENE, /// Render the scene or part of it PT_RENDERQUAD, /// Render a full screen quad PT_RENDERCUSTOM /// Render a custom sequence };
当PassType为PT_RENDERSCENE时,用到属性mFirstRenderQueue,mLastRenderQueue
当PassType为PT_STENCIL,用到mStencilCheck, mStencilFunc, mStencilRefValue, mStencilMask, mStencilFailOp, mStencilDepthFailOp, mStencilPassOp, mStencilTwoSidedOperation, mStencilReadBackAsTexture,属性虽然多,但是对应Opengl里FFP的API就是void glStencilFunc (GLenum func, GLint ref, GLuint mask);void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass),glStencilMask,前面二个函数还有一个区别正反面的版本,上面的属性就是对这几个函数的封装.
上面的几种一般不用,下面这种是很常用的.
当PassType为PT_RENDERQUAD时,用到属性mMaterial, mInputs, mQuadLeft, Top, Right, Bottom.不同于上面一般对应的是FFP(固定管线功能),这个操作主要是取出mMaterial里的VP,FP,根据自己编写的VP与FP来渲染,其中mInput是VP与FP要用到的纹理.输出到CompositionTargetPass对应的mOutputName.
对应上面的图,一个CompositionTargetPass包含一些基本设置与一个或多个CompositionPass,对应生成CompositorInstance::TargetOperation.如果说CompositionPass是渲染的环境参数设置,而CompositionTargetPass就是在一个或多个CompositionPass渲染前的特定渲染环境参数设置.
CompositionTargetPass与CompositionPass在资源文件里,都有一个input,但是他们之间的含义是不同的,在CompositionPass里的input是对应的纹理里的着色器代码要用到的纹理编号,而在CompositionTargetPass里input表示一个CompositionTargetPass::InputMode枚举.
InputMode枚举只有二个值,一个是IM_NONE,一个是IM_PREVIOUS,对应上图第一个target就是IM_PREVIOUS,后面的都是IM_NONE.其中IM_PREVIOUS表示当前窗口内容,而IM_NONE表示清空当前窗口.
enum InputMode { IM_NONE, /// No input IM_PREVIOUS /// Output of previous Composition in chain };
其中mOutputName对应CompositionTechnique里的mTextureDefinitions里的纹理,CompositionTargetPass包含的CompositionPass最后渲染的内容就保存在这个纹理中.CompositionTargetPass所对应的RenderTarget也是这个纹理.
对应上面的图,一个CompositionTechnique包含多个CompositionTargetPass,在CompositionTargetPass前,我们可以看到一些纹理说明与设置,这里的纹理与一般的不同纹理不同,我们后面可以看到,在这里CompositionTechnique::TextureDefinition生成的纹理都指定了TextureUsage为TU_RENDERTARGET,指定这个是说明这是一个每桢更新的纹理,同时会附带一个RenderTexture(RenderTarget的派生类)对象,就是说,每定义一个TextureDefinition,就生成一个RenderTarget,如果TextureDefinition对应有多个PixelFormat,那么对应的RenderTexture为MultiRenderTarget.
CompositionTechnique保存多个或一个CompositionTargetPass和一个mOutputTarget(也为CompositionTargetPass类型),也就是上图中最后一个CompositionTargetPass,针对这个处理后面会看到有些不同.
class TextureDefinition : public CompositorInstAlloc { public: String name; //Texture definition being a reference is determined by these two fields not being empty. String refCompName; //If a reference, the name of the compositor being referenced String refTexName; //If a reference, the name of the texture in the compositor being referenced size_t width; // 0 means adapt to target width size_t height; // 0 means adapt to target height float widthFactor; // multiple of target width to use (if width = 0) float heightFactor; // multiple of target height to use (if height = 0) PixelFormatList formatList; // more than one means MRT bool fsaa; // FSAA enabled; true = determine from main target (if render_scene), false = disable bool hwGammaWrite; // Do sRGB gamma correction on write (only 8-bit per channel formats) uint16 depthBufferId;//Depth Buffer‘s pool ID. (unrelated to "pool" variable below) bool pooled; // whether to use pooled textures for this one TextureScope scope; // Which scope has access to this texture TextureDefinition() :width(0), height(0), widthFactor(1.0f), heightFactor(1.0f), fsaa(true), hwGammaWrite(false), depthBufferId(1), pooled(false), scope(TS_LOCAL) {} };
CompositionTechnique列表.对应CompositorInstance,分别处理资源与渲染.
其中mGlobalTextures与mGlobalMRTs分别是CompositionTechnique里的TextureDefinition列表集合,TextureDefinition如果PixelFormat只有一个,加入mGlobalTextures中,如果有多个,加入mGlobalMRTs中.
Compositor的操纵类,Compositor对应资源文件里相应结构.而CompositorInstance是对Compositor数据渲染化.CompositorInstance用对应Compositor最合适的CompositionTechnique进行处理.
TargetOperation定义在此类中,用于设置可视化mask,lod bias level, shadow enable, material scheme等.
class TargetOperation { public: TargetOperation() { } TargetOperation(RenderTarget *inTarget): target(inTarget), currentQueueGroupID(0), visibilityMask(0xFFFFFFFF), lodBias(1.0f), onlyInitial(false), hasBeenRendered(false), findVisibleObjects(false), materialScheme(MaterialManager::DEFAULT_SCHEME_NAME), shadowsEnabled(true) { } /// Target RenderTarget *target; /// Current group ID int currentQueueGroupID; /// RenderSystem operations to queue into the scene manager, by /// uint8 RenderSystemOpPairs renderSystemOperations; /// Scene visibility mask /// If this is 0, the scene is not rendered at all uint32 visibilityMask; /// LOD offset. This is multiplied with the camera LOD offset /// 1.0 is default, lower means lower detail, higher means higher detail float lodBias; /** A set of render queues to either include or exclude certain render queues. */ typedef std::bitset<RENDER_QUEUE_COUNT> RenderQueueBitSet; /// Which renderqueues to render from scene RenderQueueBitSet renderQueues; /** @see CompositionTargetPass::mOnlyInitial */ bool onlyInitial; /** "Has been rendered" flag; used in combination with onlyInitial to determine whether to skip this target operation. */ bool hasBeenRendered; /** Whether this op needs to find visible scene objects or not */ bool findVisibleObjects; /** Which material scheme this op will use */ String materialScheme; /** Whether shadows will be enabled */ bool shadowsEnabled; };
RenderSystemOperation类也定义在这个类中,不同RenderSystemOperation的子类对应不同的渲染API或参数设置,如glClear, glStencilFunc这些.
class _OgreExport RenderSystemOperation : public CompositorInstAlloc { public: virtual ~RenderSystemOperation(); /// Set state to SceneManager and RenderSystem virtual void execute(SceneManager *sm, RenderSystem *rs) = 0; };
CompositorInstance负责Composition操作,主要包含把CompositionTargetPass转化成TargetOperation,把CompositionPass转化成RenderSystemOperation.
CompositorChain实现接口RenderTargetListener,Viewport::Listener,这样就可以监听Viewport与RenderTarget,在CompositionChain初始化时,CompositorChain会增加对应Viewport与对应Viewport的RenderTarget的监视.
这样,在Root更新RenderTarget(一般和主视图关联)时,RenderTarget更新前会先通知CompositorChain, CompositorChain生成的RenderTarget最终替换前RenderTarget(一般和主视图关联).
CompositorChain对应一个Viewport对应,通过addCompositor注册compositor到viewport对应的CompositorChain,在第一个compositor注册到Viewport时,生成CompositorChain,注册CompositorChain到对应Viewport与Viewport的RenderTarget.
CompositorChain负责渲染.其中定义了RQListener,注册当前CompositionChain到当前场景.截获场景更新.
class _OgreExport RQListener: public RenderQueueListener { public: RQListener() : mOperation(0), mSceneManager(0), mRenderSystem(0), mViewport(0) {} /** @copydoc RenderQueueListener::renderQueueStarted */ virtual void renderQueueStarted(uint8 queueGroupId, const String& invocation, bool& skipThisInvocation); /** @copydoc RenderQueueListener::renderQueueEnded */ virtual void renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation); /** Set current operation and target. */ void setOperation(CompositorInstance::TargetOperation *op,SceneManager *sm,RenderSystem *rs); /** Notify current destination viewport. */ void notifyViewport(Viewport* vp) { mViewport = vp; } /** Flush remaining render system operations. */ void flushUpTo(uint8 id); private: CompositorInstance::TargetOperation *mOperation; SceneManager *mSceneManager; RenderSystem *mRenderSystem; Viewport* mViewport; CompositorInstance::RenderSystemOpPairs::iterator currentOp, lastOp; };
注意每个CompositionTechnique一般第一个是InputMode为IM_PREVIOUS的CompositionTargetPass,在CompositionChain中,就是上一个CompositionTechnique最后一个为mOutputTarget(上图最后一个为target_out)的CompositionTargetPass.这样通过CompositionChain就可以把每个CompositionTechnique的渲染组合起来.
上面是各个Compositor类的说明,我们从下面来看下,Ogre如何组织这些类进行渲染.
1.资源文件解析.当ResourceGroupManager::initialiseResourceGroup后,对文件解析,解析成多个结点,对Compositor节点解析.具体参照CompositorTranslator, CompositionTechniqueTranslator, CompositionTargetPassTranslator, CompositionPassTranslator.解析完后Compositor内部数据Technique,TargetPass,Pass已经生成.
class _OgreExport CompositorTranslator : public ScriptTranslator { protected: Compositor *mCompositor; public: CompositorTranslator(); void translate(ScriptCompiler *compiler, const AbstractNodePtr &node); }; class _OgreExport CompositionTechniqueTranslator : public ScriptTranslator { protected: CompositionTechnique *mTechnique; public: CompositionTechniqueTranslator(); void translate(ScriptCompiler *compiler, const AbstractNodePtr &node); }; class _OgreExport CompositionTargetPassTranslator : public ScriptTranslator { protected: CompositionTargetPass *mTarget; public: CompositionTargetPassTranslator(); void translate(ScriptCompiler *compiler, const AbstractNodePtr &node); }; class _OgreExport CompositionPassTranslator : public ScriptTranslator { protected: CompositionPass *mPass; public: CompositionPassTranslator(); void translate(ScriptCompiler *compiler, const AbstractNodePtr &node); };
2.在用户创建场景时,调用CompositionManage注册Compositor到对应Viewport中,首先得到与一个与Viewport对应的CompositionChain对象(有则返回,无则新增),并且添加对Viewport与此对应Viewport的RenderTarget的监听.并对CompositionChain对象进行相关初始化,以及根据传入的Composition生成一一对应的CompositorInstance对象.
CompositorChain::CompositorChain(Viewport *vp): mViewport(vp), mOriginalScene(0), mDirty(true), mAnyCompositorsEnabled(false) { assert(vp); mOldClearEveryFrameBuffers = vp->getClearBuffers(); vp->addListener(this); createOriginalScene(); vp->getTarget()->addListener(this); }
3.当我们通过CompositionManage设置某个Compositor启用后,对应的OgreCompositorInstance调用createResources,根据Compositor里的Technique得到mTextureDefinitions,也就是第一张图上面的三个Texture定义,填充对应mLocalTextures与mLocalMRTs数据,这些Textur创建如前面指出过,都是TU_RENDERTARGET用途,附加一个对应RenderTexture.
在这里,大家可以参看一下RTT相关,在OpenGL中,相关实现方法有很多,PBuffer,FBO,Copy.在这里,根据大家选择RTT模式,在后台生成RenderTexture不同子类如GLPBRenderTexture,GLFBORenderTexture,GLCopyingRenderTexture.如果硬件允许,尽量选择FBO.其中FBO具体用法可以参看WebGL 利用FBO完成立方体贴图。 初试PyOpenGL三 (Python+OpenGL)GPGPU基本运算与乒乓技术.
假定使用opengl,FBO渲染,可以看下GLFBORenderTexture相关接口.大家可以看下opengl API如glFramebufferTexture,glBindFramebufferEXT的使用.
class _OgreGLExport GLFBORenderTexture: public GLRenderTexture { public: GLFBORenderTexture(GLFBOManager *manager, const String &name, const GLSurfaceDesc &target, bool writeGamma, uint fsaa); virtual void getCustomAttribute(const String& name, void* pData); /// Override needed to deal with multisample buffers virtual void swapBuffers(); /// Override so we can attach the depth buffer to the FBO virtual bool attachDepthBuffer( DepthBuffer *depthBuffer ); virtual void detachDepthBuffer(); virtual void _detachDepthBuffer(); protected: GLFrameBufferObject mFB; };
4.Root更新RenderTarget时,对应RenderTarget在更新前,查找监听本RenderTarget的CompositionChain对象,CompositionChain首先调用_complie完成对之上所有CompositorInstance对象按顺序链接成链表,并把对应链表从前按后调用CompositorInstance::__compileTargetOperations填充到CompositionChain里的TargetOperation列表对象mCompiledState中.
其中CompositorInstance里Technique每个CompositionTargetPass生成一个对应的TargetOperation对象,根据CompositionTargetPass的outputName传入TargetOperation的RenderTarget,还需要注意你生成第一个CompositionTargetPass(上图第一个CompositionTargetPass,InputMode为IM_PREVIOUS),会引发链接上一个CompositorInstance调用_compileOutputOperation到TargetOperation中.
这个过程比较容易理解,一个CompositorInstance,一般一个Pass要求是当前桢缓冲内容,后面是Pass合成,最后是输出Pass,那么在CompositorInstance链接表,后一个Pass要求的输出就是前一个Pass的最后输出.
TargetOperation只是针对CompositionTargetPass,CompositionTargetPass下的CompositionPass才包含每次渲染时渲染环境的精确设置,包含清空缓冲区,设置模板缓冲,或者对应上面最常用的PT_RENDERQUAD里针对着色器设置正确的纹理,所以在TargetOperation生成后,还需要针对CompositionTargetPass里的CompositionPass生成对应的RenderSystemOperation,如同CompositionPass类的说明,相应过程参照CompositorInstance::collectPasses.
void CompositorInstance::_compileTargetOperations(CompiledState &compiledState) { /// Collect targets of previous state if(mPreviousInstance) mPreviousInstance->_compileTargetOperations(compiledState); /// Texture targets CompositionTechnique::TargetPassIterator it = mTechnique->getTargetPassIterator(); while(it.hasMoreElements()) { CompositionTargetPass *target = it.getNext(); TargetOperation ts(getTargetForTex(target->getOutputName())); /// Set "only initial" flag, visibilityMask and lodBias according to CompositionTargetPass. ts.onlyInitial = target->getOnlyInitial(); ts.visibilityMask = target->getVisibilityMask(); ts.lodBias = target->getLodBias(); ts.shadowsEnabled = target->getShadowsEnabled(); ts.materialScheme = target->getMaterialScheme(); /// Check for input mode previous if(target->getInputMode() == CompositionTargetPass::IM_PREVIOUS) { /// Collect target state for previous compositor /// The TargetOperation for the final target is collected separately as it is merged /// with later operations mPreviousInstance->_compileOutputOperation(ts); } /// Collect passes of our own target collectPasses(ts, target); compiledState.push_back(ts); } }
5.还在RenderTarget(一般会主视图)更新前_complie后,针对CompositionChain已经被解析成一个个TargetOperation对象.然后会针对TargetOperation设置可视化mask,lod bias level,shadow enable,material scheme等.
在这过程中,注意CompositorChain::RQListener这个对象,在TargetOperation中的RenderTarget更新之前,会把当前场景与TargetOperation中的RenderSystemOperation都关联到CompositorChain::RQListener中,并把CompositorChain::RQListener注册到当前场景(SceneManager::addRenderQueueListener).记住这步,后面会转到这个地方.
void CompositorChain::preTargetOperation(CompositorInstance::TargetOperation &op, Viewport *vp, Camera *cam) { if (cam) { SceneManager *sm = cam->getSceneManager(); /// Set up render target listener mOurListener.setOperation(&op, sm, sm->getDestinationRenderSystem()); mOurListener.notifyViewport(vp); /// Register it sm->addRenderQueueListener(&mOurListener); /// Set whether we find visibles mOldFindVisibleObjects = sm->getFindVisibleObjects(); sm->setFindVisibleObjects(op.findVisibleObjects); /// Set LOD bias level mOldLodBias = cam->getLodBias(); cam->setLodBias(cam->getLodBias() * op.lodBias); } // Set the visibility mask mOldVisibilityMask = vp->getVisibilityMask(); vp->setVisibilityMask(op.visibilityMask); /// Set material scheme mOldMaterialScheme = vp->getMaterialScheme(); vp->setMaterialScheme(op.materialScheme); /// Set shadows enabled mOldShadowsEnabled = vp->getShadowsEnabled(); vp->setShadowsEnabled(op.shadowsEnabled); /// XXX TODO //vp->setClearEveryFrame( true ); //vp->setOverlaysEnabled( false ); //vp->setBackgroundColour( op.clearColour ); }
6.针对TargetOperation中的RenderTarget更新开始,通过我们原来最常见的渲染顺序从RenderTarget->Viewport->SceneManager.到了这里,场景开始调用fireRenderQueueStarted会调用所有注册的RenderQueueListener.
在这,第五步的RQListener开始调用renderQueueStarted方法,在这方法里,调用flushUpTo,这个方法里,根据TargetOperation里的RenderSystemOperation列表,针对当前场景与RenderSystem(gl,dx,gles)进行渲染设置.具体设置可以看RenderSystemOperation子类的execute方法.在这里,我们假设使用opengl,FBO渲染,那么TargetOperation里的RenderTarget.Update最终会指向glBindFramebufferEXT(前面初始化RenderTarget时会调用glFramebufferTexture).是不是很熟悉了.
void CompositorChain::RQListener::flushUpTo(uint8 id) { /// Process all RenderSystemOperations up to and including render queue id. /// Including, because the operations for RenderQueueGroup x should be executed /// at the beginning of the RenderQueueGroup render for x. while(currentOp != lastOp && currentOp->first <= id) { currentOp->second->execute(mSceneManager, mRenderSystem); ++currentOp; } }
7.如上针对所有TargetOperation渲染后的最终RenderTarget会取代第五步主视图的RenderTarget,我们看到的就是经过CompositorChain后的效果.如果取代请看CompositorChain::RQListener::renderQueueStarted方法,后面会把skipThisQueue设置为true.
void CompositorChain::RQListener::renderQueueStarted(uint8 id, const String& invocation, bool& skipThisQueue) { // Skip when not matching viewport // shadows update is nested within main viewport update if (mSceneManager->getCurrentViewport() != mViewport) return; flushUpTo(id); /// If no one wants to render this queue, skip it /// Don‘t skip the OVERLAY queue because that‘s handled separately if(!mOperation->renderQueues.test(id) && id!=RENDER_QUEUE_OVERLAY) { skipThisQueue = true; } }
不加入CompositorChain,渲染顺序一般从RenderTarget->Viewport->SceneManager->RenderSystem进行渲染.
加入CompositorChain进行渲染后,主要是在主视图的RenderTarget更新前,调用CompositorChain渲染,并把CompositorChain渲染的RenderTarget进行上面的RenderTarget->Viewport->SceneManager->RenderSystem过程,并把最张生成的RenderTarget替换主视图的RenderTarget.
标签:
原文地址:http://www.cnblogs.com/zhouxin/p/4304622.html