Capítulo 859 de 859
For VR devices with an actual pointing controller, three.js exposes each controller as an Object3D (via renderer.xr.getController(i)) with selectstart/select/selectend events, letting you raycast from the controller's own transform instead of from the camera, and even drag objects by reparenting them onto the controller.
renderer.xr.getController(i): returns an Object3D tracking one controller's position/orientation (three.js handles both single-3DOF and dual-6DOF controller setups); a simple 3D line parented to it visualizes the pointing direction.selectstart / select / selectend: controller events for when the user starts pressing, is pressing, and releases the controller's main button.Object3D (separate from the pointer-line objects) keeps the raycaster from accidentally picking its own visualization lines.EventDispatcher: extending three.js's EventDispatcher lets a helper class translate low-level per-controller select events into one clean high-level select event carrying which object was targeted, simplifying app code.Object3D.attach() for dragging: on selectstart, reparenting a selected object onto the controller with attach() (which preserves world position/orientation during the reparent) makes it move with the controller; reparenting it back to the scene on selectend releases it — the basis for simple 6DOF object manipulation.class ControllerPickHelper extends THREE.EventDispatcher {
constructor(scene) {
super();
this.raycaster = new THREE.Raycaster();
this.controllers = [];
for (let i = 0; i < 2; ++i) {
const controller = renderer.xr.getController(i);
controller.addEventListener("select", (event) => {
const selectedObject = this.controllerToObjectMap.get(event.target);
if (selectedObject) this.dispatchEvent({ type: "select", controller: event.target, selectedObject });
});
scene.add(controller);
this.controllers.push(controller);
}
}
}
select events in a custom EventDispatcher subclass so the app can listen for one unified select event carrying the actually-targeted object.renderer.xr.getController(i) gives you an Object3D per controller with position/orientation and selectstart/select/selectend events.Object3D.attach() reparents an object while preserving its world transform, making it the simple building block for "pick up and move" interactions with a 6DOF controller.Raycaster-based picking pattern reused here with a different ray origin.