You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将物体顶点坐标转换为相机相对坐标?附Three.js尝试代码

解决Three.js中物体顶点坐标转相机相对坐标的问题

一、两种实现思路

1. 直接修改几何体顶点(仅适用于非蒙皮网格)

如果物体是普通Mesh而非蒙皮网格,可直接遍历几何体顶点,执行「顶点位置 - 相机位置」的计算:

// 遍历物体的所有网格
object.traverse(node => {
  if (node.isMesh && !node.isSkinnedMesh) {
    const geometry = node.geometry;
    // 遍历每个顶点坐标
    const positions = geometry.attributes.position.array;
    for (let i = 0; i < positions.length; i += 3) {
      positions[i] -= camera.position.x;
      positions[i+1] -= camera.position.y;
      positions[i+2] -= camera.position.z;
    }
    // 标记顶点属性需要更新
    geometry.attributes.position.needsUpdate = true;
  }
});

注意:这种方法会永久修改几何体数据,后续相机移动时需要重新计算,仅适合静态场景。

2. Shader实时计算(推荐,支持蒙皮网格)

对于蒙皮网格(如你使用的Stormtrooper模型),顶点位置会受骨骼动画动态影响,直接修改顶点无效,必须在顶点着色器中实时计算相对相机的坐标:

// 自定义顶点着色器(基于Three.js默认蒙皮着色器修改)
varying vec2 vUv;

void main() {
    vUv = uv;
    
    // 计算蒙皮后的顶点位置
    vec4 skinnedPosition = skinningMatrix * vec4(position, 1.0);
    // 转换到世界空间
    vec4 worldPosition = modelMatrix * skinnedPosition;
    
    // 计算相对相机的位置:世界坐标 - 相机世界坐标
    vec4 relativePosition = worldPosition - vec4(cameraPosition, 1.0);
    
    // 转换到裁剪空间完成渲染
    gl_Position = projectionMatrix * viewMatrix * relativePosition;
}

在Three.js中替换蒙皮网格材质的代码示例:

// 加载模型后处理
loader.load('../resources/models/stormtrooper/stormtrooper.dae', (collada) => {
  this.avatar = collada.scene;
  this.avatar.rotation.z = Math.PI;           
  this.camera.add(this.avatar);
  this.avatar.position.set(0, 0, -20);

  this.avatar.traverse((node) => {
    if (node.isSkinnedMesh) {
      node.frustumCulled = false;
      // 创建自定义蒙皮材质
      const shaderMaterial = new THREE.ShaderMaterial({
        vertexShader: 上述顶点着色器代码,
        fragmentShader: THREE.ShaderLib.skinning.fragmentShader, // 复用默认片元着色器
        uniforms: THREE.UniformsUtils.merge([
          THREE.ShaderLib.skinning.uniforms
        ]),
        lights: true,
        skinning: true // 开启蒙皮支持
      });
      node.material = shaderMaterial;
    }
  });
  
  this.scene.add(this.camera);
});

二、你代码中的错误修正

你的代码里重复执行了this.scene.add(this.camera)(加载模型时和添加点光源时各一次),这会导致相机被重复添加到场景,引发坐标计算异常,需要删除其中一次(保留加载模型后的那行即可)。

修正后的添加点光源部分代码:

const pointLight = new THREE.PointLight(0xffffff, 0.8);
this.camera.add(pointLight);
// 删掉下面这行重复代码
// this.scene.add( this.camera );

内容的提问来源于stack exchange,提问作者Spiri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 12:52:47