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

在@react-three/fiber中使用lookAt方法

解决@react-three/fiber中立方体朝向原点的问题

我看到你在尝试用@react-three/fiber和@react-three/drei构建基于国家坐标的立方体,期望它们能朝向原点,但现在所有立方体都朝单一方向偏移——这问题我之前做类似球面可视化项目时也碰到过,咱们一步步把它搞定。

问题出在哪?

你当前代码里的lookAt用法不对:

  • @react-three/fiber的Mesh组件(包括drei的NativeBox)的lookAt属性,接受的是目标坐标(Vector3或数组),而不是你写的函数。你定义的lookAtFunc只是修改了传入的Vector3,但根本没把这个操作应用到立方体网格上,所以完全没生效。
  • 你在useFrame里让相机看向原点,这和立方体的朝向是两回事,相机视角不影响立方体自身的朝向。

两种可行的解决方案

方案1:直接通过组件属性设置(最简洁)

drei的Box组件继承了three.js Mesh的能力,直接给它的lookAt属性传原点坐标[0,0,0]就行,不需要额外函数:

import React, { FC, useRef } from 'react';
import { Box as NativeBox } from '@react-three/drei'
import { useFrame } from '@react-three/fiber';

type Props = {
  country: any,
}

const Box: FC<Props> = (props) => {
  const mesh = useRef()
  const { country } = props;
  const scale = country.population / 1000000000
  const lat = country.latlng[0]
  const lng = country.latlng[1]
  const zScale = 0.8 * scale
  const latitude = (lat / 180) * Math.PI
  const longitude = (lng / 180) * Math.PI
  const radius = 5
  const x = radius * Math.cos(latitude) * Math.sin(longitude)
  const y = radius * Math.sin(latitude)
  const z = radius * Math.cos(latitude) * Math.cos(longitude)

  return <NativeBox
    args={[
      Math.max(0.1, 0.2 * scale),
      Math.max(0.1, 0.2 * scale),
      Math.max(zScale, 0.4 * Math.random())
    ]}
    position={[ x, y, z ]}
    // 直接传入原点坐标,让立方体朝向球心
    lookAt={[0, 0, 0]}
    ref={mesh}
  >
    <meshBasicMaterial attach="material" color="#3BF7FF" opacity={0.6} transparent={true} />
  </NativeBox>;
};

export default Box;

方案2:用useFrame动态控制(适合需要实时调整的场景)

如果之后你需要根据动画、交互等动态改变立方体朝向,可以通过useRef获取网格实例,在useFrame里调用原生three.js的lookAt方法:

import React, { FC, useRef } from 'react';
import { Box as NativeBox } from '@react-three/drei'
import { Vector3 } from 'three';
import { useFrame } from '@react-three/fiber';

type Props = {
  country: any,
}

const Box: FC<Props> = (props) => {
  const mesh = useRef()
  const { country } = props;
  const scale = country.population / 1000000000
  const lat = country.latlng[0]
  const lng = country.latlng[1]
  const zScale = 0.8 * scale
  const latitude = (lat / 180) * Math.PI
  const longitude = (lng / 180) * Math.PI
  const radius = 5
  const x = radius * Math.cos(latitude) * Math.sin(longitude)
  const y = radius * Math.sin(latitude)
  const z = radius * Math.cos(latitude) * Math.cos(longitude)

  // 在每一帧更新立方体朝向(如果需要动态变化,这里可以加逻辑)
  useFrame(() => {
    if (mesh.current) {
      mesh.current.lookAt(new Vector3(0, 0, 0));
    }
  })

  return <NativeBox
    args={[
      Math.max(0.1, 0.2 * scale),
      Math.max(0.1, 0.2 * scale),
      Math.max(zScale, 0.4 * Math.random())
    ]}
    position={[ x, y, z ]}
    ref={mesh}
  >
    <meshBasicMaterial attach="material" color="#3BF7FF" opacity={0.6} transparent={true} />
  </NativeBox>;
};

export default Box;

额外说明

  • 如果你之前的useFrame里的state.camera.lookAt是为了让相机始终对准原点,那可以保留,但要注意这和立方体的朝向完全独立,别混为一谈。
  • 你的球面坐标计算是对的,修改朝向之后,每个立方体都会指向球心,不会再出现单一方向偏移的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 10:07:34