如何在ThreeJS+React-three-fiber应用中添加Crosshair准星
React Three Fiber + Three.js VR场景准星实现方案
VR场景下的中心准星优先采用3D对象挂载相机的实现方案,可完美兼容VR双目立体渲染,不会出现错位、重影问题,不推荐纯HTML叠加方案用于VR环境。
方案1:3D准星(VR场景首选)
核心逻辑是将准星作为独立3D对象,每帧更新位置到相机正前方固定距离,始终对齐视口中心,使用不受光照影响的基础材质保证全场景可见。
注意提前在文件头部引入依赖:import * as THREE from 'three'
import { useRef } from 'react' import { useThree, useFrame } from '@react-three/fiber' import { Ring, Circle } from '@react-three/drei' export default function Crosshair() { const { camera } = useThree() const crosshairGroup = useRef(null) useFrame(() => { if (!crosshairGroup.current) return // 固定在相机正前方0.5米位置,适配人眼舒适对焦距离 const frontVector = camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(0.5) crosshairGroup.current.position.copy(camera.position.clone().add(frontVector)) // 准星角度始终和相机对齐,避免倾斜变形 crosshairGroup.current.quaternion.copy(camera.quaternion) }) return ( <group ref={crosshairGroup} userData={{ skipRaycast: true }}> {/* 外白环 */} <Ring args={[0.008, 0.01, 32]}> <meshBasicMaterial color="#ffffff" side={THREE.DoubleSide} /> </Ring> {/* 中心红点 */} <Circle args={[0.002, 32]} position={[0, 0, 0.001]}> <meshBasicMaterial color="#ff3b30" side={THREE.DoubleSide} /> </Circle> </group> ) }
使用时直接将<Crosshair />放在<Canvas>组件的根层级即可,无需嵌套在其他场景节点内。
- 参数调整:修改
Ring和Circle的半径参数可以调整准星大小,修改multiplyScalar的数值可以调整准星和用户的距离,推荐设置在0.3-1米区间,避免距离过近引发眩晕。 - 交互扩展:如果需要实现击中可交互物体时准星变色、缩放的反馈,直接将射线检测的命中结果绑定到对应材质的颜色、scale属性即可,响应延迟可控制在单帧内。
方案2:CSS准星(仅2D全屏预览适用)
如果是PC端非VR的平面预览场景,直接用固定定位的CSS层实现更省性能,注意要关闭元素的鼠标事件捕获,避免拦截场景交互。
// 和Canvas组件同级放置,不要放在Canvas内部 export default function CssCrosshair() { return ( <div style={{ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: 20, height: 20, pointerEvents: 'none', zIndex: 999 }} > <div style={{ width: '100%', height: '100%', border: '2px solid #fff', borderRadius: '50%', boxSizing: 'border-box' }} /> <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: 4, height: 4, borderRadius: '50%', backgroundColor: '#ff3b30' }} /> </div> ) }
避坑提示
- 3D准星不要用
MeshStandardMaterial等受光照影响的材质,否则会出现场景过暗时准星看不见、过亮时准星过曝的问题,必须使用不受场景光照影响的MeshBasicMaterial。 - VR模式禁止使用CSS准星,VR是双目分视口渲染,CSS层只会渲染在平面屏幕上,会出现单眼可见、重影、深度错位的问题。
- 一定要给3D准星加上
userData={{ skipRaycast: true }}标记,避免交互射线误命中准星本身,导致场景交互失效。 - 准星距离不要设置在0.3米以内,过近的物体会导致双目汇聚冲突,引发用户眩晕。
内容的提问来源于stack exchange,提问作者Thushara Buddhika
相关产品推荐
相关产品推荐

