我仍然是整个 Three.js 生态系统的菜鸟,所以即使我找到非常接近解决方案的东西,我也会遇到困难。例如,我终于能够通过 seanwasere 在 Three.js Discourse 和 this CodeSandbox 上的评论找到如何在悬停时突出显示几何图形的面的解决方案。
如何将这段代码翻译为 React Three Fiber?作为参考,让我在这里重现代码:
import * as THREE from "/build/three.module.js";
import { OrbitControls } from "/jsm/controls/OrbitControls.js";
import Stats from "/jsm/libs/stats.module.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
100
);
camera.position.z = 2;
const light = new THREE.DirectionalLight();
light.position.set(2, 2, 10);
scene.add(light);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
const geometry = new THREE.BoxGeometry();
var materials = [
new THREE.MeshPhongMaterial({
color: 0x00ff00
}),
new THREE.MeshPhongMaterial({
color: 0x00ff00
}),
new THREE.MeshPhongMaterial({
color: 0x00ff00
}),
new THREE.MeshPhongMaterial({
color: 0x00ff00
}),
new THREE.MeshPhongMaterial({
color: 0x00ff00
}),
new THREE.MeshPhongMaterial({
color: 0x00ff00
})
];
const cube = new THREE.Mesh(geometry, materials);
scene.add(cube);
window.addEventListener(
"resize",
() => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
},
false
);
renderer.domElement.addEventListener("mousemove", onMouseMove, false);
const raycaster = new THREE.Raycaster();
let activeFaceIndex = 0;
function onMouseMove(event) {
raycaster.setFromCamera(
{
x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
},
camera
);
const intersects = raycaster.intersectObject(cube, false);
if (intersects.length > 0) {
if (
intersects[0].face.materialIndex !== activeFaceIndex &&
activeFaceIndex !== -1
) {
materials[activeFaceIndex].color.setHex(0x00ff00);
}
activeFaceIndex = intersects[0].face.materialIndex;
materials[activeFaceIndex].color.setHex(0xff0000);
} else {
if (activeFaceIndex !== -1) {
materials[activeFaceIndex].color.setHex(0x00ff00);
}
activeFaceIndex = -1;
}
}
const stats = Stats();
document.body.appendChild(stats.dom);
var animate = function () {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
controls.update();
render();
stats.update();
};
function render() {
renderer.render(scene, camera);
}
animate();
关于如何突出显示脸上的三角形的另一个有用参考是
R3F版本。
import React, { useRef, useState, Suspense } from 'react'
import { createRoot } from 'react-dom/client'
import { Canvas, useFrame } from '@react-three/fiber'
import { Stats, OrbitControls, Environment } from '@react-three/drei'
function Cube() {
const ref = useRef()
const [activeFaceIndex, setActiveFaceIndex] = useState(-1)
useFrame((_, delta) => {
ref.current.rotation.x += delta
ref.current.rotation.y += 0.5 * delta
})
return (
<mesh
ref={ref}
onPointerMove={({ face }) => {
setActiveFaceIndex(face.materialIndex)
}}
onPointerOut={(e) => {
setActiveFaceIndex(-1)
}}>
<boxGeometry />
<meshStandardMaterial attach={`material-0`} color={activeFaceIndex === 0 ? 'red' : 'green'} />
<meshStandardMaterial attach={`material-1`} color={activeFaceIndex === 1 ? 'red' : 'green'} />
<meshStandardMaterial attach={`material-2`} color={activeFaceIndex === 2 ? 'red' : 'green'} />
<meshStandardMaterial attach={`material-3`} color={activeFaceIndex === 3 ? 'red' : 'green'} />
<meshStandardMaterial attach={`material-4`} color={activeFaceIndex === 4 ? 'red' : 'green'} />
<meshStandardMaterial attach={`material-5`} color={activeFaceIndex === 5 ? 'red' : 'green'} />
</mesh>
)
}
function App() {
return (
<Canvas camera={{ position: [0, 0, 2] }}>
<directionalLight position={[1, 1, 1]} intensity={Math.PI} />
<ambientLight intensity={Math.PI / 8} />
<Cube />
<OrbitControls />
<Stats />
</Canvas>
)
}