Support for occlusion queries (13 posts)

  • Profile picture of phate666 phate66670p said 1 year, 3 months ago:

    I added support for occlusion queries to the renderer, can be used to implement hardware accelerated occlusion culling.

    Index: src/core/com/jme3/system/NullRenderer.java
    ===================================================================
    --- src/core/com/jme3/system/NullRenderer.java	(Revision 6689)
    +++ src/core/com/jme3/system/NullRenderer.java	(Arbeitskopie)
    @@ -47,6 +47,7 @@
     import com.jme3.texture.Image;
     import com.jme3.texture.Texture;
     import java.nio.ByteBuffer;
    +import java.nio.IntBuffer;
     import java.util.EnumSet;
    
     public class NullRenderer implements Renderer {
    @@ -140,4 +141,30 @@
         public void setAlphaToCoverage(boolean value) {
         }
    
    +    @Override
    +    public void generateQueries(IntBuffer queries){
    +    }
    +
    +    @Override
    +    public void beginOcclusionQuery(IntBuffer queries, int index){
    +    }
    +
    +    @Override
    +    public void endOcclusionQuery(){
    +    }
    +
    +    @Override
    +    public boolean queryResultAvaiable(IntBuffer query, int index){
    +	return false;
    +    }
    +
    +    @Override
    +    public int queryResult(IntBuffer query, int index){
    +	return 0;
    +    }
    +
    +    @Override
    +    public void destroyQueries(IntBuffer query){
    +    }
    +
     }
    Index: src/core/com/jme3/renderer/Renderer.java
    ===================================================================
    --- src/core/com/jme3/renderer/Renderer.java	(Revision 6689)
    +++ src/core/com/jme3/renderer/Renderer.java	(Arbeitskopie)
    @@ -44,6 +44,7 @@
     import com.jme3.texture.Image;
     import com.jme3.texture.Texture;
     import java.nio.ByteBuffer;
    +import java.nio.IntBuffer;
     import java.util.EnumSet;
    
     public interface Renderer {
    @@ -207,4 +208,15 @@
          */
         public void setAlphaToCoverage(boolean value);
    
    +    public void generateQueries(IntBuffer queries);
    +
    +    public void beginOcclusionQuery(IntBuffer queries,int index);
    +
    +    public void endOcclusionQuery();
    +
    +    public boolean queryResultAvaiable(IntBuffer queries,int index);
    +
    +    public int queryResult(IntBuffer queries,int index);
    +
    +    public void destroyQueries(IntBuffer queries);
     }
    Index: src/jogl/com/jme3/renderer/jogl/JoglRenderer.java
    ===================================================================
    --- src/jogl/com/jme3/renderer/jogl/JoglRenderer.java	(Revision 6689)
    +++ src/jogl/com/jme3/renderer/jogl/JoglRenderer.java	(Arbeitskopie)
    @@ -1111,4 +1111,39 @@
                 gl.glDisable(gl.GL_SAMPLE_ALPHA_TO_COVERAGE);
             }
         }
    +
    +    @Override
    +    public void generateQueries(IntBuffer queries){
    +	gl.glGenQueries(queries.capacity(), queries);
    +    }
    +
    +    @Override
    +    public void beginOcclusionQuery(IntBuffer queries, int index){
    +	gl.glBeginQuery(GL.GL_SAMPLES_PASSED, queries.get(index));
    +    }
    +
    +    @Override
    +    public void endOcclusionQuery(){
    +	gl.glEndQuery(GL.GL_SAMPLES_PASSED);
    +    }
    +
    +    @Override
    +    public boolean queryResultAvaiable(IntBuffer queries, int index){
    +	IntBuffer QueryState = BufferUtils.createIntBuffer(1);
    +	gl.glGetQueryObjectuiv(queries.get(index), GL.GL_QUERY_RESULT_AVAILABLE,
    +				QueryState);
    +	return QueryState.get(0) == GL.GL_TRUE;
    +    }
    +
    +    @Override
    +    public int queryResult(IntBuffer queries, int index){
    +	IntBuffer samples = BufferUtils.createIntBuffer(1);
    +	gl.glGetQueryObjectuiv(queries.get(index), GL.GL_QUERY_RESULT, samples);
    +	return samples.get(0);
    +    }
    +
    +    @Override
    +    public void destroyQueries(IntBuffer queries){
    +	gl.glDeleteQueries(queries.capacity(),queries);
    +    }
     }
    Index: src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java
    ===================================================================
    --- src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java	(Revision 6689)
    +++ src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java	(Arbeitskopie)
    @@ -2187,4 +2187,39 @@
                 glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
             }
         }
    +
    +    @Override
    +	public void beginOcclusionQuery(IntBuffer queries, int index){
    +	    glBeginQuery(GL_SAMPLES_PASSED, queries.get(index));
    +	}
    +
    +	@Override
    +	public void endOcclusionQuery(){
    +	    glEndQuery(GL_SAMPLES_PASSED);
    +	}
    +
    +	@Override
    +	public boolean queryResultAvaiable(IntBuffer queries, int index){
    +	    IntBuffer QueryState = BufferUtils.createIntBuffer(1);
    +	    glGetQueryObject(queries.get(index), GL_QUERY_RESULT_AVAILABLE,
    +				QueryState);
    +	    return QueryState.get(0) == GL_TRUE;
    +	}
    +
    +	@Override
    +	public int queryResult(IntBuffer queries, int index){
    +	    IntBuffer samples = BufferUtils.createIntBuffer(1);
    +	    glGetQueryObject(queries.get(index), GL_QUERY_RESULT, samples);
    +	    return samples.get(0);
    +	}
    +
    +	@Override
    +	public void destroyQueries(IntBuffer queries){
    +	    glDeleteQueries(queries);
    +	}
    +
    +	@Override
    +	public void generateQueries(IntBuffer queries){
    +	    glGenQueries(queries);
    +	}
     }
    Index: src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java
    ===================================================================
    --- src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java	(Revision 6689)
    +++ src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java	(Arbeitskopie)
    @@ -858,4 +858,29 @@
         public void deleteBuffer(VertexBuffer vb) {
         }
    
    +    @Override
    +    public void generateQueries(IntBuffer queries){
    +    }
    +
    +    @Override
    +    public void beginOcclusionQuery(IntBuffer queries, int index){
    +    }
    +
    +    @Override
    +    public void endOcclusionQuery(){
    +    }
    +
    +    @Override
    +    public boolean queryResultAvaiable(IntBuffer query, int index){
    +	return false;
    +    }
    +
    +    @Override
    +    public int queryResult(IntBuffer query, int index){
    +	return 0;
    +    }
    +
    +    @Override
    +    public void destroyQueries(IntBuffer query){
    +    }
     }
    
  • Profile picture of nehon nehon590p said 1 year, 3 months ago:

    wow cool
    does it work?
    and….how does it work?

  • Profile picture of phate666 phate66670p said 1 year, 3 months ago:

    pseudocode:

    generateQueries;
    beginOcclusionQuery;
    
    drawObject;
    
    endOcclusionQuery;
    
    wait until queryResultAvaiable==true
    
    pixelDrawed = queryResult;
    

    after that, you know how many pixels of the object are actually drawn, i.e. if it is zero the object is not visible.
    take a look at:
    Occlusion Culling Algorithms
    CHC
    CHC++

  • Profile picture of nehon nehon590p said 1 year, 3 months ago:

    yeah ok , what I meant was “How does it work in jME3″.
    This would need to be called at some point by the renderManager in the culling process.

    Anyway thanks for this contribution ;)

  • Profile picture of phate666 phate66670p said 1 year, 3 months ago:

    The best place would be RenderQueue.renderGeometryList().
    I am still working on it to make it really useful.

    My first idea was to render only the boundingboxes with glColorMask(false,false,false,false), so they are not visible. If the query shows that a boundingbox is not drawn, then dont draw the actual object, else draw it.

  • Profile picture of phate666 phate66670p said 1 year, 3 months ago:

    I finished a simple implementation of occlusion culling:
    occlusionculling.diff

    Just apply the diff and it should work. I tested with jme3test.stress.TestLodStress and it gives a nice speedup if many teapots are culled.

  • Profile picture of madlion madlion2p said 1 year, 3 months ago:

    Cool, very interesting! ^^

  • Profile picture of Momoko_Fan Momoko_Fan366p said 1 year, 3 months ago:

    This patch doesn’t exactly do it correctly
    It assumes objects close to the camera are rendered first, however this is not always the case.
    It works for the teapot test because all meshes have the same material and so they take advantage of front-to-back sorting, in a more varied scene it will be inefficient.
    The correct way of doing it is by rendering the terrain first, then doing the queries all at the same time, you wait for the queries to finish and whichever geometries passed the queries are rendered.

    You could probably create another queue that is used for the occlusion queries, and then flush it at some point (e.g. after terrain). You then prevent the geometry from being rendered later on by checking the query.

  • Profile picture of phate666 phate66670p said 1 year, 3 months ago:

    I thought with

    private void renderGeometryList(GeometryList list, RenderManager rm, Camera cam, boolean clear){
            list.setCamera(cam); // select camera for sorting
            list.sort();
           .....
    }
    

    the list would be sortet, such that objects close to the camera are rendered first

  • Profile picture of Momoko_Fan Momoko_Fan366p said 1 year, 3 months ago:

    Yeah they are sorted according to the GeometryComparator, which in this case is the opaque one which sorts by material first.

  • Profile picture of alrik alrik said 4 months ago:

    hi there an update for the current jme3 version?

  • Profile picture of normen normen1271p said 4 months ago:

    @alrik said:
    hi there an update for the current jme3 version?

    oO

  • Profile picture of alrik alrik said 4 months ago:

    sorry, i mean: is there a new version of the occlusion culling script? because this one doesn’t work with the current jme3 version (several errors)