在@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
相关产品推荐
相关产品推荐

