Ogre의 renderScene 코드

코드는 1.7.3 버전을 기반으로 한다.전체 scene의 렌더링 창고는 다음과 같습니다
Root::startRendering()
  Root::renderOneFrame()
    Root::_updateAllRenderTargets()
      RenderSystem::_updateAllRenderTargets()
        RenderTarget::update()
          RenderTarget::updateImpl()
            RenderTarget::_updateAutoUpdated()
              D3D9RenderWindow::_updateViewport()
                RenderTarget::_updateViewport()
                  Viewport::update()
                    Camera::_renderScene()  --          ,     listener cameraPreRenderScene() cameraPostRenderScene()
                      SceneManager::_renderScene()

즉, SceneManager::renderScene()은 전체 장면의 렌더링을 책임집니다.이 방법에서는 다음을 수행합니다.
1、그림자가 켜져 있는지 확인하고, 켜져 있으면 초기화합니다
    if (isShadowTechniqueInUse())
    {
        // Prepare shadow materials
        initShadowVolumeMaterials();
    }

2、시경체에 영향을 줄 수 있는 램프 테스트
            // 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);  --    shadow texture?No,            ?
                    // reset the cameras & viewport because of the re-entrant call
                    mCameraInProgress = camera;
                    mCurrentViewport = vp;
                }
            }

3. 그 다음에 대다수 상황에서oct tree의 장면 노드 업데이트를 진행한다. 주로 각 노드의 물체가 세계 좌표와 세계 좌표 아래의 포위함 등을 업데이트한다.
_updateSceneGraph(camera);

//octtree _updateSceneGraph       
void SceneManager::_updateSceneGraph(Camera* cam)
{
    // Process queued needUpdate calls 
    Node::processQueuedUpdates();

    // Cascade down the graph updating transforms & world bounds
    // In this implementation, just update from the root
    // Smarter SceneManager subclasses may choose to update only
    //   certain scene graph branches
    getRootSceneNode()->_update(true, false);
}

4、render Queue, PVS 생성 준비
		// 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
			firePreFindVisibleObjects(vp);
			_findVisibleObjects(camera, &(camVisObjIt->second),
				mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false);
			firePostFindVisibleObjects(vp);

			mAutoParamDataSource->setMainCamBoundsInfo(&(camVisObjIt->second));
		}

5. 프레임 업데이트
    // Begin the frame
    mDestRenderSystem->_beginFrame();

    // Set rasterisation mode
    mDestRenderSystem->_setPolygonMode(camera->getPolygonMode());  --     polygon     

	// Set initial camera state
	mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS());  
        // --  project matrix,                          D3D   。
        // --       SetTransform( D3DTS_PROJECTION, &mDxProjMat )

        mCachedViewMatrix = mCameraInProgress->getViewMatrix(true);

	if (mCameraRelativeRendering)
	{
		mCachedViewMatrix.setTrans(Vector3::ZERO);
		mCameraRelativePosition = mCameraInProgress->getDerivedPosition();
	}
	mDestRenderSystem->_setTextureProjectionRelativeTo(mCameraRelativeRendering, camera->getDerivedPosition());

	setViewMatrix(mCachedViewMatrix);  
        // --  view matrix
        // --       SetTransform( D3DTS_VIEW, &mDxViewMat )
 
        // Render scene content
	{
		OgreProfileGroup("_renderVisibleObjects", OGREPROF_RENDERING);
		_renderVisibleObjects();  -- PVS             
	}

    // End frame
    mDestRenderSystem->_endFrame();

만약 장면에 shadow가 필요하지 않으면, 경유하여 모든 노드를 렌더링합니다
void SceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup, 
												QueuedRenderableCollection::OrganisationMode om)
{
    // Basic render loop
    // Iterate through priorities
    RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator();

    while (groupIt.hasMoreElements())
    {
        RenderPriorityGroup* pPriorityGrp = groupIt.getNext();

        // Sort the queue first  --  geometry    
        pPriorityGrp->sort(mCameraInProgress);

        // Do solids    --     、      
        renderObjects(pPriorityGrp->getSolidsBasic(), om, true, true);
       
        // Do unsorted transparents --  ,     
	renderObjects(pPriorityGrp->getTransparentsUnsorted(), om, true, true);
       
        // Do transparents (always descending)  --   
        renderObjects(pPriorityGrp->getTransparents(), 
			QueuedRenderableCollection::OM_SORT_DESCENDING, true, true);


    }// for each priority
}

단일 객체 렌더링:
void SceneManager::renderSingleObject(Renderable* rend, const Pass* pass, 
                                      bool lightScissoringClipping, bool doLightIteration, 
									  const LightList* manualLightList)
{
    unsigned short numMatrices;
    RenderOperation ro;


    // Set up rendering operation
    // I know, I know, const_cast is nasty but otherwise it requires all internal
    // state of the Renderable assigned to the rop to be mutable
    const_cast<Renderable*>(rend)->getRenderOperation(ro);
    ro.srcRenderable = rend;

	GpuProgram* vprog = pass->hasVertexProgram() ? pass->getVertexProgram().get() : 0;

	bool passTransformState = true;

	if (vprog)
	{
		passTransformState = vprog->getPassTransformStates();
	}

    // Set world transformation
    numMatrices = rend->getNumWorldTransforms();
	
	if (numMatrices > 0)
	{
	    rend->getWorldTransforms(mTempXform);

		if (mCameraRelativeRendering && !rend->getUseIdentityView())
		{
			for (unsigned short i = 0; i < numMatrices; ++i)
			{
				mTempXform[i].setTrans(mTempXform[i].getTrans() - mCameraRelativePosition);
			}
		}

		if (passTransformState)
		{
                        //  --      SetTransform( D3DTS_WORLD, &mDxWorldMat )          
                        if (numMatrices > 1)
			{
				mDestRenderSystem->_setWorldMatrices(mTempXform, numMatrices);
			}
			else
			{
				mDestRenderSystem->_setWorldMatrix(*mTempXform);
			}
		}
	}
    // Issue view / projection changes if any
    useRenderableViewProjMode(rend, passTransformState);

    // mark per-object params as dirty
    mGpuParamsDirty |= (uint16)GPV_PER_OBJECT;

    if (!mSuppressRenderStateChanges)
    {
        bool passSurfaceAndLightParams = true;

        if (pass->isProgrammable())
        {
            // Tell auto params object about the renderable change
            mAutoParamDataSource->setCurrentRenderable(rend);
            // Tell auto params object about the world matrices, eliminated query from renderable again
            mAutoParamDataSource->setWorldMatrices(mTempXform, numMatrices);
			if (vprog)
			{
				passSurfaceAndLightParams = vprog->getPassSurfaceAndLightStates();
			}
        }

        // Reissue any texture gen settings which are dependent on view matrix
        Pass::ConstTextureUnitStateIterator texIter =  pass->getTextureUnitStateIterator();
        size_t unit = 0;
        while(texIter.hasMoreElements())
        {
            TextureUnitState* pTex = texIter.getNext();
            if (pTex->hasViewRelativeTextureCoordinateGeneration())
            {
                mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
            }
            ++unit;
        }

        // Sort out normalisation
		// Assume first world matrix representative - shaders that use multiple
		// matrices should control renormalisation themselves
		if ((pass->getNormaliseNormals() || mNormaliseNormalsOnScale)
			&& mTempXform[0].hasScale())
			mDestRenderSystem->setNormaliseNormals(true);
		else
			mDestRenderSystem->setNormaliseNormals(false);

		// Sort out negative scaling
		// Assume first world matrix representative 
		if (mFlipCullingOnNegativeScale)
		{
			CullingMode cullMode = mPassCullingMode;

			if (mTempXform[0].hasNegativeScale())
			{
				switch(mPassCullingMode)
				{
				case CULL_CLOCKWISE:
					cullMode = CULL_ANTICLOCKWISE;
					break;
				case CULL_ANTICLOCKWISE:
					cullMode = CULL_CLOCKWISE;
					break;
                case CULL_NONE:
                    break;
				};
			}

			// this also copes with returning from negative scale in previous render op
			// for same pass
			if (cullMode != mDestRenderSystem->_getCullingMode())
				mDestRenderSystem->_setCullingMode(cullMode);
		}

		// Set up the solid / wireframe override
		// Precedence is Camera, Object, Material
		// Camera might not override object if not overrideable
		PolygonMode reqMode = pass->getPolygonMode();
		if (pass->getPolygonModeOverrideable() && rend->getPolygonModeOverrideable())
		{
            PolygonMode camPolyMode = mCameraInProgress->getPolygonMode();
			// check camera detial only when render detail is overridable
			if (reqMode > camPolyMode)
			{
				// only downgrade detail; if cam says wireframe we don't go up to solid
				reqMode = camPolyMode;
			}
		}
		mDestRenderSystem->_setPolygonMode(reqMode);

		if (doLightIteration)
		{
            // Create local light list for faster light iteration setup
            static LightList localLightList;


			// Here's where we issue the rendering operation to the render system
			// Note that we may do this once per light, therefore it's in a loop
			// and the light parameters are updated once per traversal through the
			// loop
			const LightList& rendLightList = rend->getLights();

			bool iteratePerLight = pass->getIteratePerLight();

			// deliberately unsigned in case start light exceeds number of lights
			// in which case this pass would be skipped
			int lightsLeft = 1;
			if (iteratePerLight)
			{
				lightsLeft = static_cast<int>(rendLightList.size()) - pass->getStartLight();
				// Don't allow total light count for all iterations to exceed max per pass
				if (lightsLeft > static_cast<int>(pass->getMaxSimultaneousLights()))
				{
					lightsLeft = static_cast<int>(pass->getMaxSimultaneousLights());
				}
			}


			const LightList* pLightListToUse;
			// Start counting from the start light
			size_t lightIndex = pass->getStartLight();
			size_t depthInc = 0;

			while (lightsLeft > 0)
			{
				// Determine light list to use
				if (iteratePerLight)
				{
					// Starting shadow texture index.
					size_t shadowTexIndex = mShadowTextures.size();
					if (mShadowTextureIndexLightList.size() > lightIndex)
						shadowTexIndex = mShadowTextureIndexLightList[lightIndex];

					localLightList.resize(pass->getLightCountPerIteration());

					LightList::iterator destit = localLightList.begin();
					unsigned short numShadowTextureLights = 0;
					for (; destit != localLightList.end() 
							&& lightIndex < rendLightList.size(); 
						++lightIndex, --lightsLeft)
					{
						Light* currLight = rendLightList[lightIndex];

						// Check whether we need to filter this one out
						if (pass->getRunOnlyForOneLightType() && 
							pass->getOnlyLightType() != currLight->getType())
						{
							// Skip
							// Also skip shadow texture(s)
							if (isShadowTechniqueTextureBased())
							{
								shadowTexIndex += mShadowTextureCountPerType[currLight->getType()];
							}
							continue;
						}

						*destit++ = currLight;

						// potentially need to update content_type shadow texunit
						// corresponding to this light
						if (isShadowTechniqueTextureBased())
						{
							size_t textureCountPerLight = mShadowTextureCountPerType[currLight->getType()];
							for (size_t j = 0; j < textureCountPerLight && shadowTexIndex < mShadowTextures.size(); ++j)
							{
								// link the numShadowTextureLights'th shadow texture unit
								unsigned short tuindex = 
									pass->_getTextureUnitWithContentTypeIndex(
									TextureUnitState::CONTENT_SHADOW, numShadowTextureLights);
								if (tuindex > pass->getNumTextureUnitStates()) break;

								// I know, nasty const_cast
								TextureUnitState* tu = 
									const_cast<TextureUnitState*>(
										pass->getTextureUnitState(tuindex));
								const TexturePtr& shadowTex = mShadowTextures[shadowTexIndex];
								tu->_setTexturePtr(shadowTex);
								Camera *cam = shadowTex->getBuffer()->getRenderTarget()->getViewport(0)->getCamera();
								tu->setProjectiveTexturing(!pass->hasVertexProgram(), cam);
								mAutoParamDataSource->setTextureProjector(cam, numShadowTextureLights);
								++numShadowTextureLights;
								++shadowTexIndex;
								// Have to set TU on rendersystem right now, although
								// autoparams will be set later
								mDestRenderSystem->_setTextureUnitSettings(tuindex, *tu);
							}
						}



					}
					// Did we run out of lights before slots? e.g. 5 lights, 2 per iteration
					if (destit != localLightList.end())
					{
						localLightList.erase(destit, localLightList.end());
						lightsLeft = 0;
					}
					pLightListToUse = &localLightList;

					// deal with the case where we found no lights
					// since this is light iteration, we shouldn't render at all
					if (pLightListToUse->empty())
						return;

				}
				else // !iterate per light
				{
					// Use complete light list potentially adjusted by start light
					if (pass->getStartLight() || pass->getMaxSimultaneousLights() != OGRE_MAX_SIMULTANEOUS_LIGHTS)
					{
						// out of lights?
						// skip manual 2nd lighting passes onwards if we run out of lights, but never the first one
						if (pass->getStartLight() > 0 &&
							pass->getStartLight() >= rendLightList.size())
						{
							lightsLeft = 0;
							break;
						}
						else
						{
							localLightList.clear();
							LightList::const_iterator copyStart = rendLightList.begin();
							std::advance(copyStart, pass->getStartLight());
							LightList::const_iterator copyEnd = copyStart;
							// Clamp lights to copy to avoid overrunning the end of the list
							size_t lightsToCopy = std::min(
								static_cast<size_t>(pass->getMaxSimultaneousLights()), 
								rendLightList.size() - pass->getStartLight());
							std::advance(copyEnd, lightsToCopy);
							localLightList.insert(localLightList.begin(), 
								copyStart, copyEnd);
							pLightListToUse = &localLightList;
						}
					}
					else
					{
						pLightListToUse = &rendLightList;
					}
					lightsLeft = 0;
				}

				fireRenderSingleObject(rend, pass, mAutoParamDataSource, pLightListToUse, mSuppressRenderStateChanges);

				// Do we need to update GPU program parameters?
				if (pass->isProgrammable())
				{
					useLightsGpuProgram(pass, pLightListToUse);
				}
				// Do we need to update light states? 
				// Only do this if fixed-function vertex lighting applies
				if (pass->getLightingEnabled() && passSurfaceAndLightParams)
				{
					useLights(*pLightListToUse, pass->getMaxSimultaneousLights());
				}
				// optional light scissoring & clipping
				ClipResult scissored = CLIPPED_NONE;
				ClipResult clipped = CLIPPED_NONE;
				if (lightScissoringClipping && 
					(pass->getLightScissoringEnabled() || pass->getLightClipPlanesEnabled()))
				{
					// if there's no lights hitting the scene, then we might as 
					// well stop since clipping cannot include anything
					if (pLightListToUse->empty())
						continue;

					if (pass->getLightScissoringEnabled())
						scissored = buildAndSetScissor(*pLightListToUse, mCameraInProgress);
				
					if (pass->getLightClipPlanesEnabled())
						clipped = buildAndSetLightClip(*pLightListToUse);

					if (scissored == CLIPPED_ALL || clipped == CLIPPED_ALL)
						continue;
				}
				// issue the render op		
				// nfz: check for gpu_multipass
				mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
				// We might need to update the depth bias each iteration
				if (pass->getIterationDepthBias() != 0.0f)
				{
					float depthBiasBase = pass->getDepthBiasConstant() + 
						pass->getIterationDepthBias() * depthInc;
					// depthInc deals with light iteration 
					
					// Note that we have to set the depth bias here even if the depthInc
					// is zero (in which case you would think there is no change from
					// what was set in _setPass(). The reason is that if there are
					// multiple Renderables with this Pass, we won't go through _setPass
					// again at the start of the iteration for the next Renderable
					// because of Pass state grouping. So set it always

					// Set modified depth bias right away
					mDestRenderSystem->_setDepthBias(depthBiasBase, pass->getDepthBiasSlopeScale());

					// Set to increment internally too if rendersystem iterates
					mDestRenderSystem->setDeriveDepthBias(true, 
						depthBiasBase, pass->getIterationDepthBias(), 
						pass->getDepthBiasSlopeScale());
				}
				else
				{
					mDestRenderSystem->setDeriveDepthBias(false);
				}
				depthInc += pass->getPassIterationCount();

				// Finalise GPU parameter bindings
				updateGpuProgramParameters(pass);

				if (rend->preRender(this, mDestRenderSystem))
					mDestRenderSystem->_render(ro);
				rend->postRender(this, mDestRenderSystem);

				if (scissored == CLIPPED_SOME)
					resetScissor();
				if (clipped == CLIPPED_SOME)
					resetLightClip();
			} // possibly iterate per light
		}
		else // no automatic light processing
		{
			// Even if manually driving lights, check light type passes
			bool skipBecauseOfLightType = false;
			if (pass->getRunOnlyForOneLightType())
			{
				if (!manualLightList ||
					(manualLightList->size() == 1 && 
					manualLightList->at(0)->getType() != pass->getOnlyLightType())) 
				{
					skipBecauseOfLightType = true;
				}
			}

			if (!skipBecauseOfLightType)
			{
				fireRenderSingleObject(rend, pass, mAutoParamDataSource, manualLightList, mSuppressRenderStateChanges);
				// Do we need to update GPU program parameters?
				if (pass->isProgrammable())
				{
					// Do we have a manual light list?
					if (manualLightList)
					{
						useLightsGpuProgram(pass, manualLightList);
					}

				}

				// Use manual lights if present, and not using vertex programs that don't use fixed pipeline
				if (manualLightList && 
					pass->getLightingEnabled() && passSurfaceAndLightParams)
				{
					useLights(*manualLightList, pass->getMaxSimultaneousLights());
				}

				// optional light scissoring
				ClipResult scissored = CLIPPED_NONE;
				ClipResult clipped = CLIPPED_NONE;
				if (lightScissoringClipping && manualLightList && pass->getLightScissoringEnabled())
				{
					scissored = buildAndSetScissor(*manualLightList, mCameraInProgress);
				}
				if (lightScissoringClipping && manualLightList && pass->getLightClipPlanesEnabled())
				{
					clipped = buildAndSetLightClip(*manualLightList);
				}
	
				// don't bother rendering if clipped / scissored entirely
				if (scissored != CLIPPED_ALL && clipped != CLIPPED_ALL)
				{
					// issue the render op		
					// nfz: set up multipass rendering
					mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
					// Finalise GPU parameter bindings
					updateGpuProgramParameters(pass);

					if (rend->preRender(this, mDestRenderSystem))
						mDestRenderSystem->_render(ro);
					rend->postRender(this, mDestRenderSystem);
				}
				if (scissored == CLIPPED_SOME)
					resetScissor();
				if (clipped == CLIPPED_SOME)
					resetLightClip();
				
			} // !skipBecauseOfLightType
		}

	}
	else // mSuppressRenderStateChanges
	{
		fireRenderSingleObject(rend, pass, mAutoParamDataSource, NULL, mSuppressRenderStateChanges);
		// Just render
		mDestRenderSystem->setCurrentPassIterationCount(1);
		if (rend->preRender(this, mDestRenderSystem))
			mDestRenderSystem->_render(ro);
		rend->postRender(this, mDestRenderSystem);
	}
	
    // Reset view / projection changes if any
    resetViewProjMode(passTransformState);

}

위의 단일 물체에 대해 중점 단계는 다음과 같다.
1. 월드 matrix 설정
2. culling mode 설정
3. polygon mode 설정
4, light 설정 -- SetLight(), EnableLight()
5. DrawPrimitive 등으로 도면 그리기

좋은 웹페이지 즐겨찾기