Process some scene traversals only once when rendering in stereo

--HG--
branch : multipass-stereo
This commit is contained in:
kaetemi 2014-08-06 14:36:09 +02:00
parent e8a245a133
commit 4e33e5cf2f
15 changed files with 226 additions and 103 deletions

View file

@ -139,7 +139,7 @@ public:
* \param renderPart : The part of the scene that must be rendered
* \param newRender true If scene render is beginning. Otherwise other parts of the scene have already been rendered.
*/
void traverse(UScene::TRenderPart renderPart, bool newRender);
void traverse(UScene::TRenderPart renderPart, bool newRender, bool generateShadows);
//@}
/// \name RenderList.

View file

@ -157,7 +157,7 @@ public:
* \param doHrcPass set it to false to indicate that the CHrcTrav have not to be traversed. Useful to optimize if
* you know that NONE of your models have moved (a good example is a shoot of the scene from different cameras).
*/
void render(bool doHrcPass=true);
void render(bool doHrcPass = true);
/** Begin Part Rendering
* During beginPartRender()/endPartRender(), you can ask other scene to render their part, but you should
@ -171,10 +171,10 @@ public:
* WARNING: always must begin rendering with at least UScene::RenderOpaque, else shadows won't work
* WARNING: assert-crash if a part in 'rp' has already been rendered since the last beginPartRender()
*/
void renderPart(UScene::TRenderPart rp, bool doHrcPass=true);
void renderPart(UScene::TRenderPart rp, bool doHrcPass = true, bool doTrav = true, bool keepTrav = false);
/** End Part Rendering (commit model creation and deletion that were asked during rendering)
*/
void endPartRender();
void endPartRender(bool keepTrav = false);
//@}

View file

@ -96,8 +96,8 @@ public:
// render methods
virtual void render(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true);
virtual void beginPartRender();
virtual void renderPart(TRenderPart rp);
virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true);
virtual void renderPart(TRenderPart rp, bool doHrcPass = true, bool doTrav = true, bool keepTrav = false);
virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true, bool keepTrav = true);
// update async loading whithout a call to render
virtual void updateWaitingInstances(double ellapsedTime);

View file

@ -93,14 +93,21 @@ public:
virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const;
/// At the start of a new render target
virtual bool wantClear();
virtual bool wantClear();
/// The 3D scene
virtual bool wantScene();
/// Scene post processing effects
virtual bool wantSceneEffects();
/// Interface within the 3D scene
virtual bool wantInterface3D();
/// 2D Interface
virtual bool wantInterface2D();
/// Is this the first 3D scene of the frame
virtual bool isSceneFirst();
/// Is this the last 3D scene of the frame
virtual bool isSceneLast();
/// Returns true if a new render target was set, always fase if not using render targets
virtual bool beginRenderTarget();
/// Returns true if a render target was fully drawn, always false if not using render targets

View file

@ -116,14 +116,21 @@ public:
virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const = 0;
/// At the start of a new render target
virtual bool wantClear() = 0;
virtual bool wantClear() = 0;
/// The 3D scene
virtual bool wantScene() = 0;
/// Scene post processing effects
virtual bool wantSceneEffects() = 0;
/// Interface within the 3D scene
virtual bool wantInterface3D() = 0;
/// 2D Interface
virtual bool wantInterface2D() = 0;
/// Is this the first 3D scene of the frame
virtual bool isSceneFirst() = 0;
/// Is this the last 3D scene of the frame
virtual bool isSceneLast() = 0;
/// Returns true if a new render target was set, always fase if not using render targets
virtual bool beginRenderTarget() = 0;
/// Returns true if a render target was fully drawn, always false if not using render targets

View file

@ -110,14 +110,21 @@ public:
virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const;
/// At the start of a new render target
virtual bool wantClear();
virtual bool wantClear();
/// The 3D scene
virtual bool wantScene();
/// Scene post processing effects
virtual bool wantSceneEffects();
/// Interface within the 3D scene
virtual bool wantInterface3D();
/// 2D Interface
virtual bool wantInterface2D();
/// Is this the first 3D scene of the frame
virtual bool isSceneFirst();
/// Is this the last 3D scene of the frame
virtual bool isSceneLast();
/// Returns true if a new render target was set, always fase if not using render targets
virtual bool beginRenderTarget();
/// Returns true if a render target was fully drawn, always false if not using render targets

View file

@ -134,14 +134,17 @@ public:
/** Render a part (see render() for what it does)
* beginPartRender() must have been called
* \param renderPart a combination of UScene::TRenderPart flags, allow to choose which part of the scene must be rendered
* \param doHrcPass set it to false to indicate that the CHrcTrav have not to be traversed. Useful to optimize if
* you know that NONE of your models have moved (a good example is a shoot of the scene from different cameras).
* \param doTrav set to false when processing a second frame for stereo rending to avoid unnecessary traversals.
* WARNING: always must begin rendering with at least UScene::RenderOpaque, else shadows won't work
* WARNING: assert-crash if a part in 'rp' has already been rendered since the last beginPartRender()
*/
virtual void renderPart(UScene::TRenderPart rp) =0;
virtual void renderPart(UScene::TRenderPart rp, bool doHrcPass = true, bool doTrav = true, bool keepTrav = false) =0;
/** End Part Rendering (commit model creation and deletion that were asked during rendering)
*/
virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true) =0;
virtual void endPartRender(bool updateWaitingInstances = true, bool restoreMatrixContextAfterRender = true, bool keepTrav = false) =0;
/** Update waiting instances and igs that are loaded asynchronously

View file

@ -92,7 +92,7 @@ CRenderTrav::CRenderTrav()
// ***************************************************************************
void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender)
void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender, bool generateShadows)
{
#ifdef NL_DEBUG_RENDER_TRAV
nlwarning("Render trave begin");
@ -279,7 +279,8 @@ void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender)
*/
// Generate ShadowMaps
_ShadowMapManager.renderGenerate(Scene);
if (generateShadows)
_ShadowMapManager.renderGenerate(Scene);
// Render the Landscape
renderLandscapes();

View file

@ -353,28 +353,31 @@ void CScene::beginPartRender()
// ***************************************************************************
void CScene::endPartRender()
void CScene::endPartRender(bool keepTrav)
{
nlassert(_IsRendering);
// Delete model deleted during the rendering
_IsRendering = false;
uint i;
for (i=0; i<_ToDelete.size(); i++)
deleteModel (_ToDelete[i]);
_ToDelete.clear ();
// Special for SkeletonSpawnScript animation. create models spawned now
flushSSSModelRequests();
if (!keepTrav)
{
// Delete model deleted during the rendering
uint i;
for (i=0; i<_ToDelete.size(); i++)
deleteModel (_ToDelete[i]);
_ToDelete.clear ();
// Particle system handling (remove the resources of those which are too far, as their clusters may not have been parsed).
// Note that only a few of them are tested at each call
_ParticleSystemManager.refreshModels(ClipTrav.WorldFrustumPyramid, ClipTrav.CamPos);
// Special for SkeletonSpawnScript animation. create models spawned now
flushSSSModelRequests();
// Waiting Instance handling
double deltaT = _DeltaSystemTimeBetweenRender;
clamp (deltaT, 0.01, 0.1);
updateWaitingInstances(deltaT);
// Particle system handling (remove the resources of those which are too far, as their clusters may not have been parsed).
// Note that only a few of them are tested at each call
_ParticleSystemManager.refreshModels(ClipTrav.WorldFrustumPyramid, ClipTrav.CamPos);
// Waiting Instance handling
double deltaT = _DeltaSystemTimeBetweenRender;
clamp (deltaT, 0.01, 0.1);
updateWaitingInstances(deltaT);
}
// Reset profiling
_NextRenderProfile= false;
@ -555,7 +558,7 @@ void CScene::endPartRender()
// ***************************************************************************
void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass)
void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass, bool doTrav, bool keepTrav)
{
nlassert(_IsRendering);
@ -569,25 +572,31 @@ void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass)
// if first part to be rendered, do the start stuff
if (_RenderedPart == UScene::RenderNothing)
{
// update water envmap
//updateWaterEnvmap();
RenderTrav.clearWaterModelList();
_FirstFlare = NULL;
double fNewGlobalSystemTime = NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime());
if(_GlobalSystemTime==0)
_DeltaSystemTimeBetweenRender= 0.020;
else
_DeltaSystemTimeBetweenRender= fNewGlobalSystemTime - _GlobalSystemTime;
_GlobalSystemTime = fNewGlobalSystemTime;
if (doTrav)
{
// update water envmap
//updateWaterEnvmap();
_FirstFlare = NULL;
double fNewGlobalSystemTime = NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime());
if(_GlobalSystemTime==0)
_DeltaSystemTimeBetweenRender= 0.020;
else
_DeltaSystemTimeBetweenRender= fNewGlobalSystemTime - _GlobalSystemTime;
_GlobalSystemTime = fNewGlobalSystemTime;
}
//
++ _NumRender;
//
nlassert(CurrentCamera);
// update models.
updateModels();
// Use the camera to setup Clip / Render pass.
float left, right, bottom, top, znear, zfar;
CurrentCamera->getFrustum(left, right, bottom, top, znear, zfar);
@ -609,49 +618,70 @@ void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass)
// **** For all render traversals, traverse them (except the Hrc one), in ascending order.
if( doHrcPass )
HrcTrav.traverse();
else
HrcTrav._MovingObjects.clear();
// Set Cam World Matrix for all trav that need it
ClipTrav.setCamMatrix(CurrentCamera->getWorldMatrix());
RenderTrav.setCamMatrix (CurrentCamera->getWorldMatrix());
LoadBalancingTrav.setCamMatrix (CurrentCamera->getWorldMatrix());
// clip
ClipTrav.traverse();
// animDetail
AnimDetailTrav.traverse();
if (doTrav)
{
// animDetail
AnimDetailTrav.traverse();
}
// loadBalance
LoadBalancingTrav.traverse();
//
if (_RequestParticlesAnimate)
if (doTrav)
{
_ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems
_RequestParticlesAnimate = false;
//
if (_RequestParticlesAnimate)
{
_ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems
_RequestParticlesAnimate = false;
}
}
// Light
LightTrav.traverse();
}
// render
RenderTrav.traverse(rp, _RenderedPart == UScene::RenderNothing);
// Always must clear shadow caster (if render did not work because of IDriver::isLost())
RenderTrav.getShadowMapManager().clearAllShadowCasters();
RenderTrav.traverse(rp, (_RenderedPart == UScene::RenderNothing), doTrav);
if (!keepTrav)
{
// Always must clear shadow caster (if render did not work because of IDriver::isLost())
RenderTrav.getShadowMapManager().clearAllShadowCasters();
}
// render flare
if (rp & UScene::RenderFlare)
{
if (_FirstFlare)
if (doTrav)
{
IDriver *drv = getDriver();
CFlareModel::updateOcclusionQueryBegin(drv);
CFlareModel *currFlare = _FirstFlare;
do
if (_FirstFlare)
{
currFlare->updateOcclusionQuery(drv);
currFlare = currFlare->Next;
IDriver *drv = getDriver();
CFlareModel::updateOcclusionQueryBegin(drv);
CFlareModel *currFlare = _FirstFlare;
do
{
currFlare->updateOcclusionQuery(drv);
currFlare = currFlare->Next;
}
while(currFlare);
CFlareModel::updateOcclusionQueryEnd(drv);
}
while(currFlare);
CFlareModel::updateOcclusionQueryEnd(drv);
}
else
{
_FirstFlare = NULL;
}
}
_RenderedPart = (UScene::TRenderPart) (_RenderedPart | rp);

View file

@ -517,7 +517,7 @@ void CSceneUser::beginPartRender()
}
// ***************************************************************************
void CSceneUser::renderPart(TRenderPart rp)
void CSceneUser::renderPart(TRenderPart rp, bool doHrcPass, bool doTrav, bool keepTrav)
{
// render the scene.
@ -526,18 +526,18 @@ void CSceneUser::renderPart(TRenderPart rp)
if(_Scene.getCam() == NULL)
nlerror("render(): try to render with no camera linked (may have been deleted)");
_Scene.renderPart(rp, true);
_Scene.renderPart(rp, doHrcPass, doTrav, keepTrav);
}
}
// ***************************************************************************
void CSceneUser::endPartRender(bool updateWaitingInstancesFlag, bool restoreMatrixContextAfterRender)
void CSceneUser::endPartRender(bool updateWaitingInstancesFlag, bool restoreMatrixContextAfterRender, bool keepTrav)
{
// render the scene.
{
NL3D_HAUTO_RENDER_SCENE_END
_Scene.endPartRender();
_Scene.endPartRender(keepTrav);
}
if (updateWaitingInstancesFlag) updateWaitingInstances();

View file

@ -415,6 +415,12 @@ bool CStereoDebugger::wantScene()
return m_Stage != 3;
}
/// The 3D scene end (after multiple wantScene)
bool CStereoDebugger::wantSceneEffects()
{
return m_Stage != 3;
}
/// Interface within the 3D scene
bool CStereoDebugger::wantInterface3D()
{
@ -429,6 +435,16 @@ bool CStereoDebugger::wantInterface2D()
return m_Stage == 3;
}
bool CStereoDebugger::isSceneFirst()
{
return m_Stage == 1;
}
bool CStereoDebugger::isSceneLast()
{
return m_Stage == 2;
}
/// Returns true if a new render target was set, always fase if not using render targets
bool CStereoDebugger::beginRenderTarget()
{

View file

@ -640,6 +640,16 @@ bool CStereoOVR::wantScene()
return m_Driver->getPolygonMode() != UDriver::Filled;
}
bool CStereoOVR::wantSceneEffects()
{
switch (m_Stage)
{
case 4:
return true;
}
return m_Driver->getPolygonMode() != UDriver::Filled;
}
bool CStereoOVR::wantInterface3D()
{
switch (m_Stage)
@ -663,6 +673,26 @@ bool CStereoOVR::wantInterface2D()
return m_Driver->getPolygonMode() != UDriver::Filled;
}
bool CStereoOVR::isSceneFirst()
{
switch (m_Stage)
{
case 3:
return true;
}
return m_Driver->getPolygonMode() != UDriver::Filled;
}
bool CStereoOVR::isSceneLast()
{
switch (m_Stage)
{
case 4:
return true;
}
return m_Driver->getPolygonMode() != UDriver::Filled;
}
/// Returns non-NULL if a new render target was set
bool CStereoOVR::beginRenderTarget()
{

View file

@ -97,7 +97,9 @@ private:
// renderScene is called in main loop. It can called beginRenderLandscapePolyPart and renderLandscapePolyPart
// methods.
friend void renderScene();
friend void beginRenderScene();
friend void drawRenderScene(bool wantTraversals, bool keepTraversals);
friend void endRenderScene(bool keepTraversals);
// Enable stencil test and initialize function and operation of stencil at the beginning of renderScene method,
// before opaque render of canopy and main scene parts.

View file

@ -423,9 +423,9 @@ void beginRenderMainScenePart()
{
Scene->beginPartRender();
}
void endRenderMainScenePart()
void endRenderMainScenePart(bool keepTraversals)
{
Scene->endPartRender(true);
Scene->endPartRender(!keepTraversals, true, keepTraversals);
}
void beginRenderSkyPart()
@ -462,7 +462,7 @@ static void renderCanopyPart(UScene::TRenderPart renderPart)
// ***************************************************************************************************************************
// Render a part of the main scene
static void renderMainScenePart(UScene::TRenderPart renderPart)
static void renderMainScenePart(UScene::TRenderPart renderPart, bool wantTraversals, bool keepTraversals)
{
H_AUTO_USE ( RZ_Client_Main_Loop_Render_Main )
Driver->setDepthRange(0.f, CANOPY_DEPTH_RANGE_START);
@ -474,7 +474,7 @@ static void renderMainScenePart(UScene::TRenderPart renderPart)
{
MainFogState.setupInDriver (*Driver);
}
Scene->renderPart(renderPart);
Scene->renderPart(renderPart, true, wantTraversals, keepTraversals);
}
@ -580,7 +580,7 @@ void renderScene(bool forceFullDetail, bool bloom)
s_ForceFullDetail.set();
}
clearBuffers();
renderScene();
doRenderScene(true, false);
if (forceFullDetail)
{
s_ForceFullDetail.restore();
@ -719,9 +719,7 @@ void updateWeather()
}
}
// ***************************************************************************************************************************
// Render all scenes
void renderScene()
void beginRenderScene()
{
// Update Filter Flags
Scene->enableElementRender(UScene::FilterAllMeshNoVP, Filter3D[FilterMeshNoVP]);
@ -743,28 +741,45 @@ void renderScene()
beginRenderCanopyPart();
beginRenderMainScenePart();
beginRenderSkyPart();
}
void drawRenderScene(bool wantTraversals, bool keepTraversals)
{
// Render part
// WARNING: always must begin rendering with at least UScene::RenderOpaque,
// else dynamic shadows won't work
renderCanopyPart(UScene::RenderOpaque);
renderMainScenePart(UScene::RenderOpaque);
renderMainScenePart(UScene::RenderOpaque, wantTraversals, keepTraversals);
// render of polygons on landscape
CLandscapePolyDrawer::getInstance().renderLandscapePolyPart();
if (s_SkyMode != NoSky) renderSkyPart((UScene::TRenderPart) (UScene::RenderOpaque | UScene::RenderTransparent));
renderCanopyPart((UScene::TRenderPart) (UScene::RenderTransparent | UScene::RenderFlare));
renderMainScenePart((UScene::TRenderPart) (UScene::RenderTransparent | UScene::RenderFlare));
renderMainScenePart((UScene::TRenderPart) (UScene::RenderTransparent | UScene::RenderFlare), wantTraversals, keepTraversals);
if (s_SkyMode == NewSky) renderSkyPart(UScene::RenderFlare);
}
void endRenderScene(bool keepTraversals)
{
// End Part Rendering
endRenderSkyPart();
endRenderMainScenePart();
endRenderMainScenePart(keepTraversals);
endRenderCanopyPart();
// reset depth range
Driver->setDepthRange(0.f, CANOPY_DEPTH_RANGE_START);
}
// ***************************************************************************************************************************
// Render all scenes
void doRenderScene(bool wantTraversals, bool keepTraversals)
{
beginRenderScene();
drawRenderScene(wantTraversals, keepTraversals);
endRenderScene(keepTraversals);
}
// ***************************************************************************
class CMusicFader
@ -1628,7 +1643,6 @@ bool mainLoop()
}
uint i = 0;
bool effectRender = false;
CTextureUser *effectRenderTarget = NULL;
bool haveEffects = Render && Driver->getPolygonMode() == UDriver::Filled
&& (ClientCfg.Bloom || FXAA);
@ -1646,6 +1660,7 @@ bool mainLoop()
CBloomEffect::getInstance().setDensityBloom((uint8)ClientCfg.DensityBloom);
}
}
bool fullDetail = false;
while ((!StereoDisplay && i == 0) || (StereoDisplay && StereoDisplay->nextPass()))
{
++i;
@ -1686,42 +1701,59 @@ bool mainLoop()
if (!StereoDisplay || StereoDisplay->wantClear())
{
if (Render)
{
effectRender = haveEffects;
}
// Clear buffers
clearBuffers();
}
if (!StereoDisplay || StereoDisplay->wantScene())
{
if (!ClientCfg.Light)
if (!ClientCfg.Light && Render)
{
// Render
if(Render)
if (!StereoDisplay || StereoDisplay->isSceneFirst())
{
// nb : force full detail if a screenshot is asked
// todo : move outside render code
bool fullDetail = ScreenshotRequest != ScreenshotRequestNone && ClientCfg.ScreenShotFullDetail;
if (fullDetail)
if (!fullDetail)
{
s_ForceFullDetail.backup();
s_ForceFullDetail.set();
fullDetail = ScreenshotRequest != ScreenshotRequestNone && ClientCfg.ScreenShotFullDetail;
if (fullDetail)
{
s_ForceFullDetail.backup();
s_ForceFullDetail.set();
}
}
}
// Render scene
renderScene();
// Render scene
bool wantTraversals = !StereoDisplay || StereoDisplay->isSceneFirst();
bool keepTraversals = StereoDisplay && !StereoDisplay->isSceneLast();
doRenderScene(wantTraversals, keepTraversals);
if (!StereoDisplay || StereoDisplay->isSceneLast())
{
if (fullDetail)
{
s_ForceFullDetail.restore();
fullDetail = false;
}
}
}
}
if (!StereoDisplay || StereoDisplay->wantSceneEffects())
{
if (!ClientCfg.Light && Render && haveEffects)
{
if (StereoDisplay) Driver->setViewport(NL3D::CViewport());
UCamera pCam = Scene->getCam();
Driver->setMatrixMode2D11();
if (FXAA) FXAA->applyEffect();
if (ClientCfg.Bloom) CBloomEffect::instance().applyBloom();
Driver->setMatrixMode3D(pCam);
if (StereoDisplay) Driver->setViewport(StereoDisplay->getCurrentViewport());
}
}
if (!StereoDisplay || StereoDisplay->wantInterface3D())
{
if (!ClientCfg.Light)
@ -1729,18 +1761,6 @@ bool mainLoop()
// Render
if (Render)
{
if (effectRender)
{
if (StereoDisplay) Driver->setViewport(NL3D::CViewport());
UCamera pCam = Scene->getCam();
Driver->setMatrixMode2D11();
if (FXAA) FXAA->applyEffect();
if (ClientCfg.Bloom) CBloomEffect::instance().applyBloom();
Driver->setMatrixMode3D(pCam);
if (StereoDisplay) Driver->setViewport(StereoDisplay->getCurrentViewport());
effectRender = false;
}
// for that frame and
// tmp : display height grid
//static volatile bool displayHeightGrid = true;

View file

@ -29,7 +29,7 @@ const uint NUM_MISSION_OPTIONS = 8;
bool mainLoop();
// render all
void renderScene();
void doRenderScene(bool wantTraversals, bool keepTraversals);
void renderScene(bool forceFullDetail, bool bloom);
void setDefaultChatWindow(CChatWindow *defaultChatWindow);