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.

Ogre 监听类与渲染流程的更多相关文章

  1. [Java聊天室server]实战之二 监听类

    前言 学习不论什么一个稍有难度的技术,要对其有充分理性的分析,之后果断做出决定---->也就是人们常说的"多谋善断":本系列尽管涉及的是socket相关的知识,但学习之前,更 ...

  2. Android手势监听类GestureDetector的使用

    在使用自定义视图的时候,对触屏事件的处理是比不可少的,有能力的可以自己写代码处理,这样更加的灵活.如果不想这么麻烦,Android提供了一个手势监听类GestureDetector,可以供我们使用.G ...

  3. 基于Java+Selenium的WebUI自动化测试框架(四)-----设置监听类

    基于上一篇的内容,这里我们开始写监听类Listener.我这里写监听类的思路是,继承TestListenerAdapter这个类,然后对其中的方法进行重写.网上也有很多资料,建议先学习一下,然后写出来 ...

  4. Session监听类HttpSessionListener介绍及在listener里取得request

    Session监听类HttpSessionListener介绍及在listener里取得request servlet-api.jar中提供了监听类HttpSessionListener,主要方法有两 ...

  5. Spring事件监听ApplicationListener源码流程分析

    spring的事件机制是基于观察者设计模式的,ApplicationListener#onApplicationEvent(Event)方法,用于对事件的处理 .在容器初始化的时候执行注册到容器中的L ...

  6. java中的四种监听类用法

    在此列举四种方法: 自身类实现ActionListener接口,作为事件监听器 通过匿名类处理 通过内部类处理 通过外部类处理 下面依次介绍: 第一种:自身类实现ActionListener接口,作为 ...

  7. kafka监听类

    package com.datad.dream.service; import com.alibaba.fastjson.JSON; import com.datad.dream.dao.KafkaI ...

  8. 【Android】关于连续多次点击控件的控制方案(新建监听类)

    参考:防止Android过快点击造成多次事件的三种方法_胖胖的博客-CSDN博客 实现逻辑很简单: 设置限定时间 在用户点击时开始计时 若计时未超过限定时间,则不允许触发点击事件 因还未学习过Rxja ...

  9. 监听器以及在监听类里面获得bean的方法

    1实现HttpSessionListener和ServletContextListener,2个接口 2然后在contextInitialized初始化方法里面: ServletContext app ...

随机推荐

  1. raft Paxos

    CONSENSUS: BRIDGING THEORY AND PRACTICE https://ramcloud.stanford.edu/~ongaro/thesis.pdf https://web ...

  2. 应该用bind+function取代虚函数吗?

    用bind+function取代虚函数在好几年前就有人提出了,曾引起广泛的讨论,有支持的有反对的,可能赞成的人占大多数.这个话题挺有趣,本来是作为技术沙龙的开放性话题来讨论的,由于时间关系并没有讨论. ...

  3. android工程导入没有错误,运行提示Unable to instantiate activity ComponentInfo

    导入小米clientside_android_sdk的demo OAuth-OpenAuthDemo,点Java Build Path的Libraries内Add External JARs,将oau ...

  4. 【delphi】多线程同步之Semaphore

    另外两种多线程的同步方法 CriticalSection(临界区) 和 Mutex(互斥), 这两种同步方法差不多, 只是作用域不同; CriticalSection(临界区) 类似于只有一个蹲位的公 ...

  5. 导入第三方Jar包到Nexus私服

    公司里面有自己的公共代码库,如果希望交给Maven进行管理,可以搭建Nexus服务器,将公司的公共代码库的代码打成jar包,然后上传到Nexus私服服务器上,项目组的成员就可以在Maven项目中通过添 ...

  6. IOS 地图移动中心点获取

    MKMap显示地图后,如果用户移动了地图,自己定义的数据就需要刷新了,所以这个时候,中心点的经纬度就比较重要了. 本文演示如何获取经纬度 在MKMapViewDelegate里有个方法 - (void ...

  7. Java之线程状态

    Java线程有6种状态: 1.New(新生),使用new Thread(r)创建一个新线程时,该线程处于新生状态,新生状态会为线程的执行做一些准备. 2.Runnable(可执行),调用线程的star ...

  8. 经常遇到的http状态码

    200 success成功 301 MovedPermanently 永久性跳转 302 Found 临时性跳转 304 Not modified 未修改,不返回任何响应主体 400 Bad Requ ...

  9. Mockito 简单使用

    有一个月没写博客了,以后再忙也要抽时间写啊. 目的 正常情况下,如果要对 UserService 中方法的测试,那么其依赖的 UserDao 也要可以调通,但是,UserDao 可能并不是直接到 DB ...

  10. js统计输入文字的字节数(byte)

    这里主要考虑的是日文,日文中包含了半角和全角文字,半角算1,全角算2. <html> <head> <script language="javascript&q ...