Updated realtime occlusion culling algorithm to reduce the number of occlusion tests.
--HG-- extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40160
This commit is contained in:
@@ -179,8 +179,6 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
|
||||
|
||||
KRVector3 vecCameraDirection = m_viewport.getCameraDirection();
|
||||
|
||||
std::set<KRAABB> 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<KRAABB> 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<KRAABB>::iterator itr=m_viewport.getVisibleBounds().begin(); itr != m_viewport.getVisibleBounds().end(); itr++) {
|
||||
for(std::map<KRAABB, int>::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<KRLight *>(), 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));
|
||||
|
||||
|
||||
@@ -300,9 +300,7 @@ void KRLight::renderShadowBuffers(KRCamera *pCamera)
|
||||
getContext().getShaderManager()->selectShader(shadowShader, m_shadowViewports[iShadow], KRMat4(), std::vector<KRLight *>(), KRNode::RENDER_PASS_SHADOWMAP);
|
||||
|
||||
|
||||
std::set<KRAABB> 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<KRAABB> &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, std::set<KRAABB> &newVisibleBounds) {
|
||||
void KRScene::render(KRCamera *pCamera, std::map<KRAABB, int> &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass) {
|
||||
|
||||
std::vector<KRLight *> lights;
|
||||
|
||||
@@ -96,10 +98,10 @@ void KRScene::render(KRCamera *pCamera, const std::set<KRAABB> &visibleBounds, c
|
||||
newRemainingOctrees.clear();
|
||||
newRemainingOctreesTestResults.clear();
|
||||
for(std::vector<KROctreeNode *>::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<KROctreeNode *>::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<KRAABB> &visibleBounds, c
|
||||
newRemainingOctrees.clear();
|
||||
newRemainingOctreesTestResults.clear();
|
||||
for(std::vector<KROctreeNode *>::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<KRAABB> expired_visible_bounds;
|
||||
for(std::map<KRAABB, int>::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<KRAABB>::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<KRAABB> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, std::set<KRAABB> &newVisibleBounds, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly)
|
||||
void KRScene::render(KROctreeNode *pOctreeNode, std::map<KRAABB, int> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly)
|
||||
{
|
||||
if(pOctreeNode) {
|
||||
|
||||
@@ -124,8 +138,9 @@ void KRScene::render(KROctreeNode *pOctreeNode, const std::set<KRAABB> &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<KRAABB> &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<KRAABB> &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<KRAABB, int>::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<KRAABB> &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
|
||||
|
||||
@@ -62,9 +62,9 @@ public:
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
void render(KRCamera *pCamera, const std::set<KRAABB> &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, std::set<KRAABB> &newVisibleBounds);
|
||||
void render(KRCamera *pCamera, std::map<KRAABB, int> &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass);
|
||||
|
||||
void render(KROctreeNode *pOctreeNode, const std::set<KRAABB> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, std::set<KRAABB> &newVisibleBounds, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly);
|
||||
void render(KROctreeNode *pOctreeNode, std::map<KRAABB, int> &visibleBounds, KRCamera *pCamera, std::vector<KRLight *> lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -154,14 +154,7 @@ void KRViewport::calculateDerivedValues()
|
||||
}
|
||||
|
||||
|
||||
const std::set<KRAABB> &KRViewport::getVisibleBounds()
|
||||
std::map<KRAABB, int> &KRViewport::getVisibleBounds()
|
||||
{
|
||||
return m_visibleBounds;
|
||||
}
|
||||
|
||||
void KRViewport::setVisibleBounds(const std::set<KRAABB> visibleBounds)
|
||||
{
|
||||
m_visibleBounds = visibleBounds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "KRVector2.h"
|
||||
#include "KRMat4.h"
|
||||
#include "KRAABB.h"
|
||||
#include <map.h>
|
||||
|
||||
class KRLight;
|
||||
|
||||
@@ -38,8 +39,7 @@ public:
|
||||
// Overload assignment operator
|
||||
KRViewport& operator=(const KRViewport &v);
|
||||
|
||||
const std::set<KRAABB> &getVisibleBounds();
|
||||
void setVisibleBounds(const std::set<KRAABB> visibleBounds);
|
||||
std::map<KRAABB, int> &getVisibleBounds();
|
||||
|
||||
const std::set<KRLight *> &getVisibleLights();
|
||||
void setVisibleLights(const std::set<KRLight *> visibleLights);
|
||||
@@ -62,7 +62,7 @@ private:
|
||||
|
||||
void calculateDerivedValues();
|
||||
|
||||
std::set<KRAABB> m_visibleBounds; // AABB's that output fragments in the last frame
|
||||
std::map<KRAABB, int> m_visibleBounds; // AABB's that output fragments in the last frame
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user