ogre 引擎 框架追踪 第六章 渲染流程

来源:互联网 发布:手机mac地址伪装 编辑:程序博客网 时间:2024/06/05 23:56

ogre 引擎 框架追踪 第五章 资源加载之实加载

ogre的监听模式在渲染流程中得到大量的应用。
自己控制渲染时候可以在mfc的ontimer或者while语句中,直接调用root的renderOneFrame函数。

bool Root::renderOneFrame(void)    {        if(!_fireFrameStarted())//开始            return false;        if (!_updateAllRenderTargets())//更新            return false;        return _fireFrameEnded();//结束    }

看代码的三句话,按表面意思就是:帧开始->更新渲染物状态->帧结束。

渲染之帧开始

bool Root::_fireFrameStarted()    {        FrameEvent evt;        populateFrameEvent(FETT_STARTED, evt);//我们没有设置FrameEvent,先设置FrameEvent,得到距上一frame的时间。        return _fireFrameStarted(evt);    }

跟进

 bool Root::_fireFrameStarted(FrameEvent& evt)    {        OgreProfileBeginGroup("Frame", OGREPROF_GENERAL);        // Remove all marked listeners,从监听者中移除标记为移除的。移除时候是先将listener标记为移除的,在frame开始时候真的移除的        set<FrameListener*>::type::iterator i;        for (i = mRemovedFrameListeners.begin();            i != mRemovedFrameListeners.end(); i++)        {            mFrameListeners.erase(*i);        }        mRemovedFrameListeners.clear();        // Tell all listeners        for (i= mFrameListeners.begin(); i != mFrameListeners.end(); ++i)        {            if (!(*i)->frameStarted(evt))                return false;        }        return true;    }

先看下mFrameListeners都有啥东西吧。
根据先后顺序
(1)FrameTimeControllerValue(渲染帧时间控制器),在root初始化时由mControllerManager的创建而调用。
(2)自己程序通过Root::addFrameListener添加的监听者。一般自己控制动画时都需要继承自监听者。
第一个是必须的,用以计算最新frame time

所有,帧开始办了三件事(1)真的移除掉标记为移除的帧监听者(2)通知了渲染帧时间控制器计算frame time,(3)调用了其他监听者的帧开始

渲染之更新渲染物

_updateAllRenderTargets

 bool Root::_updateAllRenderTargets(void)    {        // update all targets but don't swap buffers,更新但不替换buffer        mActiveRenderer->_updateAllRenderTargets(false);        // 用户用的帧刷新        bool ret = _fireFrameRenderingQueued();//触发所有的frameRenderingQueued        // block for final swap        mActiveRenderer->_swapAllRenderTargetBuffers(mActiveRenderer->getWaitForVerticalBlank());        // This belongs here, as all render targets must be updated before events are        // triggered, otherwise targets could be mismatched.  This could produce artifacts,        // for instance, with shadows.        for (SceneManagerEnumerator::SceneManagerIterator it = getSceneManagerIterator(); it.hasMoreElements(); it.moveNext())            it.peekNextValue()->_handleLodEvents();        return ret;    }

跟进_updateAllRenderTargets

RenderTargetPriorityMap::iterator itarg, itargend;        itargend = mPrioritisedRenderTargets.end();        for( itarg = mPrioritisedRenderTargets.begin(); itarg != itargend; ++itarg )        {            if( itarg->second->isActive() && itarg->second->isAutoUpdated())//判断渲染对象是否激活、是否自动跟新。                itarg->second->update(swapBuffers);//更新        }

mPrioritisedRenderTargets变量为renderwindow、movableObject等渲染物的优先级及渲染物指针的map。必有的就是renderwindow

RenderTarget::update->updateImpl

_beginUpdate();//告知监听者要开始更新了,同时设置状态_updateAutoUpdatedViewports(true);//更新自动更新视口_endUpdate();//结束更新,设置状态

_updateAutoUpdatedViewports跟进

void RenderTarget::_updateAutoUpdatedViewports(bool updateStatistics)    {        // Go through viewports in Z-order,根据z-order来走一遍视口更新        // Tell each to refresh        ViewportList::iterator it = mViewportList.begin();        while (it != mViewportList.end())        {            Viewport* viewport = (*it).second;            if(viewport->isAutoUpdated())            {                _updateViewport(viewport,updateStatistics);            }            ++it;        }    }

跟进_updateViewport

void RenderTarget::_updateViewport(Viewport* viewport, bool updateStatistics)    {        assert(viewport->getTarget() == this &&                "RenderTarget::_updateViewport the requested viewport is "                "not bound to the rendertarget!");        fireViewportPreUpdate(viewport);//告诉监听者准备更新视口了        viewport->update();//视口更新        if(updateStatistics)//更新状态        {            mStats.triangleCount += viewport->_getNumRenderedFaces();            mStats.batchCount += viewport->_getNumRenderedBatches();        }        fireViewportPostUpdate(viewport);    }

viewport->update()调用视口绑定的相机来渲染场景mCamera->_renderScene(this, mShowOverlays)
跟进

 void Camera::_renderScene(Viewport *vp, bool includeOverlays)    {        OgreProfileBeginGPUEvent("Camera: " + getName());//调用渲染系统的beginProfileEvent,触发下渲染系统的开始前的准备事件        //update the pixel display ratio,更新像素展示比例        if (mProjType == Ogre::PT_PERSPECTIVE)//透视模式        {            mPixelDisplayRatio = (2 * Ogre::Math::Tan(mFOVy * 0.5f)) / vp->getActualHeight();        }        else//正交模式        {            mPixelDisplayRatio = (mTop - mBottom) / vp->getActualHeight();        }        //notify prerender scene        ListenerList listenersCopy = mListeners;        for (ListenerList::iterator i = listenersCopy.begin(); i != listenersCopy.end(); ++i)        {            (*i)->cameraPreRenderScene(this);//告知监听者        }        //render scene        mSceneMgr->_renderScene(this, vp, includeOverlays);//场景管理器去渲染场景        // Listener list may have change        listenersCopy = mListeners;        //notify postrender scene        for (ListenerList::iterator i = listenersCopy.begin(); i != listenersCopy.end(); ++i)        {            (*i)->cameraPostRenderScene(this);        }        OgreProfileEndGPUEvent("Camera: " + getName());    }

mSceneMgr->_renderScene继续跟进

    OgreProfileGroup("_renderScene", OGREPROF_GENERAL);    Root::getSingleton()._pushCurrentSceneManager(this);    mActiveQueuedRenderableVisitor->targetSceneMgr = this;//设置队列访问者     mAutoParamDataSource->setCurrentSceneManager(this);//设置当前场景管理器,为多管理器使用    // Also set the internal viewport pointer at this point, for calls that need it    // However don't call setViewport just yet (see below)    mCurrentViewport = vp;    // reset light hash so even if light list is the same, we refresh the content every frame    LightList emptyLightList;    useLights(emptyLightList, 0);    if (isShadowTechniqueInUse())    {        // Prepare shadow materials        initShadowVolumeMaterials();    }    // Perform a quick pre-check to see whether we should override far distance    // When using stencil volumes we have to use infinite far distance    // to prevent dark caps getting clipped    if (isShadowTechniqueStencilBased() && //stencil的阴影策略        camera->getProjectionType() == PT_PERSPECTIVE &&        camera->getFarClipDistance() != 0 &&         mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE) &&         mShadowUseInfiniteFarPlane)    {        // infinite far distance,设置无限远的远切面        camera->setFarClipDistance(0);    }    mCameraInProgress = camera;    // Update controllers     ControllerManager::getSingleton().updateAllControllers();    // Update the scene, only do this once per frame    unsigned long thisFrameNumber = Root::getSingleton().getNextFrameNumber();    if (thisFrameNumber != mLastFrameNumber)    {        // Update animations,更新动画        _applySceneAnimations();        updateDirtyInstanceManagers();        mLastFrameNumber = thisFrameNumber;    }    {        // Lock scene graph mutex, no more changes until we're ready to render,解释的很清楚,锁住场景画面        OGRE_LOCK_MUTEX(sceneGraphMutex)        /////////////////////////////////////灯光下的阴影材质设置        if (mIlluminationStage != IRS_RENDER_TO_TEXTURE && mFindVisibleObjects)        {            // Locate any lights which could be affecting the frustum,在视锥内有用的灯            findLightsAffectingFrustum(camera);            // Are we using any shadows at all?            if (isShadowTechniqueInUse() && vp->getShadowsEnabled())            {                // Prepare shadow textures if texture shadow based shadowing                // technique in use                if (isShadowTechniqueTextureBased())                {                    OgreProfileGroup("prepareShadowTextures", OGREPROF_GENERAL);                    // *******                    // WARNING                    // *******                    // This call will result in re-entrant calls to this method                    // therefore anything which comes before this is NOT                     // guaranteed persistent. Make sure that anything which                     // MUST be specific to this camera / target is done                     // AFTER THIS POINT                    prepareShadowTextures(camera, vp);                    // reset the cameras & viewport because of the re-entrant call                    mCameraInProgress = camera;                    mCurrentViewport = vp;                }            }        }        // Update scene graph for this camera (can happen multiple times per frame),为本相机更新画面,一帧可能走好几次(一般都是好几次,次数决定于rendertarget的数量)        {            OgreProfileGroup("_updateSceneGraph", OGREPROF_GENERAL);            _updateSceneGraph(camera);//真正的刷新场景画面的地方,node更新,包围盒更新            // Auto-track nodes,相机跟随node的设置            AutoTrackingSceneNodes::iterator atsni, atsniend;            atsniend = mAutoTrackingSceneNodes.end();            for (atsni = mAutoTrackingSceneNodes.begin(); atsni != atsniend; ++atsni)            {                (*atsni)->_autoTrack();            }            // Auto-track camera if required,如果设置了相机的自动跟踪某个节点,在这儿处理            camera->_autoTrack();        }        // Invert vertex winding?,用到这是、反射效果时需要设置        if (camera->isReflected())        {            mDestRenderSystem->setInvertVertexWinding(true);        }        else        {            mDestRenderSystem->setInvertVertexWinding(false);        }        //下面的几项设置gpu编程的 默认参数的值。        // Tell params about viewport,视口        mAutoParamDataSource->setCurrentViewport(vp);        // Set the viewport - this is deliberately after the shadow texture update        setViewport(vp);        // Tell params about camera,相机        mAutoParamDataSource->setCurrentCamera(camera, mCameraRelativeRendering);        // Set autoparams for finite dir light extrusion,灯        mAutoParamDataSource->setShadowDirLightExtrusionDistance(mShadowDirLightExtrudeDist);        // Tell params about current ambient light,环境光        mAutoParamDataSource->setAmbientLightColour(mAmbientLight);        // Tell rendersystem        mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b);        // Tell params about render target        mAutoParamDataSource->setCurrentRenderTarget(vp->getTarget());        // Set camera window clipping planes (if any),设置相机剪切平面        if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_USER_CLIP_PLANES))        {            mDestRenderSystem->resetClipPlanes();            if (camera->isWindowSet())              {                mDestRenderSystem->setClipPlanes(camera->getWindowPlanes());            }        }        // Prepare render queue for receiving new objects,准备渲染队列,以接受新的物体        {            OgreProfileGroup("prepareRenderQueue", OGREPROF_GENERAL);            prepareRenderQueue();//设置有阴影的物体,设置无阴影的材质,把工作队列分组        }        if (mFindVisibleObjects)        {            OgreProfileGroup("_findVisibleObjects", OGREPROF_CULLING);            // Assemble an AAB on the fly which contains the scene elements visible            // by the camera.            CamVisibleObjectsMap::iterator camVisObjIt = mCamVisibleObjectsMap.find( camera );            assert (camVisObjIt != mCamVisibleObjectsMap.end() &&                "Should never fail to find a visible object bound for a camera, "                "did you override SceneManager::createCamera or something?");            // reset the bounds            camVisObjIt->second.reset();            // Parse the scene and tag visibles,找到相机中可见的 object(在设置物体visibleflag时候设置的是否可见)            firePreFindVisibleObjects(vp);            _findVisibleObjects(camera, &(camVisObjIt->second),                mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);            firePostFindVisibleObjects(vp);            mAutoParamDataSource->setMainCamBoundsInfo(&(camVisObjIt->second));        }        // Add overlays, if viewport deems it,overlay的更新        if (vp->getOverlaysEnabled() && mIlluminationStage != IRS_RENDER_TO_TEXTURE)        {            OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp);        }        // Queue skies, if viewport seems it,天空的更新        if (vp->getSkiesEnabled() && mFindVisibleObjects && mIlluminationStage != IRS_RENDER_TO_TEXTURE)        {            _queueSkiesForRendering(camera);        }    } // end lock on scene graph mutex//渲染系统顶点数清零    mDestRenderSystem->_beginGeometryCount();    // Clear the viewport if required,视口清理    if (mCurrentViewport->getClearEveryFrame())    {        mDestRenderSystem->clearFrameBuffer(            mCurrentViewport->getClearBuffers(),             mCurrentViewport->getBackgroundColour(),            mCurrentViewport->getDepthClear() );//清理    }            // Begin the frame,激活视剪切    mDestRenderSystem->_beginFrame();    // Set rasterisation mode,光栅化模式(点、网格、体)    mDestRenderSystem->_setPolygonMode(camera->getPolygonMode());    // Set initial camera state,投影矩阵    mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());    mCachedViewMatrix = mCameraInProgress->getViewMatrix(true);    //更新相机位置,若相机设置为相对坐标的话    if (mCameraRelativeRendering)    {        mCachedViewMatrix.setTrans(Vector3::ZERO);        mCameraRelativePosition = mCameraInProgress->getDerivedPosition();    }    mDestRenderSystem->_setTextureProjectionRelativeTo(mCameraRelativeRendering, camera->getDerivedPosition());    //设置投影矩阵    setViewMatrix(mCachedViewMatrix);    // Render scene content    {        OgreProfileGroup("_renderVisibleObjects", OGREPROF_RENDERING);        _renderVisibleObjects();//内部调用_renderQueueGroupObjects,不同阴影策略不同的渲染方法,再底层调用renderSingleObject(其中进行shader程序的运行,设置渲染系统的世界矩阵,gpu选择材质pass)->RenderSystem::_render->bindVertexElementToGpu,(glVertexPointer、glTexCoordPointer设置顶点和文字坐标)更新顶点位置、uv等,更新深度偏移->底层调用glDrawElements(若用gl),调用glClientActiveTextureARB,    }    // End frame    mDestRenderSystem->_endFrame();    // Notify camera of vis faces    camera->_notifyRenderedFaces(mDestRenderSystem->_getFaceCount());    // Notify camera of vis batches    camera->_notifyRenderedBatches(mDestRenderSystem->_getBatchCount());    Root::getSingleton()._popCurrentSceneManager(this);

SceneManager::_updateSceneGraph跟进

firePreUpdateSceneGraph(cam);//告知监听者Node::processQueuedUpdates();getRootSceneNode()->_update(true, false);    firePostUpdateSceneGraph(cam);

渲染物的更新ManualObject::_updateRenderQueue

SceneManager::_renderQueueGroupObjects

SceneManager::renderSingleObject

SceneManager::updateGpuProgramParameters

GLRenderSystem::_render

位置的计算->node->renderable

核心代码的流程:
Root::renderOneFrame->
1、计算evt的两个时间(timeSinceLastEvent、timeSinceLastFrame),用作后面的更新
2、移除掉标记为已删除的监听者
3、告知所有监听者帧开始
4、调用_updateAllRenderTargets的更新所有渲染物(所谓渲染物即渲染对象,可以理解为渲染到哪里)
5、结束
Root::_updateAllRenderTargets->
1、调用RenderSystem::_updateAllRenderTargets更新所有的渲染物(RenderTexture、RenderWindow),更新node、camera、animation、顶点材质等
2、调用用户的帧渲染函数_fireFrameRenderingQueued ,并告知所有监听者
3、替换所有渲染buffer

RenderSystem::_updateAllRenderTargets->
调用RenderTarget::update,更新所有优先级渲染物(如果该渲染物是被激活的并且是自动更新的)

RenderTarget::update->
调用updateImpl更新渲染物

RenderTarget::updateImpl->
1、更新开始,告知监听器,对渲染物状态的两个参数(triangleCount、batchCount)清零
2、调用_updateAutoUpdatedViewports更新所有自动更新的视口
3、结束更新

RenderTarget::_updateAutoUpdatedViewports->
调用所有视口的_updateViewport

RenderTarget::_updateViewport->
1、告知视口时间监听者,视口更新准备函数
2、调用Camera::_renderScene

Camera::_renderScene->
1、根据相机类型(投影、正交)设置像素比例,//直接关系到渲染出来的结果是否真实
2、告知相机事件监听者准备渲染
3、调用SceneManager::_renderScene渲染场景(场景中包含的灯光、阴影、顶点、材质、动画等)

SceneManager::_renderScene->
1、设置当前队列的访问者,设置gpu编程参数场景管理器,设置当前视口,设置当前相机
2、阴影效果用到的材质初始化(只初始化一次)
3、根据情况设置相机远切面是否无限远
4、更新场景中的ogre通用控制器(材质中纹理动画管理器、粒子系统动画管理等)
5、更新帧数,更新动画
6、设置根据场景的视锥中灯的情况,设置阴影材质,可能又会回调到renderscene,因为阴影纹理也是rendertarget
7、更新场景画面,包含节点(node)、包围盒,并在之前和之后告知监听者;同时若相机是有设置了跟踪某个节点,在此时设置相机方位。
8、相机设置了反射、折射后的对渲染系统的特殊设置(gpu编程时候使用)
9、设置gpu编程参数(视口、相机、相机相关、产生阴影的方向灯光照射距离、环境光颜色、渲染物)
10、渲染系统剪切平面设置
11、准备渲染队列
12、遍历,查询到所有该相机视锥内的可见对象(通过八叉树的场景管理方式查询所有时候比较快),包括overlay、天空盒
13、渲染系统在更新前的相关设置:批数目清零、帧缓存清理、帧开始测试、三角模式(网格、顶点或模型)、投影矩阵设置、纹理投影设置、视口矩阵设置
14、调用_renderVisibleObjects,渲染所有可见物体
15、结束一帧
16、告知相机渲染面信息、批信息。弹出当前场景管理器

_renderVisibleObjects->
调用用户自己设置频率的渲染函数或者调用默认的渲染函数renderVisibleObjectsDefaultSequence
renderVisibleObjectsDefaultSequence->
1、告知监听者队列渲染准备
2、告知开始渲染队列
3、调用_renderQueueGroupObjects,渲染队列组中的物体
4、告知队列渲染结束
SceneManager::_renderQueueGroupObjects->
根据不同的阴影策略,调用不同的函数,下面的进入默认情况下 的函数
SceneManager::renderBasicQueueGroupObjects->
1、渲染优先级队列排序
2、调用renderObjects
SceneManager::renderObjects->
1、设置队列访问者
2、调用acceptVisitor
QueuedRenderableCollection::acceptVisitor->
根据组织模式不同,调用不同函数。
以pass分组的进入acceptVisitorGrouped;以相机距离递减的访问acceptVisitorDescending;以相机距离递增的访问acceptVisitorAscending
acceptVisitorGrouped->
调用visit,对所有pass分组下,所有renderable进行访问
SceneMgrQueuedRenderableVisitor::visit->
1、判断是否有效
2、调用renderSingleObject,渲染单个儿object
SceneManager::renderSingleObject->
1、获取renderable,获取pass中 的gpu程序对象
2、设置渲染系统的世界矩阵
3、设置三角模式(pass的)
4、灯列表
5、告知监听者要渲染单个物体
6、渲染系统设置深度偏移
7、更新gpu程序参数,最后一次绑定ogre中的参数与gpu程序的参数
8、调用渲染系统_render渲染
8、重置view的投影模式

GLRenderSystem::_render
1、调用基类_render
2、获取顶点声明信息等相关顶点信息
3、调用bindVertexElementToGpu,将顶点信息同gpu绑定(vertexprogram的顶点、uv信息输入),底层调用的glVertexPointer、glNormalPointer、glColorPointer、glTexCoordPointer等更新顶点及uv信息。
4、顶点索引buffer获取
5、根据顶点信息、索引信息,调用glDrawElements渲染出画面。
6、解绑必要的属性

0 0
原创粉丝点击