Why is the result of my occlusion query 0?

My scene has a 1×1×1 cube, it’s blown to be 50×50×4, it’s located in (-2, -2, -2). I render the bounding box at the end of one frame and query the occlusion results at the beginning of the next frame to determine if the cube should be rendered——using glGetQueryObjecti(id, GL_QUERY_RESULT). When the cube is in my field of view, the result is sometimes normal, sometimes zero. I don’t know why.
This is my window:
image

My camera is close to the cube, the window’s size is 640×480. The printed query result:
image

glGetQueryObjectui(id, GL.GL_QUERY_RESULT_AVAILABLE) was called before the query result was retrieved.

Without sync objects you cannot tell if the cube has already rendered at the time you are retrieving the result.

https://www.khronos.org/opengl/wiki/Sync_Object

Note: this causes the application to wait. if you wait to early that causes a a render stall and it comes with a huge performance hit.

I suggest getting the result of frame n after frame n+1 has been rendered

I guess that’s what I did—— I render the bounding box at the end of one frame(frame n) and query the occlusion results at the beginning of the next frame(frame n+1) to determine if the cube should be rendered, if result of using glGetQueryObjectui(id, GL.GL_QUERY_RESULT_AVAILABLE) is false, I won’t render the bounding box at the end of frame n+1.

in the gpu command buffer your method would be like:

createQuerry
renderBox
endFrame
getQuerryResult

Note that you are only giving the commands to the driver, when they are executed on the gpu is not known.

you basically want:

createQuerry
renderBox
createSynch
endFrame
waitForSync
getQuerryResult

that should work but you have an empty command buffer after the synch.

Better would be:

createQuerry 1
renderBox
createSync 1
endFrame
createQuerry 2
renderBox
createSync 2
waitForSync 1
getQuerryResult 1

Here’s what I did:

Rendering process{
  if(query.isReady()){
     if(query.getQuerryResult() > 0){
         renderBox(real);
     }else{
         beginQuery
         renderBox(simplified)
         endQuery
  }else{
     renderBox(real);
  }
  endFrame
}

I think query.isReady() is equal to waitForSync.

if query.isReady is implemented using GL.GL_QUERY_RESULT_AVAILABLE then no. according to the specs it is non waiting and returns immediately

yes, query.isReady is implemented using GL.GL_QUERY_RESULT_AVAILABLE.

I’m not sure what you mean. I used glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) at the end of the query, followed by glFlush. When query.isReady is true, glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0) is GL_ALREADY_SIGNALED. Shouldn’t I get query results at this point?

Hello,
I am wondering, you use the query to see if you should render the real or the simplified object and the problem is that your output shows a number of samples passed that is switching between 0 and exactly 4x your window size (probably multisampling) but do not observe any screen flickering? like i would expect the geometry to only render every other frame according to that output and your description

once your object was visible one time, it will always render the real object? (Looks like what you are observing)
But if you only use a query if the object is not visible, how can you get that output at all?

the general idea for the easiest approach would look quite similar to what you have

Rendering process{
  if(query.isReady()){
     int samples = query.getQueryResult()
     beginQuery
     renderBox(samples > 0 ? real : simplified)
     endQuery
  }else{
     int samples = query.getLastValidResult()
     renderBox(samples > 0 ? real : simplified)
  }
}

(assuming isReady() returns true for a query that has never been started and getQueryResult() internally stores the result in a field that can be retrieved with getLastValidResult())
where you reuse the same query as soon as the query result is available (you might end up reusing the same result across several frames), which comes with the downside of a higher latency but of course never has to wait for a result of a query

no need for anything “endFrame”. if you mean this:

you dont need fences (glFenceSync, glClientWaitSync, glWaitSync) when using queries that way (fences came in 3.2 and query objects exist since 1.5) and you should avoid calling glFlush.
if you start and end the query before you place the fence, then glClientWaitSync must not neccessarily return GL_ALREADY_SIGNALED when your query result is available, but the otherway round is true of course, once the fence is signaled you can be sure the result is available. you dont need fences here though.

yes, it is flickering, because render and unrender are running alternately.

I am sorry, I made a mistake here. In fact, it is:

Rendering process{
  if(query.isReady()){
     if(query.getQuerryResult() > 0){
         renderBox(real);
     }
     query.isComsumeResult = true;
  }else{
     int samples = query.getLastValidResult()
     if(samples > 0){
         renderBox(real);
     }
  }
  if(query.isComsumeResult){
     query.isComsumeResult = false;
     disable some opengl attributes(for example GL_LIGHTING, GL_NORMAL, etc)
     beginQuery
     renderBox(simplified)
     endQuery
     open some opengl attributes
  }
}

I just want to indicate that this is the end of a frame, that is not code.
My problem is still there: sometimes query.getQuerryResult() = 0 and sometimes query.getQuerryResult() = right value, so that object is flickering.

Since even in the second pseudo code you did not rename the method i have to ask: is your real object also a box and all you want to safe is using a more heavy-weight material, not actually the vertex count?
Because to me your new pseudo-code reads like: If the query is ready and samples passed the test, draw the box using the real material (without query), then at the end of the frame, render another box with a cheaper material using a query exactly on top of the box drawn at the beginning (definitely no samples will pass that, as long as you dont set depth compare to less than or equal to as opposed to only less than) which means the next time your query is available no more than 0 samples passed the test, meaning your renderBox(real) will not be called, resuting in the box rendered at the end being visible so the whole thing begins again and you get the output you have shown

EDIT: wait a minute “GL_LIGHTING”, “GL_NORMAL”… you are not, are you?

1 Like

The real object maybe a complex object, the simplified box is real object’s bounding box. I want to use occlusion query through drawing simplified box to determine if the real object is drawn. When drawing simplified box, I disable following attributes:

        GL11.glDisable(GL11.GL_LIGHTING);
        GL11.glDisable(GL11.GL_COLOR_MATERIAL);
        GL11.glDisable(GL11.GL_NORMALIZE);
        GL11.glDepthMask(false);
        GL11.glColorMask(false, false, false, false);

When simplified box has been drawn, I will reenable them.

So when I render simplified box, I need to use GL11.glDepthFunc(GL11.GL_LEQUAL) ?

Are you using jme for rendering or are we talking about your own fixed function rendering here?

tbh i dont know if query objects do work with the fixed function pipeline. i would think yes but the specs only say that lot of features wont work fit ffp

For real object(complex object), I use jme, because their data structure belong to JME. For simplified box(real object’s bounding box), I rendered them by LWJGL. I use glDrawElements essentially to render a box.

I think my fixed function of rendering is works. If it’s not, I shouldn’t get some right value sometimes.