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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:09:11