React Three Fiber中InstancedMesh单实例选中高亮及HTML提示实现
React Three Fiber 下 InstancedMesh 单实例交互实现需求
背景
在React应用中基于react-three-fiber使用three.js的 InstancedMesh 开发3D散点图,目前已完成球体绘制、分色渲染功能,无法实现鼠标点击/悬停时选中、高亮单个球体实例的需求。
此前使用onPointerOver、onPointerOut事件实现交互未生效,这类事件默认不支持InstancedMesh单个实例的拾取,已知实现该交互需要用到raycaster,需要具体可落地的实现方案。
项目初始化步骤
npx create-react-app demo cd demo npm install three npm i @react-three/fiber npm i @react-three/drei
现有实现代码
App.jsx
import React from 'react' import { Suspense } from "react"; import { Canvas } from "@react-three/fiber"; import { OrbitControls } from "@react-three/drei"; import Spheres from "./IScatter"; import * as THREE from "three"; function App() { return ( <div> <Canvas style={{width:"100%",height:"100vh"}}> <OrbitControls enableZoom={true} /> <ambientLight intensity={0.5} /> <pointLight position={[10, 10, 10]}/> <Suspense fallback={null}> <primitive object={new THREE.AxesHelper(1.5)} /> <Spheres /> </Suspense> </Canvas> </div> ); } export default App;
IScatter.jsx
import * as THREE from "three"; import React, { useRef, useState } from "react"; import { useEffect } from "react"; import { DoubleSide } from "three"; const points = [ [1, 0, -1], [0, 1, -0.5], [0.5, 0.5, 0.5], [1,0.25,-1], [1,0,1], [0,1,0.5] ]; const content = ["Hello", "World", "Hello World", "Shoes", "Drone", "Foo Bar"]; const colors = [0,0,0,5,5,5]; const tempSphere = new THREE.Object3D(); const Spheres = () => { const material = new THREE.MeshLambertMaterial({ opacity: 0.5, side: THREE.DoubleSide, transparent: true,}); const spheresGeometry = new THREE.SphereBufferGeometry(0.25, 15, 15); const ref = useRef(); const [active, setActive] = useState(false); const [hover, setHover] = useState(false); useEffect(() => { points.map(function (val, row) { console.log(val, row); tempSphere.position.set(val[0], val[1], val[2]); tempSphere.updateMatrix(); ref.current.setMatrixAt(row, tempSphere.matrix); ref.current.setColorAt(row, new THREE.Color(`hsl(${colors[row]*100}, 100%, 50%)`)); }); ref.current.instanceMatrix.needsUpdate = true; // ref.current.instanceColor.needsUpdate = true; }); return ( <instancedMesh onClick={() => { setActive(!active); }} onPointerOver={() => { setHover(true); }} onPointerOut={() => { setHover(false); }} ref={ref} rotation={[0,0,0]} args={[spheresGeometry, material, 15]} opacity={active?0.9:0.5} /> ); }; export default Spheres;
预期交互效果
- 选中单个球体时,修改对应球体的不透明度、适当放大尺寸,作为选中状态标识
- 选中球体时,在画布外侧、散点图旁展示该球体关联的HTML内容
实现效果参考three.js官方InstancedMesh射线拾取示例,需适配react-three-fiber技术栈,同时支持球体关联内容的展示。
内容的提问来源于stack exchange,提问作者jar
相关产品推荐
相关产品推荐

