Three.js技术问题:如何为2D场景添加带自定义属性的可点击图形
Hey there! Let's get your triangle mesh set up with custom properties and working click events. First, a quick heads-up: Three.js Mesh objects don't natively support the on('click') event you're trying to use—we'll need to use a Raycaster to detect clicks on 3D objects instead. Plus, adding custom properties is straightforward once you know the right way to do it without conflicting with Three.js internals.
Step 1: Fix Click Detection with Raycaster
Raycasting is how Three.js checks if a mouse click intersects with any 3D objects in your scene. Here's how to implement it:
First, declare these variables outside your mesh creation code (so they're accessible in event handlers):
let raycaster = new THREE.Raycaster(); let mouse = new THREE.Vector2();
Then, add a mouse click event listener to your window/canvas:
window.addEventListener('mousedown', onMouseDown); function onMouseDown(event) { // Convert mouse position to normalized device coordinates (-1 to +1) mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // Update the picking ray with the camera and mouse position raycaster.setFromCamera(mouse, camera); // Make sure 'camera' is your scene's camera // Calculate objects intersecting the picking ray const intersects = raycaster.intersectObjects(scene.children); // Check if we hit any objects if (intersects.length > 0) { const clickedMesh = intersects[0].object; console.log('Clicked mesh:', clickedMesh); // Here's where we'll access custom properties later! } }
Step 2: Add Custom Properties to Your Mesh
Three.js provides a userData property on all objects specifically for storing custom data—this is the safest way to add your own properties without overwriting built-in Three.js functionality. You can also add direct properties, but userData is recommended.
Modify your mesh creation code to include custom properties:
var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3(50, 0, 90), new THREE.Vector3(130, 0, 95), new THREE.Vector3(74, 0, -50) ); geometry.faces.push(new THREE.Face3(0, 1, 2)); // Important: For older Geometry (not BufferGeometry), update faces/vertices geometry.computeFaceNormals(); var material = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.9, transparent: true }); // Add transparent: true for opacity to work var mesh = new THREE.Mesh(geometry, material); // Add custom properties using userData mesh.userData = { id: 'triangle-001', name: 'Red Clickable Triangle', customData: { value: 42, description: 'My first interactive mesh' } }; // Alternatively, add direct properties (not recommended, but works) // mesh.myCustomId = 'triangle-001'; scene.add(mesh);
Step 3: Access Custom Properties on Click
Now update the onMouseDown function to access your custom properties when the mesh is clicked:
function onMouseDown(event) { // ... (previous code) if (intersects.length > 0) { const clickedMesh = intersects[0].object; console.log('Clicked mesh custom data:', clickedMesh.userData); console.log('Mesh name:', clickedMesh.userData.name); console.log('Custom value:', clickedMesh.userData.customData.value); // If you added direct properties: // console.log('Direct custom ID:', clickedMesh.myCustomId); } }
Extra Tips for Improvement
- Use BufferGeometry:
THREE.Geometryis deprecated—for better performance, switch toTHREE.BufferGeometryinstead. Here's a quick conversion for your triangle:const geometry = new THREE.BufferGeometry(); const vertices = new Float32Array([ 50, 0, 90, 130, 0, 95, 74, 0, -50 ]); geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); geometry.setIndex(new THREE.BufferAttribute(new Uint16Array([0, 1, 2]), 1)); geometry.computeFaceNormals(); - Optimize Raycasting: If you have many objects, add them to a group and pass
group.childrentointersectObjectsinstead ofscene.childrento narrow down the detection range. - Hover Effects: You can extend the raycasting logic to
mousemoveevents to add hover states (e.g., changing material color when the mouse is over the mesh).
内容的提问来源于stack exchange,提问作者Giox

