#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; 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), mRenderQueue(NULL) { } 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, mRenderState, 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->CountNumTriangles(); if (mUseRenderQueue) mRenderQueue->Enqueue(ent); else ent->Render(mRenderState); // store the visible entities for rendering in the second pass if (mUseDepthPass) mVisibleObjects.push_back(ent); } } } void RenderTraverser::SetHierarchy(Bvh *bvh) { mBvh = bvh; } void RenderTraverser::SetRenderState(RenderState *state) { mRenderState = state; } void RenderTraverser::RenderScene() { mVisibleObjects.clear(); glEnableClientState(GL_VERTEX_ARRAY); if (!mUseDepthPass) 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); //cout << "rq overhead: " << 1e3f * mRenderQueue->rTimer.TotalTime() << " ms" << endl; } void RenderTraverser::SetUseRenderQueue(bool useRenderQueue) { mUseRenderQueue = useRenderQueue; //std::cout << "using render queue: " << mUseRenderQueue << std::endl; } void RenderTraverser::SetUseDepthPass(bool b) { mUseDepthPass = b; } 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) { OcclusionQuery *query = mQueryHandler.RequestQuery(); query->AddNode(node); IssueOcclusionQuery(*query); 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(); } } }