如何基于vUv与深度值在three.js中重构世界坐标worldPosition.xyz
基于Three.js深度纹理与UV重建世界坐标的实现方法
步骤1:补充着色器Uniform配置
你需要在原depthShader的uniforms中新增两个矩阵参数,JS侧从相机实例直接取值传入:
uniforms: { 'tDiffuse': { value: null }, 'tDepth': { value: null }, 'cameraNear': { value: 0 }, 'cameraFar': { value: 0 }, // 新增参数 'projectionMatrixInverse': { value: null }, 'viewMatrixInverse': { value: null } }
JS侧每帧更新uniform:
depthShader.uniforms.projectionMatrixInverse.value = camera.projectionMatrixInverse; depthShader.uniforms.viewMatrixInverse.value = camera.matrixWorld;
步骤2:修改片段着色器逻辑
原代码中的readDepth函数最终输出的是正交深度值,我们需要保留透视投影下的视图Z坐标用于重建,修改后的片段着色器如下:
#include <packing> uniform sampler2D tDiffuse; uniform sampler2D tDepth; uniform float cameraNear; uniform float cameraFar; uniform mat4 projectionMatrixInverse; uniform mat4 viewMatrixInverse; varying vec2 vUv; // 可以保留原readDepth函数用于深度可视化,新增逻辑单独实现 float readDepth( sampler2D depthSampler, vec2 coord ) { float fragCoordZ = texture2D( depthSampler, coord ).x; float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar ); return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar ); } // 世界坐标重建函数 vec3 getWorldPositionFromDepth(vec2 uv, float depth) { // 构造NDC坐标,范围从[-1, 1] vec4 ndc = vec4(uv * 2.0 - 1.0, depth, 1.0); // 转换到视图空间 vec4 viewPos = projectionMatrixInverse * ndc; // 对齐次坐标做归一化 viewPos /= viewPos.w; // 转换到世界空间 vec4 worldPos = viewMatrixInverse * viewPos; return worldPos.xyz; } void main() { // 采样原始深度值 float rawDepth = texture2D(tDepth, vUv).x; // 重建世界坐标 vec3 worldPosition = getWorldPositionFromDepth(vUv, rawDepth); // 以下是你原有的可视化逻辑可以保留 float depth = readDepth(tDepth, vUv); vec4 color = texture2D(tDiffuse, vUv); gl_FragColor.rgb = 1.0 - vec3( depth ); // 测试:可以输出世界坐标验证是否正确 // gl_FragColor.rgb = worldPosition; }
注意事项
- 上述代码仅适配透视相机,正交相机可以直接用
viewZ替换rawDepth调整计算逻辑 - 建议使用高精度深度纹理避免坐标抖动,Three.js中创建深度纹理时可以指定格式为
THREE.FloatType - 相机位置、旋转、投影参数变化时,需要同步更新两个逆矩阵的uniform值
内容的提问来源于stack exchange,提问作者Spiri
相关产品推荐
相关产品推荐

