WebGL屏幕转世界坐标:深度缓冲区值获取异常问题排查
3D地球模型点击检测的深度值转换问题
背景
我正在创建一个带高程的3D地球模型:
现在需要添加点击检测功能,通过2D屏幕XY坐标+深度值获取3D世界XYZ坐标。我基于gl-matrix实现了反投影计算代码:
static unProject(screenX: number, screenY: number, depth: number, projMatrix: mat4, viewMatrix: mat4): vec3 { // Convert x, y, depth from [0 .. 1] to NDC [-1 .. 1] const clipSpacePosition: vec4 = vec4.fromValues( screenX * 2.0 - 1.0, screenY * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0 ); let viewSpacePosition: vec4 = vec4.transformMat4(vec4.create(), clipSpacePosition, mat4.invert(mat4.create(), projMatrix)); // Normalize eye coordinates viewSpacePosition[0] /= viewSpacePosition[3]; viewSpacePosition[1] /= viewSpacePosition[3]; viewSpacePosition[2] /= viewSpacePosition[3]; viewSpacePosition[3] /= viewSpacePosition[3]; const worldSpacePosition: vec4 = vec4.transformMat4(vec4.create(), viewSpacePosition, mat4.invert(mat4.create(), viewMatrix)); // Normalize world coordinates worldSpacePosition[0] /= worldSpacePosition[3]; worldSpacePosition[1] /= worldSpacePosition[3]; worldSpacePosition[2] /= worldSpacePosition[3]; return vec3.fromValues(worldSpacePosition[0], worldSpacePosition[1], worldSpacePosition[2]); }
测试时点击法国东南部,绘制了1000个深度值在[0..1]范围的立方体:
隐藏球体后的效果:
立方体正确分布在z-near和z-far平面之间,但z-near附近的分辨率远高于z-far(立方体沿轴线分布不均)。缩小z-near会加剧该效果(极端情况所有立方体都在z-near上),这符合深度测试的原理,但不确定是否存在问题。
问题
我通过测试找到与球体相交的紫色立方体的深度值约为0.962(z-near=1,z-far=500),现在需要从OpenGL深度缓冲区获取该值。我使用片段着色器将深度值(gl_FragCoord.z)编码为RGBA:
#version 300 es precision highp float; vec4 encode(float depth) { vec4 bitSh = vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0); vec4 bitMsk = vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); vec4 enc = fract(depth * bitSh); enc -= enc.xxyz * bitMsk; return enc; } void main(void) { color = encode(gl_FragCoord.z); }
并在JS端进行解码:
decode(color: vec4) { const bitSh: vec4 = vec4.fromValues(1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0); return vec4.dot(color, bitSh); }
我在JS中实现了相同的编码方法,验证编码解码功能正常(仅存在微小精度误差,例如编码解码0.962得到0.9619999999999997)。
但通过该方法从OpenGL获取的深度值远小于预期:实际得到约0.268,而预期为0.962。请问我是否遗漏了对深度缓冲区值的转换?
内容的提问来源于stack exchange,提问作者Tim Autin
相关产品推荐
相关产品推荐

