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

如何在React Three Fiber中实现几何体面的悬停高亮效果?

Three.js原生立方体面悬停高亮转译为React Three Fiber版本

原生Three.js实现核心逻辑回顾

你找到的原生方案核心是通过Raycaster检测鼠标与立方体面的交点,根据materialIndex切换对应面材质的颜色,核心代码片段如下:

// 省略场景/相机/渲染器初始化代码
const geometry = new THREE.BoxGeometry();
const materials = Array.from({ length: 6 }, () => new THREE.MeshPhongMaterial({ color: 0x00ff00 }));
const cube = new THREE.Mesh(geometry, materials);

const raycaster = new THREE.Raycaster();
let activeFaceIndex = -1;
renderer.domElement.addEventListener("mousemove", (event) => {
  const mouse = new THREE.Vector2(
    (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
    -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
  );
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObject(cube, false);
  
  // 颜色切换逻辑
  if (intersects.length > 0) {
    const faceIndex = intersects[0].face.materialIndex;
    if (faceIndex !== activeFaceIndex) {
      if (activeFaceIndex !== -1) materials[activeFaceIndex].color.setHex(0x00ff00);
      activeFaceIndex = faceIndex;
      materials[faceIndex].color.setHex(0xff0000);
    }
  } else {
    if (activeFaceIndex !== -1) materials[activeFaceIndex].color.setHex(0x00ff00);
    activeFaceIndex = -1;
  }
});

React Three Fiber转译实现

React Three Fiber通过声明式API封装了Three.js底层逻辑,以下是转译后的完整实现:

依赖安装

先安装所需依赖:

npm install three @react-three/fiber @react-three/drei

完整组件代码

import { useState, useRef, useFrame } from 'react';
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
import * as THREE from 'three';

function HoverCube() {
  // 存储立方体实例
  const cubeRef = useRef(null);
  // 跟踪当前高亮的面索引
  const [activeFaceIndex, setActiveFaceIndex] = useState(-1);
  // 存储6个面的材质(避免React状态频繁更新)
  const materialsRef = useRef([]);

  useFrame((state) => {
    const { mouse, camera } = state;

    // 初始化材质(仅执行一次)
    if (materialsRef.current.length === 0 && cubeRef.current) {
      materialsRef.current = Array.from({ length: 6 }, () => 
        new THREE.MeshPhongMaterial({ color: 0x00ff00 })
      );
      cubeRef.current.material = materialsRef.current;
    }

    // 鼠标交互检测
    const raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(mouse, camera);

    if (cubeRef.current) {
      const intersects = raycaster.intersectObject(cubeRef.current, false);
      
      if (intersects.length > 0) {
        const faceIndex = intersects[0].face.materialIndex;
        if (faceIndex !== activeFaceIndex) {
          // 恢复上一个面的颜色
          if (activeFaceIndex !== -1) {
            materialsRef.current[activeFaceIndex].color.setHex(0x00ff00);
          }
          setActiveFaceIndex(faceIndex);
          // 设置当前面为高亮色
          materialsRef.current[faceIndex].color.setHex(0xff0000);
        }
      } else {
        // 鼠标离开时恢复所有面颜色
        if (activeFaceIndex !== -1) {
          materialsRef.current[activeFaceIndex].color.setHex(0x00ff00);
          setActiveFaceIndex(-1);
        }
      }

      // 立方体旋转动画
      cubeRef.current.rotation.x += 0.01;
      cubeRef.current.rotation.y += 0.01;
    }
  });

  return (
    <mesh ref={cubeRef}>
      <boxGeometry />
    </mesh>
  );
}

export default function App() {
  return (
    <Canvas camera={{ position: [0, 0, 2] }}>
      {/* 平行光,对应原生的DirectionalLight */}
      <directionalLight position={[2, 2, 10]} />
      <HoverCube />
      {/* 轨道控制器,自动绑定相机和渲染器 */}
      <OrbitControls />
    </Canvas>
  );
}

关键差异说明

  • 封装层级:Canvas组件自动处理场景、相机、渲染器的创建与resize适配,无需手动监听窗口事件
  • 状态管理:使用useRef存储材质数组,避免因React状态更新触发不必要的重渲染;useState仅跟踪当前高亮面索引
  • 动画与交互:useFrame钩子替代原生的requestAnimationFrame循环,每帧执行交互检测和动画逻辑,state.mouse已自动转换为Three.js所需的设备坐标
  • 组件化:将立方体的交互逻辑封装为独立组件,符合React的组件化开发模式

扩展方案(三角形面高亮)

若需要实现单个三角形面的高亮(而非整个立方体面),核心逻辑类似,只需将intersects[0].face.materialIndex替换为intersects[0].faceIndex,并调整材质逻辑:

  • 若使用单材质,需启用几何体的顶点颜色,通过修改geometry.colors数组实现单个三角形的颜色切换
  • 或使用自定义着色器,通过uniform变量传递高亮的三角形索引,在片元着色器中控制颜色

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:07:20