diff --git a/KREngine/KREngine/Classes/KRCamera.cpp b/KREngine/KREngine/Classes/KRCamera.cpp index 5d8b345..5374564 100644 --- a/KREngine/KREngine/Classes/KRCamera.cpp +++ b/KREngine/KREngine/Classes/KRCamera.cpp @@ -179,8 +179,6 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { KRVector3 vecCameraDirection = m_viewport.getCameraDirection(); - std::set newVisibleBounds; - // GLuint shadowDepthTexture[KRENGINE_MAX_SHADOW_BUFFERS]; // KRViewport shadowViewports[KRENGINE_MAX_SHADOW_BUFFERS]; // int cShadows = 0; @@ -209,10 +207,10 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glDisable(GL_BLEND)); // Render the geometry - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_DEFERRED_GBUFFER, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_DEFERRED_GBUFFER); // ----====---- Generate Shadowmaps for Lights ----====---- - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS); GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y)); // ----====---- Opaque Geometry, Deferred rendering Pass 2 ----====---- @@ -239,7 +237,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { // Render the geometry - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS); // ----====---- Opaque Geometry, Deferred rendering Pass 3 ----====---- // Set render target @@ -270,8 +268,8 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glDepthMask(GL_TRUE)); // Render the geometry - std::set emptyBoundsSet; // At this point, we only render octree nodes that produced fragments during the 1st pass into the GBuffer - scene.render(this, emptyBoundsSet, m_viewport, KRNode::RENDER_PASS_DEFERRED_OPAQUE, newVisibleBounds); + // TODO: At this point, we only want to render octree nodes that produced fragments during the 1st pass into the GBuffer + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_DEFERRED_OPAQUE); // Deactivate source buffer texture units m_pContext->getTextureManager()->selectTexture(6, NULL); @@ -282,7 +280,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glBindTexture(GL_TEXTURE_2D, 0)); } else { // ----====---- Generate Shadowmaps for Lights ----====---- - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS); GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y)); // ----====---- Opaque Geometry, Forward Rendering ----====---- @@ -313,7 +311,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { // Render the geometry - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_FORWARD_OPAQUE, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_FORWARD_OPAQUE); } // ----====---- Sky Box ----====---- @@ -372,7 +370,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); // Render all transparent geometry - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_FORWARD_TRANSPARENT, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_FORWARD_TRANSPARENT); // ----====---- Flares ----====---- @@ -396,7 +394,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glBlendFunc(GL_ONE, GL_ONE)); // Render all flares - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_ADDITIVE_PARTICLES, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_ADDITIVE_PARTICLES); // ----====---- Volumetric Lighting ----====---- @@ -424,7 +422,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glDepthRangef(0.0, 1.0)); } - scene.render(this, m_viewport.getVisibleBounds(), volumetricLightingViewport, KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE, newVisibleBounds); + scene.render(this, m_viewport.getVisibleBounds(), volumetricLightingViewport, KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE); if(volumetric_environment_downsample != 0) { // Set render target @@ -459,10 +457,10 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { KRMat4 projectionMatrix = getProjectionMatrix(); m_pContext->getModelManager()->bindVBO((void *)KRENGINE_VBO_3D_CUBE, KRENGINE_VBO_3D_CUBE_SIZE, true, false, false, false, false); - for(std::set::iterator itr=m_viewport.getVisibleBounds().begin(); itr != m_viewport.getVisibleBounds().end(); itr++) { + for(std::map::iterator itr=m_viewport.getVisibleBounds().begin(); itr != m_viewport.getVisibleBounds().end(); itr++) { KRMat4 matModel = KRMat4(); - matModel.scale((*itr).size() / 2.0f); - matModel.translate((*itr).center()); + matModel.scale((*itr).first.size() / 2.0f); + matModel.translate((*itr).first.center()); if(getContext().getShaderManager()->selectShader(pVisShader, m_viewport, matModel, std::vector(), KRNode::RENDER_PASS_FORWARD_TRANSPARENT)) { GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 14)); @@ -470,8 +468,6 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { } } - m_viewport.setVisibleBounds(newVisibleBounds); - // Re-enable z-buffer write GLDEBUG(glDepthMask(GL_TRUE)); diff --git a/KREngine/KREngine/Classes/KRLight.cpp b/KREngine/KREngine/Classes/KRLight.cpp index 281dcaa..ee891f5 100644 --- a/KREngine/KREngine/Classes/KRLight.cpp +++ b/KREngine/KREngine/Classes/KRLight.cpp @@ -300,9 +300,7 @@ void KRLight::renderShadowBuffers(KRCamera *pCamera) getContext().getShaderManager()->selectShader(shadowShader, m_shadowViewports[iShadow], KRMat4(), std::vector(), KRNode::RENDER_PASS_SHADOWMAP); - std::set newVisibleBounds; - getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP, newVisibleBounds); - m_shadowViewports[iShadow].setVisibleBounds(newVisibleBounds); + getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP); } } diff --git a/KREngine/KREngine/Classes/KRScene.cpp b/KREngine/KREngine/Classes/KRScene.cpp index 3fc7611..073a8c3 100644 --- a/KREngine/KREngine/Classes/KRScene.cpp +++ b/KREngine/KREngine/Classes/KRScene.cpp @@ -45,6 +45,8 @@ #import "KRPointLight.h" #import "KRQuaternion.h" +const long KRENGINE_OCCLUSION_TEST_EXPIRY = 60; + KRScene::KRScene(KRContext &context, std::string name) : KRResource(context, name) { m_pFirstLight = NULL; m_pRootNode = new KRNode(*this, "scene_root"); @@ -58,7 +60,7 @@ KRScene::~KRScene() { #if TARGET_OS_IPHONE -void KRScene::render(KRCamera *pCamera, const std::set &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, std::set &newVisibleBounds) { +void KRScene::render(KRCamera *pCamera, std::map &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass) { std::vector lights; @@ -96,10 +98,10 @@ void KRScene::render(KRCamera *pCamera, const std::set &visibleBounds, c newRemainingOctrees.clear(); newRemainingOctreesTestResults.clear(); for(std::vector::iterator octree_itr = remainingOctrees.begin(); octree_itr != remainingOctrees.end(); octree_itr++) { - render(*octree_itr, visibleBounds, pCamera, lights, viewport, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, false, false); + render(*octree_itr, visibleBounds, pCamera, lights, viewport, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, false, false); } for(std::vector::iterator octree_itr = remainingOctreesTestResults.begin(); octree_itr != remainingOctreesTestResults.end(); octree_itr++) { - render(*octree_itr, visibleBounds, pCamera, lights, viewport, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, true, false); + render(*octree_itr, visibleBounds, pCamera, lights, viewport, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, true, false); } remainingOctrees = newRemainingOctrees; remainingOctreesTestResults = newRemainingOctreesTestResults; @@ -108,11 +110,23 @@ void KRScene::render(KRCamera *pCamera, const std::set &visibleBounds, c newRemainingOctrees.clear(); newRemainingOctreesTestResults.clear(); for(std::vector::iterator octree_itr = remainingOctreesTestResultsOnly.begin(); octree_itr != remainingOctreesTestResultsOnly.end(); octree_itr++) { - render(*octree_itr, visibleBounds, pCamera, lights, viewport, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, true, true); + render(*octree_itr, visibleBounds, pCamera, lights, viewport, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, true, true); + } + + + // Expire cached occlusion test results + std::set expired_visible_bounds; + for(std::map::iterator visible_bounds_itr = visibleBounds.begin(); visible_bounds_itr != visibleBounds.end(); visible_bounds_itr++) { + if((*visible_bounds_itr).second + KRENGINE_OCCLUSION_TEST_EXPIRY < getContext().getCurrentFrame()) { + expired_visible_bounds.insert((*visible_bounds_itr).first); + } + } + for(std::set::iterator expired_visible_bounds_itr = expired_visible_bounds.begin(); expired_visible_bounds_itr != expired_visible_bounds.end(); expired_visible_bounds_itr++) { + visibleBounds.erase(*expired_visible_bounds_itr); } } -void KRScene::render(KROctreeNode *pOctreeNode, const std::set &visibleBounds, KRCamera *pCamera, std::vector lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector &remainingOctrees, std::vector &remainingOctreesTestResults, std::vector &remainingOctreesTestResultsOnly, std::set &newVisibleBounds, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly) +void KRScene::render(KROctreeNode *pOctreeNode, std::map &visibleBounds, KRCamera *pCamera, std::vector lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector &remainingOctrees, std::vector &remainingOctreesTestResults, std::vector &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly) { if(pOctreeNode) { @@ -124,8 +138,9 @@ void KRScene::render(KROctreeNode *pOctreeNode, const std::set &visibleB GLuint params = 0; GLDEBUG(glGetQueryObjectuivEXT(pOctreeNode->m_occlusionQuery, GL_QUERY_RESULT_EXT, ¶ms)); if(params) { - newVisibleBounds.insert(octreeBounds); // Record the actual tests that succeeded during this frame -// visibleBounds.insert(octreeBounds); // Update the list of tests that we won't repeat for subsequent passes during this frame + // Record the frame number that the test has passed on + visibleBounds[octreeBounds] = getContext().getCurrentFrame(); + if(!bOcclusionTestResultsOnly) { // Schedule a pass to perform the rendering remainingOctrees.push_back(pOctreeNode); @@ -140,8 +155,8 @@ void KRScene::render(KROctreeNode *pOctreeNode, const std::set &visibleB float min_coverage = 0.0f; - float lod_coverage = pOctreeNode->getBounds().coverage(viewport.getViewProjectionMatrix(), viewport.getSize()); // This also checks the view frustrum culling - if(lod_coverage > min_coverage) { + float lod_coverage = pOctreeNode->getBounds().coverage(viewport.getViewProjectionMatrix(), viewport.getSize()); // Cull against the view frustrum + if(lod_coverage > min_coverage) { // ----====---- Rendering and occlusion test pass ----====---- bool bVisible = false; @@ -153,25 +168,24 @@ void KRScene::render(KROctreeNode *pOctreeNode, const std::set &visibleB KRAABB cameraExtents = KRAABB(viewport.getCameraPosition() - KRVector3(pCamera->getPerspectiveNearZ()), viewport.getCameraPosition() + KRVector3(pCamera->getPerspectiveNearZ())); bVisible = octreeBounds.intersects(cameraExtents); if(bVisible) { - newVisibleBounds.insert(octreeBounds); // Record the actual tests that succeeded during this frame -// visibleBounds.insert(octreeBounds); // Update the list of tests that we won't repeat for subsequent passes during this frame + // Record the frame number in which the camera was within the bounds + visibleBounds[octreeBounds] = getContext().getCurrentFrame(); bNeedOcclusionTest = false; } } - if(!bVisible) { - // Check if an occlusion query from the prior pass has returned true - bVisible = newVisibleBounds.find(octreeBounds) != newVisibleBounds.end(); - if(bVisible) { - bNeedOcclusionTest = false; - } - } if(!bVisible) { - // Take advantage of temporal consistency of visible elements from frame to frame + // Check if a previous occlusion query has returned true, taking advantage of temporal consistency of visible elements from frame to frame // If the previous frame rendered this octree, then attempt to render it in this frame without performing a pre-occlusion test - bVisible = visibleBounds.find(octreeBounds) != visibleBounds.end(); - // We don't set bNeedOcclusionTest to false here, as we need to perform an occlusion test to record if this octree node was visible for the next frame + std::map::iterator match_itr = visibleBounds.find(octreeBounds); + if(match_itr != visibleBounds.end()) { + bVisible = true; + + // We set bNeedOcclusionTest to false only when the previous occlusion test is old and we need to perform an occlusion test to record if this octree node was visible for the next frame + bNeedOcclusionTest = false; + } + } if(!bVisible) { @@ -270,7 +284,7 @@ void KRScene::render(KROctreeNode *pOctreeNode, const std::set &visibleB const int *childOctreeOrder = renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT || renderPass == KRNode::RENDER_PASS_ADDITIVE_PARTICLES || renderPass == KRNode::RENDER_PASS_VOLUMETRIC_EFFECTS_ADDITIVE ? viewport.getBackToFrontOrder() : viewport.getFrontToBackOrder(); for(int i=0; i<8; i++) { - render(pOctreeNode->getChildren()[childOctreeOrder[i]], visibleBounds, pCamera, lights, viewport, renderPass, remainingOctrees, remainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, false, false); + render(pOctreeNode->getChildren()[childOctreeOrder[i]], visibleBounds, pCamera, lights, viewport, renderPass, remainingOctrees, remainingOctreesTestResults, remainingOctreesTestResultsOnly, false, false); } // Remove lights added at this octree level from the stack diff --git a/KREngine/KREngine/Classes/KRScene.h b/KREngine/KREngine/Classes/KRScene.h index 196a320..29b1d1a 100644 --- a/KREngine/KREngine/Classes/KRScene.h +++ b/KREngine/KREngine/Classes/KRScene.h @@ -62,9 +62,9 @@ public: #if TARGET_OS_IPHONE - void render(KRCamera *pCamera, const std::set &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, std::set &newVisibleBounds); + void render(KRCamera *pCamera, std::map &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass); - void render(KROctreeNode *pOctreeNode, const std::set &visibleBounds, KRCamera *pCamera, std::vector lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector &remainingOctrees, std::vector &remainingOctreesTestResults, std::vector &remainingOctreesTestResultsOnly, std::set &newVisibleBounds, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly); + void render(KROctreeNode *pOctreeNode, std::map &visibleBounds, KRCamera *pCamera, std::vector lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector &remainingOctrees, std::vector &remainingOctreesTestResults, std::vector &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly); #endif diff --git a/KREngine/KREngine/Classes/KRViewport.cpp b/KREngine/KREngine/Classes/KRViewport.cpp index 002d9a3..7f013fb 100644 --- a/KREngine/KREngine/Classes/KRViewport.cpp +++ b/KREngine/KREngine/Classes/KRViewport.cpp @@ -154,14 +154,7 @@ void KRViewport::calculateDerivedValues() } -const std::set &KRViewport::getVisibleBounds() +std::map &KRViewport::getVisibleBounds() { return m_visibleBounds; } - -void KRViewport::setVisibleBounds(const std::set visibleBounds) -{ - m_visibleBounds = visibleBounds; -} - - diff --git a/KREngine/KREngine/Classes/KRViewport.h b/KREngine/KREngine/Classes/KRViewport.h index 6523931..438e4e9 100644 --- a/KREngine/KREngine/Classes/KRViewport.h +++ b/KREngine/KREngine/Classes/KRViewport.h @@ -12,6 +12,7 @@ #include "KRVector2.h" #include "KRMat4.h" #include "KRAABB.h" +#include class KRLight; @@ -38,8 +39,7 @@ public: // Overload assignment operator KRViewport& operator=(const KRViewport &v); - const std::set &getVisibleBounds(); - void setVisibleBounds(const std::set visibleBounds); + std::map &getVisibleBounds(); const std::set &getVisibleLights(); void setVisibleLights(const std::set visibleLights); @@ -62,7 +62,7 @@ private: void calculateDerivedValues(); - std::set m_visibleBounds; // AABB's that output fragments in the last frame + std::map m_visibleBounds; // AABB's that output fragments in the last frame }; #endif