Ok.
I try to understand this one: Hierarchical-Z map based occlusion culling – RasterGrid
Full source code here: http://rastergrid.com/blog/downloads/mountains-demo/
void MountainsDemo::renderScene(float dtime) {
this->drawCallCount = 0;
// update camera data to uniform buffer
this->transform.ModelViewMatrix = mat4(1.0f);
this->transform.ModelViewMatrix = rotate(this->transform.ModelViewMatrix, this->camera.rotation.x, vec3(1.0f, 0.0f, 0.0f));
this->transform.ModelViewMatrix = rotate(this->transform.ModelViewMatrix, this->camera.rotation.y, vec3(0.0f, 1.0f, 0.0f));
this->transform.ModelViewMatrix = rotate(this->transform.ModelViewMatrix, this->camera.rotation.z, vec3(0.0f, 0.0f, 1.0f));
this->transform.ModelViewMatrix = translate(this->transform.ModelViewMatrix, -this->camera.position);
this->transform.MVPMatrix = this->transform.ProjectionMatrix * this->transform.ModelViewMatrix;
glBindBuffer(GL_UNIFORM_BUFFER, this->transformUB);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(this->transform), &this->transform);
// bind offscreen framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, this->framebuffer);
glClear(GL_DEPTH_BUFFER_BIT);
// draw terrain
glUseProgram(this->terrainPO);
glBindVertexArray(this->terrainVA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->heightmap);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, this->terrainTex);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, this->detailTex);
bool visible[7][7] = { false };
this->visibleBlocks = 0;
// terrain elements will be drawn only in a 7x7 grid around the camera
float x = roundf(-this->camera.position.x / TERRAIN_OBJECT_SIZE);
float z = roundf(-this->camera.position.z / TERRAIN_OBJECT_SIZE);
for (int i=-3; i<=3; i++)
for (int j=-3; j<=3; j++)
// perform view frustum culling for the terrain elements
if ( cullTerrain( vec4( TERRAIN_OBJECT_SIZE*(i-x), 0.f, TERRAIN_OBJECT_SIZE*(j-z), 1.f ) ) ) {
glUniform2f(glGetUniformLocation(this->terrainPO, "Offset"), TERRAIN_OBJECT_SIZE*(i-x), TERRAIN_OBJECT_SIZE*(j-z));
glDrawElements(terrainDraw.prim_type, terrainDraw.indexCount, GL_UNSIGNED_INT, (void*)terrainDraw.indexOffset);
this->drawCallCount++;
// store visibility so we can use it during the tree instance rendering
visible[i+3][j+3] = true;
this->visibleBlocks++;
}
// create Hi-Z map if necessary
if ( this->cullMode == HI_Z_OCCLUSION_CULL ) {
glUseProgram(this->hizPO);
// disable color buffer as we will render only a depth image
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->depthTex);
// we have to disable depth testing but allow depth writes
glDepthFunc(GL_ALWAYS);
// calculate the number of mipmap levels for NPOT texture
int numLevels = 1 + (int)floorf(log2f(fmaxf(SCREEN_WIDTH, SCREEN_HEIGHT)));
int currentWidth = SCREEN_WIDTH;
int currentHeight = SCREEN_HEIGHT;
for (int i=1; i<numLevels; i++) {
glUniform2i(glGetUniformLocation(this->hizPO, "LastMipSize"), currentWidth, currentHeight);
// calculate next viewport size
currentWidth /= 2;
currentHeight /= 2;
// ensure that the viewport size is always at least 1x1
currentWidth = currentWidth > 0 ? currentWidth : 1;
currentHeight = currentHeight > 0 ? currentHeight : 1;
glViewport(0, 0, currentWidth, currentHeight);
// bind next level for rendering but first restrict fetches only to previous level
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i-1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, this->depthTex, i);
// dummy draw command as the full screen quad is generated completely by a geometry shader
glDrawArrays(GL_POINTS, 0, 1);
this->drawCallCount++;
}
// reset mipmap level range for the depth image
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numLevels-1);
// reset the framebuffer configuration
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->colorTex, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, this->depthTex, 0);
// reenable color buffer writes, reset viewport and reenable depth test
glDepthFunc(GL_LEQUAL);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
if ( !this->showDepthTex ) {
// render tree instances and apply culling
glUseProgram(this->cullPO);
glUniformSubroutinesuiv(GL_VERTEX_SHADER, 1, &this->subIndexVS[this->cullMode]);
glUniformSubroutinesuiv(GL_GEOMETRY_SHADER, 1, &this->subIndexGS[this->LODMode ? 1 : 0]);
glEnable(GL_RASTERIZER_DISCARD);
glBindVertexArray(this->cullVA);
for (int i=0; i<NUM_LOD; i++)
glBeginQueryIndexed(GL_PRIMITIVES_GENERATED, i, this->cullQuery[i]);
glBeginTransformFeedback(GL_POINTS);
for (int i=-3; i<=3; i++)
for (int j=-3; j<=3; j++)
if ( visible[i+3][j+3] ) {
glUniform2f(glGetUniformLocation(this->cullPO, "Offset"), TERRAIN_OBJECT_SIZE*(i-x), TERRAIN_OBJECT_SIZE*(j-z));
glDrawArrays(GL_POINTS, 0, this->instanceCount);
this->drawCallCount++;
}
glEndTransformFeedback();
for (int i=0; i<NUM_LOD; i++)
glEndQueryIndexed(GL_PRIMITIVES_GENERATED, i);
glDisable(GL_RASTERIZER_DISCARD);
glBindVertexArray(this->terrainVA);
// draw skybox
glUseProgram(this->skyboxPO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, this->skyboxTex);
// dummy draw command as the skybox itself is generated completely by a geometry shader
glDrawArrays(GL_POINTS, 0, 1);
this->drawCallCount++;
// draw trees
glUseProgram(this->treePO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, this->treeTex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, this->terrainTex);
// get the number of instances from the query object
for (int i=0; i<NUM_LOD; i++) {
if ( this->showLODColor ) {
switch ( i ) {
case 0: glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 1.0, 0.0, 0.0, 1.0); break;
case 1: glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 0.0, 1.0, 0.0, 1.0); break;
case 2: glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 0.0, 0.0, 1.0, 1.0); break;
}
}
glBindVertexArray(this->treeVA[i]);
glGetQueryObjectiv(this->cullQuery[i], GL_QUERY_RESULT, &this->visibleTrees[i]);
if ( this->visibleTrees[i] > 0 ) {
// draw the trees
glDrawElementsInstanced(treeDraw[i].prim_type, treeDraw[i].indexCount, GL_UNSIGNED_INT, (void*)(treeDraw[i].indexOffset*sizeof(uint)), this->visibleTrees[i]);
this->drawCallCount++;
}
}
if ( this->showLODColor ) {
glUniform4f(glGetUniformLocation(this->treePO, "ColorMask"), 1.0, 1.0, 1.0, 1.0);
}
}
// bind default framebuffer and render post processing
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(this->postPO);
// visualize depth buffer texture if needed
if ( this->showDepthTex ) {
glUseProgram(this->depthPO);
glUniform1f(glGetUniformLocation(this->depthPO, "LOD"), this->LOD);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->colorTex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, this->depthTex);
glDisable(GL_DEPTH_TEST);
// dummy draw command as the full screen quad is generated completely by a geometry shader
glDrawArrays(GL_POINTS, 0, 1);
this->drawCallCount++;
glEnable(GL_DEPTH_TEST);
GLenum glError;
if ((glError = glGetError()) != GL_NO_ERROR) {
cout << "Warning: OpenGL error code: " << glError << endl;
}
}
Where is the rendering of first depth map?
It must be ready before building of mipmap as I think.