【问题标题】:Occlusion query using GL_ANY_SAMPLES_PASSED returning true when fragments are occluded当片段被遮挡时,使用 GL_ANY_SAMPLES_PASSED 的遮挡查询返回 true
【发布时间】:2018-04-06 20:31:35
【问题描述】:

我正在为我的引擎实现镜头发光效果。

但是,尝试使用遮挡查询仅在相关片段完全被遮挡时才返回 true。

也许问题在于我手动写入每个顶点的 z 值,因为我使用的是对数深度缓冲区。但是,我不确定为什么这会影响遮挡测试。

以下是相关代码sn-ps:

public class Query implements Disposable{
    private final int id;
    private final int type;

    private boolean inUse = false;

    public Query(int type){
        this.type = type;
        int[] arr = new int[1];
        Gdx.gl30.glGenQueries(1,arr,0);
        id = arr[0];
    }

    public void start(){
        Gdx.gl30.glBeginQuery(type, id);
        inUse = true;
    }

    public void end(){
        Gdx.gl30.glEndQuery(type);
    }

    public boolean isResultReady(){
        IntBuffer result = BufferUtils.newIntBuffer(1);
        Gdx.gl30.glGetQueryObjectuiv(id,Gdx.gl30.GL_QUERY_RESULT_AVAILABLE, result);
        return result.get(0) == Gdx.gl.GL_TRUE;
    }

    public int getResult(){
        inUse = false;
        IntBuffer result = BufferUtils.newIntBuffer(1);
        Gdx.gl30.glGetQueryObjectuiv(id, Gdx.gl30.GL_QUERY_RESULT, result);
        return result.get(0);
    }

    public boolean isInUse(){
        return inUse;
    }

    @Override
    public void dispose() {
        Gdx.gl30.glDeleteQueries(1, new int[]{id},0);
    }
}

这是我进行实际测试的方法:

private void doOcclusionTest(Camera cam){
        if(query.isResultReady()){
            int visibleSamples = query.getResult();
            System.out.println(visibleSamples);
        }


        temp4.set(cam.getPosition());
        temp4.sub(position);
        temp4.normalize();
        temp4.mul(getSize()*10);
        temp4.add(position);
        occlusionTestPoint.setPosition(temp4.x,temp4.y,temp4.z);


        if(!query.isInUse()) {
            query.start();
            Gdx.gl.glEnable(Gdx.gl.GL_DEPTH_TEST);
            occlusionTestPoint.render(renderer.getPointShader(), cam);
            query.end();
        }
    }

我的一个点的顶点着色器,包括对数深度缓冲区计算:

#version 330 core
layout (location = 0) in vec3 aPos;

uniform mat4 modelView;
uniform mat4 projection;
uniform float og_farPlaneDistance;
uniform float u_logarithmicDepthConstant;

vec4 modelToClipCoordinates(vec4 position, mat4 modelViewPerspectiveMatrix, float depthConstant, float farPlaneDistance){
    vec4 clip = modelViewPerspectiveMatrix * position;

    clip.z = ((2.0 * log(depthConstant * clip.z + 1.0) / log(depthConstant * farPlaneDistance + 1.0)) - 1.0) * clip.w;
    return clip;
}

void main()
{
    gl_Position = modelToClipCoordinates(vec4(aPos, 1.0), projection * modelView, u_logarithmicDepthConstant, og_farPlaneDistance);
}

一个点的片段着色器:

#version 330 core

uniform vec4 color;

void main() {
    gl_FragColor = color;
}

由于我只是测试单个点的遮挡,我知道另一种方法是在渲染所有内容后简单地检查该像素的深度值。但是,我不确定如何计算 CPU 上某个点的对数 z 值。

【问题讨论】:

    标签: java opengl 3d libgdx lwjgl


    【解决方案1】:

    我找到了解决问题的方法。这是一种解决方法,仅适用于单点,而不适用于整个模型,但它是这样的:

    首先,您必须计算点的 z 值和它所在的像素坐标。计算 z 值应该很简单,但是在我的情况下,我使用的是对数深度缓冲区。出于这个原因,我不得不对 z 值进行一些额外的计算。

    这是我在标准化设备坐标中获取坐标的方法,包括 z 值(temp4f 可以是任何 Vector4f):

    public Vector4f worldSpaceToDeviceCoords(Vector4f pos){
        temp4f.set(pos);
        Matrix4f projection = transformation.getProjectionMatrix(FOV, screenWidth,screenHeight,1f,MAXVIEWDISTANCE);
        Matrix4f view = transformation.getViewMatrix(camera);
        view.transform(temp4f); //Multiply the point vector by the view matrix
        projection.transform(temp4f); //Multiply the point vector by the projection matrix
    
    
        temp4f.x = ((temp4f.x / temp4f.w) + 1) / 2f; //Convert x coordinate to range between 0 to 1
        temp4f.y = ((temp4f.y / temp4f.w) + 1) / 2f; //Convert y coordinate to range between 0 to 1
    
        //Logarithmic depth buffer z-value calculation (Get rid of this if not using a logarithmic depth buffer)
        temp4f.z = ((2.0f * (float)Math.log(LOGDEPTHCONSTANT * temp4f.z + 1.0f) /
                (float)Math.log(LOGDEPTHCONSTANT * MAXVIEWDISTANCE + 1.0f)) - 1.0f) * temp4f.w;
    
        temp4f.z /= temp4f.w; //Perform perspective division on the z-value
        temp4f.z = (temp4f.z + 1)/2f; //Transform z coordinate into range 0 to 1
    
        return temp4f;
    }
    

    另外这个方法是用来获取屏幕上像素坐标的(temp2是任意的Vector2f):

        public Vector2f projectPoint(Vector3f position){
        temp4f.set(worldSpaceToDeviceCoords(temp4f.set(position.x,position.y,position.z, 1)));
        temp4f.x*=screenWidth;
        temp4f.y*=screenHeight;
    
        //If the point is not visible, return null
        if (temp4f.w < 0){
            return null;
        }
    
    
        return temp2f.set(temp4f.x,temp4f.y);
    
    }
    

    最后,一个获取给定像素的存储深度值的方法(outBuff是任何直接的FloatBuffer):

    public float getFramebufferDepthComponent(int x, int y){
        Gdx.gl.glReadPixels(x,y,1,1,Gdx.gl.GL_DEPTH_COMPONENT,Gdx.gl.GL_FLOAT,outBuff);
        return outBuff.get(0);
    }
    

    所以通过这些方法,你需要做的是找出某个点是否被遮挡:

    1. 检查点所在的像素(第二种方法)
    2. 在该像素处检索当前存储的 z 值(第三种方法)
    3. 获取点的计算z值(第一种方法)
    4. 如果计算的 z 值低于存储的 z 值,则该点可见

    请注意,您应该在对深度缓冲区进行采样之前绘制场景中的所有内容,否则提取的深度缓冲区值将无法反映渲染的所有内容。

    【讨论】:

      猜你喜欢
      • 2017-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      • 2011-06-27
      相关资源
      最近更新 更多