Ogre Compositor解析

Compositor脚本与类型

  我们先看下面一张基本的Compositor的脚本图:

Ogre Compositor解析_第1张图片

  上面就是一个Composition资源.在解析时,主要是使用CompositionPass, CompositionTargetPass, CompositionTechnique, Compositor,而在渲染时,使用RenderSystemOperation, TargetOperation, CompositorInstance, CompositionChain.管理Composition用CompositionManage.

Compositor主要类型说明.

CompositionPass:

  一次渲染环境设置,包含基本渲染设置,根据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:

  对应上面的图,一个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:

  对应上面的图,一个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) {}
        };
复制代码

Compositor:

  CompositionTechnique列表.对应CompositorInstance,分别处理资源与渲染.

  其中mGlobalTextures与mGlobalMRTs分别是CompositionTechnique里的TextureDefinition列表集合,TextureDefinition如果PixelFormat只有一个,加入mGlobalTextures中,如果有多个,加入mGlobalMRTs中.

CompositorInstance:

  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:

  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渲染流程

  上面是各个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.在用户创建场景时,调用CompositorManage注册Compositor到对应Viewport中,首先得到与一个与Viewport对应的CompositorChain对象(有则返回,无则新增),并且添加对Viewport与此对应Viewport的RenderTarget的监听.并对CompositorChain对象进行相关初始化,以及根据传入的Compositor生成一一对应的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.当我们通过CompositorManage设置某个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的CompositorChain对象,第一次重构CompositorChain时会首先调用_complie完成对之上所有CompositorInstance对象按顺序链接成链表,并把对应链表从前按后调用CompositorInstance::_compileTargetOperations填充到CompositorChain里的TargetOperation列表对象mCompiledState中.其中最后一个CompositorInstance中的OutputTargetPass(特殊的CompositionTargetPass)没放入上面,而是单独保存在mOutputOperation.

  其中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开始调用preRenderTargetUpdate,检测到CompositorChain,针对mCompiledState里的所有TargetOperation中的RenderTarget更新开始,  

  在这过程中,注意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.在第五步中,针对mCompiledState的每个TargetOperation中的RenderTarget渲染都会对SceneManager注册通道监听事件,那么在每次RenderTarget更新中的通道事件中,到第五步的RQListener开始调用renderQueueStarted方法,在这方法里,调用flushUpTo,这个方法里,根据TargetOperation里的RenderSystemOperation列表,针对当前场景与RenderSystem(gl,dx,gles)进行渲染设置.具体设置可以看RenderSystemOperation子类的execute方法.在这里,我们假设使用opengl,FBO渲染,那么TargetOperation里的RenderTarget.Update最终会指向glBindFramebufferEXT(前面初始化RenderTarget时会调用glFramebufferTexture).是不是很熟悉了.

  感觉有必要单独说下CompositorChain::RQListener::flushUpTo,参数id表示当前的RenderQueueGroupID,ogre从小到大渲染,意思在渲染所有通道组时,每次进通道组,也就是进flushUpTo中,id是从小到大的,在方法里,我们检查RenderSystemOperation 的最小渲染通道是否小于或等于当前的RenderQueueGroupID,如果是才执行.其中pass render_scene这种如果没有设置material_scheme,则只会改变当前TargetOperation 的currentQueueGroupID为pass->getLastRenderQueue() + 1与renderQueues (当前TargetOperation影响的RenderQueueGroupID),否则不仅改变currentQueueGroupID与renderQueues,还会添加一个RSSetSchemeOperation,一个RSRestoreSchemeOperation. 注意pass render_custom与pass render_scene一样,currentQueueGroupID受本身pass影响,而pass clear,render_quad,stencil不会改变currentQueueGroupID.

复制代码
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.当mCompiledState中的TargetOperation渲染完成后,然后到了主视图的RenderTarget中的preViewportUpdate更新mOutputOperation,前面说过,这也是一个TargetOperation,但是不会在RenderTarget中的preRenderTargetUpdate那里调用更新,mOutputOperation本身的RenderTarget为空,而和主视图RenderTarget共用一个viewport.这个效果就是mOutputOperation的更新就是主视图的RenderTarget更新(设置viewport,会把viewport中的RenderTarget 放入渲染中,详见RenderSystem::_setRenderTarget ).

  如上CompositorChain最后的渲染效果会放入到主视图的RenderTarget,我们看到的就是经过CompositorChain后的效果.  

  

Ogre中有许多监听类,我们可以简单理解成C#中的事件,这些类作用都不小,说大点可能改变流程,说小点修改参数等,下面列举一些常用的监听类.

  • FrameListener:由Ogre中的Root负责维护,主要针对所有RenderTarget监听
    • frameStarted:在一桢开始的时候,所有RenderTarget更新之前.
    • frameRenderingQueued:所有RenderTarget更新之后,但是还没交换缓冲区.(意思屏幕上显示没变)
    • frameEnded:所有RenderTarget更新并交换了缓冲区数据.
  • RenderTargetListener:由RenderTarget负责维护,主要针对当前RenderTarget监听
    • preRenderTargetUpdate:在Viewport开始更新之前,可以用来根据不同的RenderTarget改变Renderable的可见性,摄像机位置.或是捕获当前RenderTarget做别的处理.
    • postRenderTargetUpdate:在Viewport更新之后,一般用来还原在preRenderTargetUpdate做的处理.
    • preViewportUpdate:在上面的preRenderTargetUpdate之后,SceneManger开始渲染之前.可以针对viewport修改.
    • postViewportUpdate:在postRenderTargetUpdate之前,可以还原preViewportUpdate所做更改.
  • SceneManager::Listener:由SceneManager负责维护,针对场景节点更新,场景模型可见,阴影
    • preUpdateSceneGraph:在上面viewport开始更新后,SceneManager开始更新结果,由RootSceneNode递归更新.
    • postUpdateSceneGraph:如上所有节点更新完后.在去查找模型可见之前.
    • preFindVisibleObjects:更新节点后,开始查找Renderable可见之前.
    • postFindVisibleObjects:在所有可见的Renderable添加见渲染通道之后.
    • shadowTexturesUpdated:以及下面的几个方法主要是关于阴影的更新,这里不细说,以后细说阴影部分.
  • MaterialManager::Listener:由MaterialManager负责维护,能针对Viewport提供多方案.
    • handleSchemeNotFound:在查找所有可见的Renderable中,也就是添加在渲染通道的时候,查找对应Renderable的材质,是否和当前的方案一致,如不一致发生.
  • RenderQueueListener:由SceneManager负责维护,提供针对每组渲染通道设置.
    • preRenderQueues:开始渲染通道里的Renderable.所有通道组开始渲染之前.
    • postRenderQueues:所有渲染通道里的Renderable都渲染之后.
    • renderQueueStarted:同组的渲染通道开始渲染.preRenderQueues有多组渲染通道,在之后针对每组渲染.
    • renderQueueEnded:当前组的渲染通道渲染完后.
  • RenderObjectListener:由SceneManager负责维护,提供渲染时当前Renderable与Pass.
    • notifyRenderSingleObject:,在进入通道后,在渲染Renderable之前.其中RTSS就用来更新当前着色器参数.
  • CompositorInstance::Listener:由CompositorInstance负责维护,主要用于修改当前合成器的着色器参数.
    • notifyMaterialSetup:在RenderSystemOperation刚创建时,一般用于修改不变的着色器参数.
    • notifyMaterialRender:RenderSystemOperation每次更新调用,一般用来每桢要更新参数.
    • createResources:在createResources(创建当前CompositorInstance中的RenderTexture)后.
  • Viewport::Listener:由Viewport负责维护,主要检查当前viewport一些变化.
    • viewportCameraChanged:当前Viewport上摄像机变化后.
    • viewportDimensionsChanged:当前Viewport尺寸变化.
    • viewportDestroyed:当前Viewport析构时发生.

  如上这些是一些基本的监听类,还有一些没有列举出来.上面虽然大致说了那些监听事件在那调用,但是大家肯定也感觉不清晰,如下结合渲染流程来说,大家就会有个比较清楚的认识.

  如下是正常的渲染流程,大致说下主要过程,Root调用srartRendering开始渲染,每桢更新,在每桢中查找当前所有的RenderTarget,更新当前RenderTarget,然后交给viewport,camera到SceneManager,场景首先更新根节点下所有节点位置, 更新参数mAutoParamDataSource一部分已知参数,然后检查所有节点上的MovableObject是否可见,如果可见,把MovableObject对应的Renderable和pass根据渲染等级加入渲染通道组.(说下渲染等级RenderQueueGroupID,一般是从0到105,0是背景,100是UI,就是说RenderQueueGroupID越大,越在上面显示.)然后由渲染等级由低到高开始渲染通道内的Renderable,然后结束本桢.如下是一些主要的渲染过程.

  1. Root::startRendering->Root::renderOneFrame 开始当前桢渲染
  2. Root::_fireFrameStarted(FrameListener::frameStarted)
  3. Root::_updateAllRenderTargets 开始更新所有RenderTarget
    1. RenderSystem::_updateAllRenderTargets
      1. RenderTarget::update->RenderTarget::updateImpl 更新当前的RenderTarget
      2. RenderTarget::_beginUpdate(RenderTargetListener::preRenderTargetUpdate)
      3. RenderTarget::_updateViewport 更新当前RenderTarget的当前Viewport
        1. RenderTarget::fireViewportPreUpdate(RenderTargetListener::preViewportUpdate) 可以针对Viewport修改
        2. Viewport::update->Camera::_renderScene 转交给Camera
          1. Camera::Listener::cameraPreRenderScene 可以针对当前Camera修改
          2. SceneManger::_renderScene 场景接管渲染
            1. SceneManger::_updateSceneGraph 更新场景中所有节点
              1. SceneManger::firePreUpdateSceneGraph(SceneManager::Listener::preUpdateSceneGraph) 当前场景与摄像机
              2. Node::processQueuedUpdate 标记所有需要更新的节点
              3. RootSceneNode::_update(true,false) 更新所有需要更新的节点 递归RootSceneNode
              4. SceneManger::firePostUpdateSceneGraph(SceneManager::Listener::postUpdateSceneGraph) 节点更新完后
            2. SceneManager::setViewport 设置当前viewport
              1. RenderSystem::_setViewport
                1. RenderSystem::_setRenderTarget (设定渲染系统的RenderTarget) 
              2. MaterialManager::setActiveScheme 把当前viewport方案给MaterialManager知道
            3. SceneManger::firePreFindVisibleObjects(SceneManager::Listener::preFindVisibleObjects) 在查找所有模型可见前
            4. SceneManger::_findVisibleObjects(父节点,第一次为根节点) 
              1. SceneNode::_findVisibleObjects 开始查找当前节点下模型
              2. RenderQueue::processVisibleObject 查找模型MovableObject是否在当前摄像机下可见
              3. MovableObject::_notifyCurrentCamera 通知MovableObject当前模型机在查找
              4. Renderable::Visitor::visitor 当前MovableObject关联的Renderable的访问者执行
              5. MovableObject::_updateRenderQueue 当前MovableObject关联的Renderable添加到渲染通道
              6. RenderQueue::addRenderable 添加Renderable,RenderQueue里开始根据RenderQueueGroupID开始分组成RenderQueueGroup
              7. Renderable::getTechnique 添加到RenderQueueGroup时要找到对应技术(如果没找到当前方案,执行下面二句)
              8. MaterialManager:: _arbitrateMissingTechniqueForActiveScheme 找所有的MaterialManager::Listener
              9. MaterialManager::Listener::handleSchemeNotFound 当前材质,Renderable,方案
              10. QueuedRenderableCollection::addRenderable(Pass,Renderable) RenderQueueGroup根据优先级分成RenderPriorityGroup,根据投射阴影,接收阴影,透明等继续分组,添加技术下各个Pass到QueuedRenderableCollection
              11. SceneNode:: _findVisibleObjects (子节点) 递归子节点
            5. SceneManger::firePostFindVisibleObjects(SceneManager::Listener::postFindVisibleObjects) 结束查找所有节点下模型可见
            6. RenderSystem::_beginFrame RenderSystem开始渲染准备
            7. SceneManager::_renderVisibleObjects SceneManager开始渲染可见物体
              1. SceneManager::firePreRenderQueues(RenderQueueListener::preRenderQueues) 通知用户开始渲染通道里的所有通道组
              2. SceneManager::fireRenderQueueStarted( RenderQueueListener::renderQueueStarted) 通知用户开始渲染当前通道组
                1. SceneMangger::renderObjects ->QueuedRenderableCollection::acceptVisitorGrouped 渲染当前通道组各优先级通道
                  1. SceneManager::SceneMgrQueuedRenderableVisitor::visit 访问当前QueuedRenderableCollection下的各个RenderablePass
                  2. SceneManager::renderSingleObject 渲染当前的Renderable与pass
                    1. RenderSystem::fireRenderSingleObject(RenderObjectListener::notifyRenderSingleObject) 通知用户
                    2. SceneManager::updateGpuProgramParameters 更新当前pass下着色器代码参数
                    3. Renderable::getRenderOperation 获取当前Renderable的缓冲区对象数据
                    4. Renderable::preRender 开始渲染当前Renderable
                    5. RenderSystem::_render 交给RenderSystem渲染了
                    6. Renderable::postRender 结束渲染当前Renderable
              3. SceneManager::fireRenderQueueEnded(RenderQueueListener::renderQueueEnded) 通知用户结束了当前通道组
              4. SceneManager::firePostRenderQueues(RenderQueueListener::postRenderQueues) 通知用户结束了所有通道组
            8. RenderSystem::_endFrame RenderSystem结束渲染
          3. Camera::Listener::cameraPostRenderScene 通知用户当前桢摄像机结束渲染
        3. RenderTarget::fireViewportPostUpdate(RenderTargetListener::postViewportUpdate) 当前桢视图结束渲染
      4. RenderTarget::_endUpdate(RenderTargetListener::postRenderTargetUpdate) 当前桢RenderTarget结束渲染
    2. Root::_fireFrameRenderingQueued(FrameListener:: frameRenderingQueued) 当前桢结束渲染
    3. RenderSystem::_swapAllRenderTargetBuffers 交换所有RenderTarget的桢缓冲
  4. Root::_fireFrameEnded(FrameListener:: frameEnded) 当前桢结束

  如果Ogre启用Compositor后,有些位置需要改变了,前篇Ogre Compositor解析里有简单介绍过CompositorChain实现了接口RenderTargetListener与Viewport::Listener,那么在上面3.1.2 RenderTarget::_beginUpdate中就捕捉到当前的RenderTarget,并且调用CompositorChain的compile,生成当前TargetOperation列表,RenderSystemOperation列表,在TargetOperation的RenderTarget更新时,指定对应的TargetOperation到RenderQueueListener中,这样在渲染通道时,执行当前TargetOperation下的所有RenderSystemOperation,然后开始渲染.

  1. RenderTarget::_beginUpdate( RenderTargetListener::preRenderTargetUpdate)
    1. CompositorChain::_compile
      1. CompositorChain::_complieTargetOperations
        1. CompositorChain::_complieTargetOperations (compiledState收集TargetOperation)
        2. CompositorChain::collectPasses (queueRenderSystemOp收集RenderSystemOperation)
          1. new RenderSystemOperation (根据CompositionTargetPass的type传入生成不同对象)
          2. CompositorInstance::_fireNotifyMaterialSetup (CompositorInstance::Listener::notifyMaterialSetup)
    2. TargetOperation->RenderTarget::update (一个CompositorChain里有多个TargetOperation)
      1. CompositorChain::preTargetOperation (指定当前TargetOperation, RenderSystemOperation到CompositorChain::RQListener)
      2. 同上面流程RenderTarget::update 到SceneManager::_renderVisibleObjects
      3. SceneManager::firePreRenderQueues (RenderQueueListener::preRenderQueues)
      4. SceneManager::fireRenderQueueStarted ( RenderQueueListener::renderQueueStarted)
        1. CompositorChain::RQListener::flushUpTo (执行所有RenderSystemOperation)
          1. RenderSystemOperation::execute
            1. CompositorInstance:: _fireNotifyMaterialRender (CompositorInstance::Listener:: notifyMaterialRender)
      5. 检查skipThisQueue == true -> 跳过本级别(同RenderQueueGroupID)的SceneMangger::renderObjects,否则同原过程一样.
      6. SceneManager::firePostRenderQueues (RenderQueueListener::postRenderQueues)
    3. TargetOperation->RenderTarget::swapBuffers-> (如果选用RTT用FBO)GLFBORenderTexture::swapBuffers
  2. RenderTarget::_endUpdate (RenderTargetListener::postRenderTargetUpdate)  

  以上渲染过程都只是一般情况下的,不是固定的,我们本身就可以修改其中一些过程,还有用户可以自己手动渲染Renderable,这些都会造成原来渲染流程变化.

  本文比较简单,但是相关流程是整个Ogre的核心,掌握上面的流程与监听事件,我们才能更好的使用Ogre.


上文来自:http://www.cnblogs.com/zhouxin/p/4619331.html

你可能感兴趣的:(C++,c,C++11,OGRE)