Fixed inaccurate view frustum culling

Implemented smarter octree visibility query batching algorithm

--HG--
extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40106
This commit is contained in:
kearwood
2012-09-21 07:31:18 +00:00
parent d23fe9a700
commit d4903c1d84
16 changed files with 226 additions and 218 deletions

View File

@@ -8,6 +8,7 @@
#include "KRAABB.h" #include "KRAABB.h"
#include "KRMat4.h" #include "KRMat4.h"
#include "assert.h"
KRAABB::KRAABB(const KRVector3 &minPoint, const KRVector3 &maxPoint) KRAABB::KRAABB(const KRVector3 &minPoint, const KRVector3 &maxPoint)
{ {
@@ -87,6 +88,11 @@ bool KRAABB::contains(const KRAABB &b) const
return b.min.x >= min.x && b.min.y >= min.y && b.min.z >= min.z && b.max.x <= max.x && b.max.y <= max.y && b.max.z <= max.z; return b.min.x >= min.x && b.min.y >= min.y && b.min.z >= min.z && b.max.x <= max.x && b.max.y <= max.y && b.max.z <= max.z;
} }
bool KRAABB::contains(const KRVector3 &v) const
{
return v.x >= min.x && v.x <= max.x && v.y >= min.y && v.y <= max.y && v.z >= min.z && v.z <= max.z;
}
KRAABB KRAABB::Infinite() KRAABB KRAABB::Infinite()
{ {
return KRAABB(KRVector3::Min(), KRVector3::Max()); return KRAABB(KRVector3::Min(), KRVector3::Max());
@@ -102,13 +108,13 @@ bool KRAABB::visible(const KRMat4 &matViewProjection) const
int outside_count[6] = {0, 0, 0, 0, 0, 0}; int outside_count[6] = {0, 0, 0, 0, 0, 0};
for(int iCorner=0; iCorner<8; iCorner++) { for(int iCorner=0; iCorner<8; iCorner++) {
KRVector3 cornerVertex = KRVector3( KRVector3 sourceCornerVertex = KRVector3(
(iCorner & 1) == 0 ? min.x : max.x, (iCorner & 1) == 0 ? min.x : max.x,
(iCorner & 2) == 0 ? min.y : max.y, (iCorner & 2) == 0 ? min.y : max.y,
(iCorner & 4) == 0 ? min.z : max.z); (iCorner & 4) == 0 ? min.z : max.z);
cornerVertex = KRMat4::Dot(matViewProjection, cornerVertex); KRVector3 cornerVertex = KRMat4::Dot(matViewProjection, sourceCornerVertex);
float cornerVertexW = KRMat4::DotW(matViewProjection, cornerVertex); float cornerVertexW = KRMat4::DotW(matViewProjection, sourceCornerVertex);
if(cornerVertex.x < -cornerVertexW) { if(cornerVertex.x < -cornerVertexW) {
outside_count[0]++; outside_count[0]++;
@@ -130,6 +136,37 @@ bool KRAABB::visible(const KRMat4 &matViewProjection) const
} }
} }
// for(int iCorner=0; iCorner<8; iCorner++) {
// KRVector3 sourceCornerVertex = KRVector3(
// (iCorner & 1) == 0 ? min.x : max.x,
// (iCorner & 2) == 0 ? min.y : max.y,
// (iCorner & 4) == 0 ? min.z : max.z);
//
// KRVector3 cornerVertex = KRMat4::Dot(matViewProjection, sourceCornerVertex);
// float cornerVertexW = KRMat4::DotW(matViewProjection, sourceCornerVertex);
// cornerVertex /= cornerVertexW;
//
//
// if(cornerVertex.x < -1.0) {
// outside_count[0]++;
// }
// if(cornerVertex.y < -1.0) {
// outside_count[1]++;
// }
// if(cornerVertex.z < -1.0) {
// outside_count[2]++;
// }
// if(cornerVertex.x > 1.0) {
// outside_count[3]++;
// }
// if(cornerVertex.y > 1.0) {
// outside_count[4]++;
// }
// if(cornerVertex.z > 1.0) {
// outside_count[5]++;
// }
// }
bool is_visible = true; bool is_visible = true;
for(int iFace=0; iFace < 6; iFace++) { for(int iFace=0; iFace < 6; iFace++) {
if(outside_count[iFace] == 8) { if(outside_count[iFace] == 8) {
@@ -138,9 +175,10 @@ bool KRAABB::visible(const KRMat4 &matViewProjection) const
} }
if(!is_visible) { if(!is_visible) {
fprintf(stderr, "AABB culled: %i%i%i%i%i%i out, (%f, %f, %f) - (%f, %f, %f)\n", outside_count[0], outside_count[1], outside_count[2], outside_count[3], outside_count[4], outside_count[5], min.x, min.y, min.z, max.x, max.y, max.z); //fprintf(stderr, "AABB culled: %i%i%i%i%i%i out, (%f, %f, %f) - (%f, %f, %f)\n", outside_count[0], outside_count[1], outside_count[2], outside_count[3], outside_count[4], outside_count[5], min.x, min.y, min.z, max.x, max.y, max.z);
} else { } else {
fprintf(stderr, "AABB visible: %i%i%i%i%i%i out, (%f, %f, %f) - (%f, %f, %f)\n", outside_count[0], outside_count[1], outside_count[2], outside_count[3], outside_count[4], outside_count[5], min.x, min.y, min.z, max.x, max.y, max.z); //fprintf(stderr, "AABB visible: %i%i%i%i%i%i out, (%f, %f, %f) - (%f, %f, %f)\n", outside_count[0], outside_count[1], outside_count[2], outside_count[3], outside_count[4], outside_count[5], min.x, min.y, min.z, max.x, max.y, max.z);
} }
//is_visible = true;
return is_visible; return is_visible;
} }

View File

@@ -24,6 +24,7 @@ public:
KRVector3 size() const; KRVector3 size() const;
bool intersects(const KRAABB& b) const; bool intersects(const KRAABB& b) const;
bool contains(const KRAABB &b) const; bool contains(const KRAABB &b) const;
bool contains(const KRVector3 &v) const;
bool visible(const KRMat4 &matViewProjection) const; bool visible(const KRMat4 &matViewProjection) const;
KRAABB& operator =(const KRAABB& b); KRAABB& operator =(const KRAABB& b);

View File

@@ -192,6 +192,9 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
setViewportSize(KRVector2(backingWidth, backingHeight)); setViewportSize(KRVector2(backingWidth, backingHeight));
KRBoundingVolume frustrumVolume = KRBoundingVolume(viewMatrix, perspective_fov, getViewportSize().x / getViewportSize().y, perspective_nearz, perspective_farz); KRBoundingVolume frustrumVolume = KRBoundingVolume(viewMatrix, perspective_fov, getViewportSize().x / getViewportSize().y, perspective_nearz, perspective_farz);
std::set<KRAABB> newVisibleBounds;
if(bEnableDeferredLighting) { if(bEnableDeferredLighting) {
// ----====---- Opaque Geometry, Deferred rendering Pass 1 ----====---- // ----====---- Opaque Geometry, Deferred rendering Pass 1 ----====----
@@ -216,7 +219,7 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
GLDEBUG(glDisable(GL_BLEND)); GLDEBUG(glDisable(GL_BLEND));
// Render the geometry // Render the geometry
scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_DEFERRED_GBUFFER); scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_DEFERRED_GBUFFER, newVisibleBounds);
// ----====---- Opaque Geometry, Deferred rendering Pass 2 ----====---- // ----====---- Opaque Geometry, Deferred rendering Pass 2 ----====----
// Set render target // Set render target
@@ -242,9 +245,7 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
// Render the geometry // Render the geometry
scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, 0, KRNode::RENDER_PASS_DEFERRED_LIGHTS); scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, 0, KRNode::RENDER_PASS_DEFERRED_LIGHTS, newVisibleBounds);
scene.getOcclusionQueryResults(m_visibleBounds);
// ----====---- Opaque Geometry, Deferred rendering Pass 3 ----====---- // ----====---- Opaque Geometry, Deferred rendering Pass 3 ----====----
// Set render target // Set render target
@@ -275,7 +276,8 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
GLDEBUG(glDepthMask(GL_TRUE)); GLDEBUG(glDepthMask(GL_TRUE));
// Render the geometry // Render the geometry
scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_DEFERRED_OPAQUE); 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_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_DEFERRED_OPAQUE, newVisibleBounds);
// Deactivate source buffer texture units // Deactivate source buffer texture units
m_pContext->getTextureManager()->selectTexture(6, NULL); m_pContext->getTextureManager()->selectTexture(6, NULL);
@@ -312,9 +314,7 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
// Render the geometry // Render the geometry
scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FORWARD_OPAQUE); scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FORWARD_OPAQUE, newVisibleBounds);
scene.getOcclusionQueryResults(m_visibleBounds);
} }
// ----====---- Transparent Geometry, Forward Rendering ----====---- // ----====---- Transparent Geometry, Forward Rendering ----====----
@@ -339,7 +339,7 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
GLDEBUG(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); GLDEBUG(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
// Render all transparent geometry // Render all transparent geometry
scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FORWARD_TRANSPARENT); scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FORWARD_TRANSPARENT, newVisibleBounds);
// ----====---- Flares ----====---- // ----====---- Flares ----====----
@@ -363,7 +363,7 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE)); GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
// Render all flares // Render all flares
scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FLARES); scene.render(this, m_visibleBounds, m_pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FLARES, newVisibleBounds);
// ----====---- Debug Overlay ----====---- // ----====---- Debug Overlay ----====----
@@ -395,15 +395,13 @@ void KRCamera::renderFrame(KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightD
} }
} }
// scene.getOcclusionQueryResults(m_visibleBounds); m_visibleBounds = newVisibleBounds;
// fprintf(stderr, "visible bounds: %i\n", (int)m_visibleBounds.size());
// Re-enable z-buffer write // Re-enable z-buffer write
GLDEBUG(glDepthMask(GL_TRUE)); GLDEBUG(glDepthMask(GL_TRUE));
fprintf(stderr, "VBO Mem: %i Kbyte Texture Mem: %i Kbyte Shader Handles: %i\n", (int)m_pContext->getModelManager()->getMemUsed() / 1024, (int)m_pContext->getTextureManager()->getMemUsed() / 1024, (int)m_pContext->getShaderManager()->getShaderHandlesUsed()); fprintf(stderr, "VBO Mem: %i Kbyte Texture Mem: %i Kbyte Shader Handles: %i Visible Bounds: %i\n", (int)m_pContext->getModelManager()->getMemUsed() / 1024, (int)m_pContext->getTextureManager()->getMemUsed() / 1024, (int)m_pContext->getShaderManager()->getShaderHandlesUsed(), (int)m_visibleBounds.size());
} }
@@ -574,8 +572,10 @@ void KRCamera::renderShadowBuffer(KRScene &scene, int iShadow)
KRVector3 cameraPosition; KRVector3 cameraPosition;
KRVector3 lightDirection; KRVector3 lightDirection;
KRBoundingVolume shadowVolume = KRBoundingVolume(vertices); KRBoundingVolume shadowVolume = KRBoundingVolume(vertices);
scene.render(this, m_shadowVisibleBounds[iShadow], m_pContext, shadowVolume, shadowmvpmatrix[iShadow], cameraPosition, lightDirection, shadowmvpmatrix, NULL, m_cShadowBuffers, KRNode::RENDER_PASS_SHADOWMAP);
scene.getOcclusionQueryResults(m_shadowVisibleBounds[iShadow]); std::set<KRAABB> newVisibleBounds;
scene.render(this, m_shadowVisibleBounds[iShadow], m_pContext, shadowVolume, shadowmvpmatrix[iShadow], cameraPosition, lightDirection, shadowmvpmatrix, NULL, m_cShadowBuffers, KRNode::RENDER_PASS_SHADOWMAP, newVisibleBounds);
m_shadowVisibleBounds[iShadow] = newVisibleBounds;
GLDEBUG(glViewport(0, 0, backingWidth, backingHeight)); GLDEBUG(glViewport(0, 0, backingWidth, backingHeight));
} }

View File

@@ -91,8 +91,8 @@ void KRInstance::render(KRCamera *pCamera, KRContext *pContext, KRBoundingVolume
} }
if(m_pModel != NULL) { if(m_pModel != NULL) {
if(getExtents(pContext).test_intersect(frustrumVolume) || renderPass == RENDER_PASS_SHADOWMAP) { //if(getExtents(pContext).test_intersect(frustrumVolume) || renderPass == RENDER_PASS_SHADOWMAP) {
//if(m_pModel != NULL && (getBounds().visible(viewMatrix * projectionMatrix) || renderPass == RENDER_PASS_SHADOWMAP)) { if(getBounds().visible(viewMatrix * projectionMatrix)) {
if(m_pLightMap == NULL && m_lightMap.size()) { if(m_pLightMap == NULL && m_lightMap.size()) {
m_pLightMap = pContext->getTextureManager()->getTexture(m_lightMap.c_str()); m_pLightMap = pContext->getTextureManager()->getTexture(m_lightMap.c_str());

View File

@@ -91,12 +91,3 @@ std::set<KRNode *> &KROctree::getOuterSceneNodes()
{ {
return m_outerSceneNodes; return m_outerSceneNodes;
} }
#if TARGET_OS_IPHONE
void KROctree::getOcclusionQueryResults(std::set<KRAABB> &renderedBounds)
{
renderedBounds.clear();
if(m_pRootNode) {
m_pRootNode->getOcclusionQueryResults(renderedBounds);
}
}
#endif

View File

@@ -26,9 +26,7 @@ public:
KROctreeNode *getRootNode(); KROctreeNode *getRootNode();
std::set<KRNode *> &getOuterSceneNodes(); std::set<KRNode *> &getOuterSceneNodes();
#if TARGET_OS_IPHONE
void getOcclusionQueryResults(std::set<KRAABB> &renderedBounds);
#endif
private: private:
KROctreeNode *m_pRootNode; KROctreeNode *m_pRootNode;
std::set<KRNode *>m_outerSceneNodes; std::set<KRNode *>m_outerSceneNodes;

View File

@@ -15,8 +15,6 @@ KROctreeNode::KROctreeNode(const KRAABB &bounds) : m_bounds(bounds)
m_occlusionQuery = 0; m_occlusionQuery = 0;
m_occlusionTested = false; m_occlusionTested = false;
m_occlusionQueryTransparent = 0;
m_occlusionTestedTransparent = false;
m_activeQuery = false; m_activeQuery = false;
} }
@@ -28,8 +26,6 @@ KROctreeNode::KROctreeNode(const KRAABB &bounds, int iChild, KROctreeNode *pChil
m_occlusionQuery = 0; m_occlusionQuery = 0;
m_occlusionTested = false; m_occlusionTested = false;
m_occlusionQueryTransparent = 0;
m_occlusionTestedTransparent = false;
m_activeQuery = false; m_activeQuery = false;
} }
@@ -44,21 +40,13 @@ KROctreeNode::~KROctreeNode()
if(m_occlusionTested) { if(m_occlusionTested) {
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery)); GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
} }
if(m_occlusionTestedTransparent) {
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQueryTransparent));
}
#endif #endif
} }
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
void KROctreeNode::beginOcclusionQuery(bool bTransparentPass) void KROctreeNode::beginOcclusionQuery()
{ {
if(bTransparentPass && !m_occlusionTestedTransparent) { if(!m_occlusionTested){
GLDEBUG(glGenQueriesEXT(1, &m_occlusionQueryTransparent));
GLDEBUG(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, m_occlusionQueryTransparent));
m_occlusionTestedTransparent = true;
m_activeQuery = true;
} else if(!bTransparentPass && !m_occlusionTested){
GLDEBUG(glGenQueriesEXT(1, &m_occlusionQuery)); GLDEBUG(glGenQueriesEXT(1, &m_occlusionQuery));
GLDEBUG(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, m_occlusionQuery)); GLDEBUG(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, m_occlusionQuery));
m_occlusionTested = true; m_occlusionTested = true;
@@ -74,54 +62,9 @@ void KROctreeNode::endOcclusionQuery()
} }
} }
bool KROctreeNode::getOcclusionQueryResults(std::set<KRAABB> &renderedBounds)
{
bool bRendered = false;
bool bGoDeeper = false;
if(m_occlusionTested) {
GLuint params = 0;
GLDEBUG(glGetQueryObjectuivEXT(m_occlusionQuery, GL_QUERY_RESULT_EXT, &params));
if(params) bRendered = true; // At least one opaque fragment processed
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQuery));
m_occlusionTested = false;
bGoDeeper = true;
}
if(m_occlusionTestedTransparent) {
GLuint params = 0;
GLDEBUG(glGetQueryObjectuivEXT(m_occlusionQueryTransparent, GL_QUERY_RESULT_EXT, &params));
if(params) bRendered = true; // At least one transparent fragment processed
GLDEBUG(glDeleteQueriesEXT(1, &m_occlusionQueryTransparent));
m_occlusionTestedTransparent = false;
bGoDeeper = true;
}
// FINDME - Test Code:
//bGoDeeper = true;
//bRendered = true;
if(bGoDeeper) { // Only recurse deeper if we reached this level in the previous pass
for(int i=0; i<8; i++) {
if(m_children[i]) {
if(m_children[i]->getOcclusionQueryResults(renderedBounds)) {
bRendered = true; // We must always include the parent, even if the parent's local scene graph nodes are fully occluded
}
}
}
}
if(bRendered) {
renderedBounds.insert(m_bounds);
}
return bRendered;
}
#endif #endif
KRAABB KROctreeNode::getBounds() KRAABB KROctreeNode::getBounds()
{ {
return m_bounds; return m_bounds;
@@ -157,55 +100,7 @@ KRAABB KROctreeNode::getChildBounds(int iChild)
} }
int KROctreeNode::getChildIndex(KRNode *pNode) int KROctreeNode::getChildIndex(KRNode *pNode)
{ {
/*
KRVector3 min = pNode->getMinPoint();
KRVector3 max = pNode->getMaxPoint();
// 0: max.x < center.x && max.y < center.y && max.z < center.z
// 1: min.x > center.x && max.y < center.y && max.z < center.z
// 2: max.x < center.x && min.y > center.y && max.z < center.z
// 3: min.x > center.x && min.y > center.y && max.z < center.z
// 4: max.x < center.x && max.y < center.y && min.z > center.z
// 5: min.x > center.x && max.y < center.y && min.z > center.z
// 6: max.x < center.x && min.y > center.y && min.z > center.z
// 7: min.x > center.x && min.y > center.y && min.z > center.z
KRVector3 center = m_bounds.center();
int iChild = -1;
if(max.z < center.z) {
if(max.y < center.y) {
if(max.x < center.x) {
iChild = 0;
} else if(min.x > center.x) {
iChild = 1;
}
} else if(min.y > center.y) {
if(max.x < center.x) {
iChild = 2;
} else if(min.x > center.x) {
iChild = 3;
}
}
} else if(min.z > center.z) {
if(max.y < center.y) {
if(min.x > center.x) {
iChild = 4;
} else if(min.x > center.x) {
iChild = 5;
}
} else if(min.y > center.y) {
if(max.x < center.x) {
iChild = 6;
} else if(min.x > center.x) {
iChild = 7;
}
}
}
return iChild;
*/
for(int iChild=0; iChild < 8; iChild++) { for(int iChild=0; iChild < 8; iChild++) {
if(getChildBounds(iChild).contains(pNode->getBounds())) { if(getChildBounds(iChild).contains(pNode->getBounds())) {
return iChild; return iChild;

View File

@@ -38,19 +38,14 @@ public:
bool canShrinkRoot() const; bool canShrinkRoot() const;
KROctreeNode *stripChild(); KROctreeNode *stripChild();
void beginOcclusionQuery(bool bTransparentPass); void beginOcclusionQuery();
void endOcclusionQuery(); void endOcclusionQuery();
bool getOcclusionQueryResults(std::set<KRAABB> &renderedBounds);
private:
GLuint m_occlusionQuery; GLuint m_occlusionQuery;
bool m_occlusionTested; bool m_occlusionTested;
GLuint m_occlusionQueryTransparent;
bool m_occlusionTestedTransparent;
bool m_activeQuery; bool m_activeQuery;
private:
KRAABB m_bounds; KRAABB m_bounds;

View File

@@ -56,7 +56,7 @@ KRScene::~KRScene() {
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
void KRScene::render(KRCamera *pCamera, std::set<KRAABB> &visibleBounds, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass) { void KRScene::render(KRCamera *pCamera, std::set<KRAABB> &visibleBounds, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass, std::set<KRAABB> &newVisibleBounds) {
updateOctree(); updateOctree();
@@ -103,7 +103,33 @@ void KRScene::render(KRCamera *pCamera, std::set<KRAABB> &visibleBounds, KRConte
pCamera->dSunB = sun_color.z; pCamera->dSunB = sun_color.z;
} }
render(m_nodeTree.getRootNode(), visibleBounds, pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, forward_render_light_direction, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass); std::vector<KROctreeNode *> remainingOctrees;
std::vector<KROctreeNode *> remainingOctreesTestResults;
std::vector<KROctreeNode *> remainingOctreesTestResultsOnly;
if(m_nodeTree.getRootNode() != NULL) {
remainingOctrees.push_back(m_nodeTree.getRootNode());
}
std::vector<KROctreeNode *> newRemainingOctrees;
std::vector<KROctreeNode *> newRemainingOctreesTestResults;
while((!remainingOctrees.empty() || !remainingOctreesTestResults.empty())) {
newRemainingOctrees.clear();
newRemainingOctreesTestResults.clear();
for(std::vector<KROctreeNode *>::iterator octree_itr = remainingOctrees.begin(); octree_itr != remainingOctrees.end(); octree_itr++) {
render(*octree_itr, visibleBounds, pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, forward_render_light_direction, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, false, false);
}
for(std::vector<KROctreeNode *>::iterator octree_itr = remainingOctreesTestResults.begin(); octree_itr != remainingOctreesTestResults.end(); octree_itr++) {
render(*octree_itr, visibleBounds, pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, forward_render_light_direction, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, true, false);
}
remainingOctrees = newRemainingOctrees;
remainingOctreesTestResults = newRemainingOctreesTestResults;
}
newRemainingOctrees.clear();
newRemainingOctreesTestResults.clear();
for(std::vector<KROctreeNode *>::iterator octree_itr = remainingOctreesTestResultsOnly.begin(); octree_itr != remainingOctreesTestResultsOnly.end(); octree_itr++) {
render(*octree_itr, visibleBounds, pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, forward_render_light_direction, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass, newRemainingOctrees, newRemainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, true, true);
}
for(std::set<KRNode *>::iterator itr=m_nodeTree.getOuterSceneNodes().begin(); itr != m_nodeTree.getOuterSceneNodes().end(); itr++) { for(std::set<KRNode *>::iterator itr=m_nodeTree.getOuterSceneNodes().begin(); itr != m_nodeTree.getOuterSceneNodes().end(); itr++) {
@@ -111,61 +137,94 @@ void KRScene::render(KRCamera *pCamera, std::set<KRAABB> &visibleBounds, KRConte
} }
} }
void KRScene::render(KROctreeNode *pOctreeNode, std::set<KRAABB> &visibleBounds, KRCamera *pCamera, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass) void KRScene::render(KROctreeNode *pOctreeNode, std::set<KRAABB> &visibleBounds, KRCamera *pCamera, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, std::set<KRAABB> &newVisibleBounds, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly)
{ {
if(pOctreeNode) { if(pOctreeNode) {
KRMat4 projectionMatrix;
if(renderPass != KRNode::RENDER_PASS_SHADOWMAP) {
projectionMatrix = pCamera->getProjectionMatrix();
}
KRAABB octreeBounds = pOctreeNode->getBounds(); KRAABB octreeBounds = pOctreeNode->getBounds();
KRBoundingVolume frustrumVolumeNoNearClip = KRBoundingVolume(viewMatrix, pCamera->perspective_fov, pCamera->m_viewportSize.x / pCamera->m_viewportSize.y, 0.0, pCamera->perspective_farz); if(bOcclusionResultsPass) {
// ----====---- Occlusion results pass ----====----
//if(true) { if(pOctreeNode->m_occlusionTested) {
//if(pOctreeNode->getBounds().visible(viewMatrix * projectionMatrix)) { // Only recurse deeper if within the view frustrum GLuint params = 0;
if(frustrumVolumeNoNearClip.test_intersect(pOctreeNode->getBounds())) { // Only recurse deeper if within the view frustrum GLDEBUG(glGetQueryObjectuivEXT(pOctreeNode->m_occlusionQuery, GL_QUERY_RESULT_EXT, &params));
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
if(!bOcclusionTestResultsOnly) {
// Schedule a pass to perform the rendering
remainingOctrees.push_back(pOctreeNode);
}
}
GLDEBUG(glDeleteQueriesEXT(1, &pOctreeNode->m_occlusionQuery));
pOctreeNode->m_occlusionTested = false;
pOctreeNode->m_occlusionQuery = 0;
}
} else {
bool can_occlusion_test = renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_DEFERRED_GBUFFER/* || renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT*/;
// KRBoundingVolume frustrumVolumeNoNearClip = KRBoundingVolume(viewMatrix, pCamera->perspective_fov, pCamera->m_viewportSize.x / pCamera->m_viewportSize.y, 0.0, pCamera->perspective_farz);
// if(frustrumVolumeNoNearClip.test_intersect(pOctreeNode->getBounds())) { // Only recurse deeper if within the view frustrum
//
// can_occlusion_test = false;
bool bVisible = true;
//bool bVisible = visibleBounds.find(octreeBounds) != visibleBounds.end();
if(bVisible) {
if(can_occlusion_test) { KRMat4 projectionMatrix;
pOctreeNode->beginOcclusionQuery(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT); if(renderPass != KRNode::RENDER_PASS_SHADOWMAP) {
} projectionMatrix = pCamera->getProjectionMatrix();
}
// Occlusion test indicates that this bounding box was visible in the last frame if(pOctreeNode->getBounds().visible(viewMatrix * projectionMatrix)) { // Only recurse deeper if within the view frustrum
for(std::set<KRNode *>::iterator itr=pOctreeNode->getSceneNodes().begin(); itr != pOctreeNode->getSceneNodes().end(); itr++) {
//assert(pOctreeNode->getBounds().contains((*itr)->getBounds())); // Sanity check // ----====---- Rendering and occlusion test pass ----====----
bool bVisible = false;
(*itr)->render(pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass); bool bNeedOcclusionTest = true;
}
//bVisible = true; // FINDME - Test Code
if(can_occlusion_test) {
pOctreeNode->endOcclusionQuery(); if(!bVisible) {
} // Assume bounding boxes are visible without occlusion test queries if the camera is inside the box.
// The near clipping plane of the camera is taken into consideration by expanding the match area
KRMat4 invView = viewMatrix;
bool bRenderChildren = renderPass != KRNode::RENDER_PASS_DEFERRED_OPAQUE; invView.invert();
if(!bRenderChildren) { KRVector3 cameraPos = KRMat4::Dot(invView, KRVector3::Zero());
bRenderChildren = visibleBounds.find(octreeBounds) != visibleBounds.end(); KRAABB cameraExtents = KRAABB(cameraPos - KRVector3(pCamera->perspective_nearz), cameraPos + KRVector3(pCamera->perspective_nearz));
} bVisible = octreeBounds.intersects(cameraExtents);
if(bRenderChildren) { if(bVisible) {
for(int i=0; i<8; i++) { newVisibleBounds.insert(octreeBounds); // Record the actual tests that succeeded during this frame
render(pOctreeNode->getChildren()[i], visibleBounds, pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass); visibleBounds.insert(octreeBounds); // Update the list of tests that we won't repeat for subsequent passes during this frame
bNeedOcclusionTest = false;
} }
} }
} else if(KRNode::RENDER_PASS_FORWARD_OPAQUE || renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE) {
if(pOctreeNode->getSceneNodes().empty()) { if(!bVisible) {
for(int i=0; i<8; i++) { // Check if an occlusion query from the prior pass has returned true
render(pOctreeNode->getChildren()[i], visibleBounds, pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass); bVisible = newVisibleBounds.find(octreeBounds) != newVisibleBounds.end();
if(bVisible) {
bNeedOcclusionTest = false;
} }
} else { }
pOctreeNode->beginOcclusionQuery(renderPass == KRNode::RENDER_PASS_FORWARD_TRANSPARENT);
if(!bVisible) {
// Take 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
}
if(!bVisible) {
// Optimization: If this is an empty octree node with only a single child node, then immediately try to render the child node without an occlusion test for this higher level, as it would be more expensive than the occlusion test for the child
if(pOctreeNode->getSceneNodes().empty()) {
int child_count = 0;
for(int i=0; i<8; i++) {
if(pOctreeNode->getChildren()[i] != NULL) child_count++;
}
if(child_count == 1) bVisible = true;
}
}
if(bNeedOcclusionTest) {
pOctreeNode->beginOcclusionQuery();
KRShader *pVisShader = m_pContext->getShaderManager()->getShader("occlusion_test", pCamera, false, false, false, 0, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT); KRShader *pVisShader = m_pContext->getShaderManager()->getShader("occlusion_test", pCamera, false, false, false, 0, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT);
@@ -180,22 +239,60 @@ void KRScene::render(KROctreeNode *pOctreeNode, std::set<KRAABB> &visibleBounds,
// Enable additive blending // Enable additive blending
GLDEBUG(glEnable(GL_BLEND)); GLDEBUG(glEnable(GL_BLEND));
GLDEBUG(glBlendFunc(GL_ONE, GL_ONE)); GLDEBUG(glBlendFunc(GL_ONE, GL_ONE));
if(renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE ||
renderPass == KRNode::RENDER_PASS_DEFERRED_GBUFFER ||
renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE ||
renderPass == KRNode::RENDER_PASS_SHADOWMAP) {
// Disable z-buffer write
GLDEBUG(glDepthMask(GL_FALSE));
}
if(pVisShader->bind(pCamera, viewMatrix, mvpmatrix, cameraPosition, lightDirection, pShadowMatrices, shadowDepthTextures, 0, KRNode::RENDER_PASS_FORWARD_TRANSPARENT)) { if(pVisShader->bind(pCamera, viewMatrix, mvpmatrix, cameraPosition, lightDirection, pShadowMatrices, shadowDepthTextures, 0, KRNode::RENDER_PASS_FORWARD_TRANSPARENT)) {
GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 14)); GLDEBUG(glDrawArrays(GL_TRIANGLE_STRIP, 0, 14));
} }
if(renderPass == KRNode::RENDER_PASS_FORWARD_OPAQUE ||
renderPass == KRNode::RENDER_PASS_DEFERRED_GBUFFER ||
renderPass == KRNode::RENDER_PASS_DEFERRED_OPAQUE ||
renderPass == KRNode::RENDER_PASS_SHADOWMAP) {
// Re-enable z-buffer write
GLDEBUG(glDepthMask(GL_TRUE));
}
GLDEBUG(glDisable(GL_BLEND)); GLDEBUG(glDisable(GL_BLEND));
pOctreeNode->endOcclusionQuery(); pOctreeNode->endOcclusionQuery();
if(bVisible) {
// Schedule a pass to get the result of the occlusion test only for future frames and passes, without rendering the model or recurring further
remainingOctreesTestResultsOnly.push_back(pOctreeNode);
} else {
// Schedule a pass to get the result of the occlusion test and continue recursion and rendering if test is true
remainingOctreesTestResults.push_back(pOctreeNode);
}
}
if(bVisible) {
for(std::set<KRNode *>::iterator itr=pOctreeNode->getSceneNodes().begin(); itr != pOctreeNode->getSceneNodes().end(); itr++) {
//assert(pOctreeNode->getBounds().contains((*itr)->getBounds())); // Sanity check
(*itr)->render(pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass);
}
for(int i=0; i<8; i++) {
render(pOctreeNode->getChildren()[i], visibleBounds, pCamera, pContext, frustrumVolume, viewMatrix, cameraPosition, lightDirection, pShadowMatrices, shadowDepthTextures, cShadowBuffers, renderPass, remainingOctrees, remainingOctreesTestResults, remainingOctreesTestResultsOnly, newVisibleBounds, false, false);
}
} }
} }
} else {
//fprintf(stderr, "Octree culled: (%f, %f, %f) - (%f, %f, %f)\n", pOctreeNode->getBounds().min.x, pOctreeNode->getBounds().min.y, pOctreeNode->getBounds().min.z, pOctreeNode->getBounds().max.x, pOctreeNode->getBounds().max.y, pOctreeNode->getBounds().max.z);
} }
} }
// fprintf(stderr, "Octree culled: (%f, %f, %f) - (%f, %f, %f)\n", pOctreeNode->getBounds().min.x, pOctreeNode->getBounds().min.y, pOctreeNode->getBounds().min.z, pOctreeNode->getBounds().max.x, pOctreeNode->getBounds().max.y, pOctreeNode->getBounds().max.z);
} }
#endif #endif
@@ -317,9 +414,4 @@ void KRScene::updateOctree()
} }
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
void KRScene::getOcclusionQueryResults(std::set<KRAABB> &renderedBounds)
{
m_nodeTree.getOcclusionQueryResults(renderedBounds);
}
#endif #endif

View File

@@ -64,12 +64,9 @@ public:
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
void render(KRCamera *pCamera, std::set<KRAABB> &visibleBounds, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass); void render(KRCamera *pCamera, std::set<KRAABB> &visibleBounds, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass, std::set<KRAABB> &newVisibleBounds);
void render(KROctreeNode *pOctreeNode, std::set<KRAABB> &visibleBounds, KRCamera *pCamera, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass); void render(KROctreeNode *pOctreeNode, std::set<KRAABB> &visibleBounds, KRCamera *pCamera, KRContext *pContext, KRBoundingVolume &frustrumVolume, KRMat4 &viewMatrix, KRVector3 &cameraPosition, KRVector3 &lightDirection, KRMat4 *pShadowMatrices, GLuint *shadowDepthTextures, int cShadowBuffers, KRNode::RenderPass renderPass, std::vector<KROctreeNode *> &remainingOctrees, std::vector<KROctreeNode *> &remainingOctreesTestResults, std::vector<KROctreeNode *> &remainingOctreesTestResultsOnly, std::set<KRAABB> &newVisibleBounds, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly);
void getOcclusionQueryResults(std::set<KRAABB> &renderedBounds);
#endif #endif

View File

@@ -31,7 +31,7 @@
#define KRENGINE_MAX_TEXTURE_UNITS 8 #define KRENGINE_MAX_TEXTURE_UNITS 8
#define KRENGINE_MAX_TEXTURE_HANDLES 10000 #define KRENGINE_MAX_TEXTURE_HANDLES 10000
#define KRENGINE_MAX_TEXTURE_MEM 100000000 #define KRENGINE_MAX_TEXTURE_MEM 128000000
#ifndef KRTEXTUREMANAGER_H #ifndef KRTEXTUREMANAGER_H
#define KRTEXTUREMANAGER_H #define KRTEXTUREMANAGER_H

View File

@@ -30,5 +30,6 @@
// //
void main() { void main() {
//gl_FragColor = vec4(0.00, 0.00, 0.00, 0.00);
gl_FragColor = vec4(0.00, 0.00, 0.00, 0.00); gl_FragColor = vec4(0.00, 0.00, 0.00, 0.00);
} }

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0440" LastUpgradeVersion = "0450"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -23,7 +23,7 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug"> buildConfiguration = "Debug">

View File

@@ -106,7 +106,7 @@
} }
[self.engine setNearZ: 5.0]; [self.engine setNearZ: 5.0];
[self.engine setFarZ: 3000.0]; [self.engine setFarZ: 5000.0];
//[renderEngine setNearZ: 1.0]; //[renderEngine setNearZ: 1.0];
//[renderEngine setFarZ: 3000.0]; //[renderEngine setFarZ: 3000.0];

View File

@@ -252,7 +252,7 @@
} }
double dScaleFactor = 200.0f * deltaTime; double dScaleFactor = 500.0f * deltaTime;
camera_position.z += (-cos(camera_pitch) * cos(camera_yaw) * leftStickDeltaX + -cos(camera_pitch) * cos(camera_yaw - 90.0f * d2r) * -leftStickDeltaY) * dScaleFactor; camera_position.z += (-cos(camera_pitch) * cos(camera_yaw) * leftStickDeltaX + -cos(camera_pitch) * cos(camera_yaw - 90.0f * d2r) * -leftStickDeltaY) * dScaleFactor;
camera_position.x += (cos(camera_pitch) * sin(camera_yaw) * leftStickDeltaX + cos(camera_pitch) * sin(camera_yaw - 90.0f * d2r) * -leftStickDeltaY) * dScaleFactor; camera_position.x += (cos(camera_pitch) * sin(camera_yaw) * leftStickDeltaX + cos(camera_pitch) * sin(camera_yaw - 90.0f * d2r) * -leftStickDeltaY) * dScaleFactor;

View File

@@ -271,7 +271,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = { 29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 0440; LastUpgradeCheck = 0450;
}; };
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "KRObjView" */; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "KRObjView" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";