我正在为我的引擎实现镜头发光效果。
但是,当有问题的片段完全被遮挡时,尝试使用遮挡查询仅返回true。
也许问题在于我手动写入每个顶点的z值,因为我使用的是对数深度缓冲区。但是,我不确定为什么这会影响遮挡测试。
以下是相关的代码段:
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值。
答案 0 :(得分:0)
我找到了解决问题的方法。这是一种解决方法,只适用于单点,而不适用于整个模型,但现在就是:
首先,您必须计算点的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);
}
因此,使用这些方法,您需要做的是确定某个点是否被遮挡:
请注意,您应该在采样深度缓冲区之前绘制场景中的所有内容,否则提取的深度缓冲区值将不会反映所有渲染的内容。