#include "RenderTraverser.h" #include "glInterface.h" #include "Camera.h" #include "SceneEntity.h" #include "RenderState.h" #include "Geometry.h" #include "Timer/PerfTimer.h" using namespace std; namespace CHCDemoEngine { void TraversalStatistics::Reset() { mNumTraversedNodes = 0; mNumQueryCulledNodes = 0; mNumFrustumCulledNodes = 0; mNumRenderedGeometry = 0; mNumRenderedTriangles = 0; mNumRenderedNodes = 0; mNumIssuedQueries = 0; mNumStateChanges = 0; mNumBatches = 0; mRenderTime = 0; mWaitTime = 0; mQueryTime = 0; mRestTime = 0; } /******************************************************/ /* RenderTraverser implementation */ /******************************************************/ RenderTraverser::RenderTraverser(): mVisibilityThreshold(0), mBvh(NULL), mUseOptimization(false), mFrameId(-1), mUseRenderQueue(false), mAssumedVisibleFrames(10), mMaxBatchSize(50), mUseTightBounds(false), mShowBounds(false) { } RenderTraverser::~RenderTraverser() { mQueryHandler.DestroyQueries(); } void RenderTraverser::EnqueueNode(BvhNode *node) { mBvh->CalcDistance(node); mDistanceQueue.push(node); } void RenderTraverser::TraverseNode(BvhNode *node) { ++ mStats.mNumTraversedNodes; if (node->IsVirtualLeaf()) { RenderNode(node); if (mShowBounds) mBvh->RenderBoundsForViz(node, mUseTightBounds); } else { // for non leafs this renders only the bounding volume (if the flag is set) BvhInterior *interior = static_cast(node); EnqueueNode(interior->GetFront()); EnqueueNode(interior->GetBack()); } } void RenderTraverser::RenderNode(BvhNode *node) { if (node->GetLastRenderedFrame() != mFrameId) { if (mRenderState->SetState(RenderState::RENDER)) ++ mStats.mNumStateChanges; node->SetLastRenderedFrame(mFrameId); int geometrySize; SceneEntity **entities = mBvh->GetGeometry(node, geometrySize); mStats.mNumRenderedGeometry += geometrySize; ++ mStats.mNumRenderedNodes; for (int i = 0; i < geometrySize; ++ i) { SceneEntity *ent = entities[i]; mStats.mNumRenderedTriangles += ent->GetGeometry()->GetNumTriangles(); if (mUseRenderQueue) mRenderQueue.Enqueue(ent); else ent->Render(mRenderState); } } } void RenderTraverser::SetHierarchy(Bvh *bvh) { mBvh = bvh; } void RenderTraverser::SetRenderState(RenderState *state) { mRenderState = state; mRenderQueue.SetRenderState(state); } void RenderTraverser::RenderScene() { PerfTimer timer; glFinish(); timer.Start(); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); ++ mFrameId; mBvh->InitFrame(); mStats.Reset(); mQueryHandler.ResetQueries(); EnqueueNode(mBvh->GetRoot()); /////////// //-- the actual rendering algorithm Traverse(); // render the contents of the render queue if (mUseRenderQueue) ApplyRenderQueue(); // reset the render state mRenderState->Reset(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glFinish(); mStats.mRenderTime = timer.Elapsedms(); //Debug << "type: " << GetType() << endl; //if (mUseRenderQueue) Debug << "rq sort: " << 1e3f * mRenderQueue.sortTimer.TotalTime() << " ms" << endl; /* Debug << "wait time: " << 1e3f * waitTimer.TotalTime() << " ms" << endl; Debug << "query time: " << 1e3f * queryTimer.TotalTime() << " ms" << endl; Debug << "rest time: " << 1e3f * restTimer.TotalTime() << " ms" << endl; */ } void RenderTraverser::SetUseRenderQueue(bool useRenderQueue) { mUseRenderQueue = useRenderQueue; //std::cout << "using render queue: " << mUseRenderQueue << std::endl; } void RenderTraverser::SetVisibilityThreshold(int threshold) { mVisibilityThreshold = threshold; } void RenderTraverser::SetUseOptimization(bool useOptimization) { mUseOptimization = useOptimization; //cout << "using optimization: " << mUseOptimization << endl; } void RenderTraverser::SetAssumedVisibleFrames(int assumedVisibleFrames) { mAssumedVisibleFrames = assumedVisibleFrames; } void RenderTraverser::SetMaxBatchSize(int batchSize) { mMaxBatchSize = batchSize; } void RenderTraverser::SetUseMultiQueries(bool useMultiQueries) { mUseMultiQueries = useMultiQueries; //cout << "using multiqueries: " << mUseMultiQueries << endl; } void RenderTraverser::SetShowBounds(bool showBounds) { mShowBounds = showBounds; } void RenderTraverser::SetUseTightBounds(bool useTightBounds) { mUseTightBounds = useTightBounds; //cout << "using tight bounds: " << useTightBounds << endl; } OcclusionQuery *RenderTraverser::IssueOcclusionQuery(BvhNode *node) { queryTimer.Entry(); OcclusionQuery *query = mQueryHandler.RequestQuery(); query->AddNode(node); IssueOcclusionQuery(*query); queryTimer.Exit(); return query; } void RenderTraverser::IssueOcclusionQuery(const OcclusionQuery &query) { ++ mStats.mNumIssuedQueries; // render pending objects before changing to query mode if (mUseRenderQueue && (mRenderState->GetMode() == RenderState::RENDER)) ApplyRenderQueue(); query.BeginQuery(); // change to query mode and render box if (mRenderState->SetState(RenderState::QUERY)) ++ mStats.mNumStateChanges; mBvh->RenderBounds(query.GetNodes(), mRenderState, mUseTightBounds); query.EndQuery(); } void RenderTraverser::ApplyRenderQueue() { if (mRenderState->SetState(RenderState::RENDER)) ++ mStats.mNumStateChanges; if (mRenderQueue.GetSize() > 0) ++ mStats.mNumBatches; mRenderQueue.Apply(); } }