This is not optimal. I remember years ago frustrated having the same fps looking at a plain wall at Seyda Neen and then the same fps looking at the town and landscape beyond.
I read that we can use GPU’s occlusion queries (OpenGL) to determine if an object is visible. The GPU will calculate if objects are occluded by other geometry and return visibility results.
I also read about Hierarchical Z-Buffer (HZB): you can create a low-resolution depth buffer (pyramid-like structure) to test objects for occlusion quickly.
I asked chatgpt and gave me some code:
components/occlusion/OcclusionQuery.hpp
Code: Select all
#ifndef OCCLUSIONQUERY_HPP
#define OCCLUSIONQUERY_HPP
#include <GL/glew.h>
class OcclusionQuery {
public:
OcclusionQuery();
~OcclusionQuery();
void startQuery();
void endQuery();
bool isVisible();
private:
GLuint queryID;
GLuint result;
};
#endif // OCCLUSIONQUERY_HPP
Code: Select all
#include "OcclusionQuery.hpp"
OcclusionQuery::OcclusionQuery() {
glGenQueries(1, &queryID);
result = 0;
}
OcclusionQuery::~OcclusionQuery() {
glDeleteQueries(1, &queryID);
}
void OcclusionQuery::startQuery() {
glBeginQuery(GL_ANY_SAMPLES_PASSED, queryID);
}
void OcclusionQuery::endQuery() {
glEndQuery(GL_ANY_SAMPLES_PASSED);
}
bool OcclusionQuery::isVisible() {
glGetQueryObjectuiv(queryID, GL_QUERY_RESULT, &result);
return result > 0;
}
Code: Select all
#include "OcclusionQuery.hpp"
// Create an occlusion query object per visible node.
OcclusionQuery occlusionQuery;
void renderObject(osg::Node* node) {
// Step 1: Start Occlusion Query and Render Bounding Box
occlusionQuery.startQuery();
// Render a simple bounding box for occlusion testing
osg::BoundingBox bb = node->getBound();
renderBoundingBox(bb); // You need a helper function to render bounding volumes.
occlusionQuery.endQuery();
// Step 2: Check Visibility
if(!occlusionQuery.isVisible()) {
// Skip rendering if not visible
return;
}
// Step 3: Render the actual object
node->accept(*visitor); // Standard OSG rendering
}
Code: Select all
#include <osg/Geometry>
#include <osg/MatrixTransform>
void renderBoundingBox(const osg::BoundingBox& bb) {
glPushMatrix();
glBegin(GL_LINES);
glVertex3f(bb._min.x(), bb._min.y(), bb._min.z());
glVertex3f(bb._max.x(), bb._min.y(), bb._min.z());
glVertex3f(bb._max.x(), bb._min.y(), bb._min.z());
glVertex3f(bb._max.x(), bb._max.y(), bb._min.z());
glVertex3f(bb._max.x(), bb._max.y(), bb._min.z());
glVertex3f(bb._min.x(), bb._max.y(), bb._min.z());
glVertex3f(bb._min.x(), bb._max.y(), bb._min.z());
glVertex3f(bb._min.x(), bb._min.y(), bb._min.z());
glEnd();
glPopMatrix();
}