Skip to main content

threejs-interaction

"Implement — Three.js interaction - raycasting, controls, mouse/touch input, object selection. Use when handling user input,"

الانتقال إلى التثبيت

معلومات المصدر

المستودع
thiagofernandes1987-create/APEX
آخر نشاط في المصدر
١٨ أبريل ٢٠٢٦ في ٠٩:٣٥
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
threejs-interaction
description
"Implement — Three.js interaction - raycasting, controls, mouse/touch input, object selection. Use when handling user input,"
# Three.js Interaction ## When to Use - You need user interaction inside a Three.js scene. - The task involves raycasting, object picking, pointer handling, touch input, or camera controls. - You are building an interactive 3D experience rather than a passive render. ## Quick Start ```javascript import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; // Camera controls const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; // Raycasting for click detection const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); function onClick(event) { mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(scene.children); if (intersects.length > 0) { console.log("Clicked:", intersects[0].object); } } window.addEventListener("click", onClick); ``` ## Raycaster ### Basic Raycasting ```javascript const raycaster = new THREE.Raycaster(); // From camera (mouse picking) raycaster.setFromCamera(mousePosition, camera); // From any origin and direction raycaster.set(origin, direction); // origin: Vector3, direction: normalized Vector3 // Get intersections const intersects = raycaster.intersectObjects(objects, recursive); // intersects array contains: // { // distance: number, // Distance from ray origin // point: Vector3, // Intersection point in world coords // face: Face3, // Intersected face // faceIndex: number, // Face index // object: Object3D, // Intersected object // uv: Vector2, // UV coordinates at intersection // uv1: Vector2, // Second UV channel // normal: Vector3, // Interpolated face normal // instanceId: number // For InstancedMesh // } ``` ### Mouse Position Conversion ```javascript const mouse = new THREE.Vector2(); function updateMouse(event) { // For full window mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; } // For specific canvas element function updateMouseCanvas(event, canvas) { const rect = canvas.getBoundingClientRect(); mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; } ``` ### Touch Support ```javascript function onTouchStart(event) { event.preventDefault(); if (event.touches.length === 1) { const touch = event.touches[0]; mouse.x = (touch.clientX / window.innerWidth) * 2 - 1; mouse.y = -(touch.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(clickableObjects); if (intersects.length > 0) { handleSelection(intersects[0]); } } } renderer.domElement.addEventListener("touchstart", onTouchStart); ``` ### Raycaster Options ```javascript const raycaster = new THREE.Raycaster(); // Near/far clipping (default: 0, Infinity) raycaster.near = 0; raycaster.far = 100; // Line/Points precision raycaster.params.Line.threshold = 0.1; raycaster.params.Points.threshold = 0.1; // Layers (only intersect objects on specific layers) raycaster.layers.set(1); ``` ### Efficient Raycasting ```javascript // Only check specific objects const clickables = [mesh1, mesh2, mesh3]; const intersects = raycaster.intersectObjects(clickables, false); // Use layers for filtering mesh1.layers.set(1); // Clickable layer raycaster.layers.set(1); // Throttle raycast for hover effects let lastRaycast = 0; function onMouseMove(event) { const now = Date.now(); if (now - lastRaycast < 50) return; // 20fps max lastRaycast = now; // Raycast here } ``` ## Camera Controls ### OrbitControls ```javascript import { OrbitControls } from "three/addons/controls/OrbitControls.js"; const controls = new OrbitControls(camera, renderer.domElement); // Damping (smooth movement) controls.enableDamping = true; controls.dampingFactor = 0.05; // Rotation limits controls.minPolarAngle = 0; // Top controls.maxPolarAngle = Math.PI / 2; // Horizon controls.minAzimuthAngle = -Math.PI / 4; // Left controls.maxAzimuthAngle = Math.PI / 4; // Right // Zoom limits controls.minDistance = 2; controls.maxDistance = 50; // Enable/disable features controls.enableRotate = true; controls.enableZoom = true; controls.enablePan = true; // Auto-rotate controls.autoRotate = true; controls.autoRotateSpeed = 2.0; // Target (orbit point) controls.target.set(0, 1, 0); // Update in animation loop function animate() { controls.update(); // Required for damping and auto-rotate renderer.render(scene, camera); } ``` #### OrbitControls Programmatic Methods (r183) ```javascript // Programmatic camera movement controls.dolly(1.5); // Dolly in/out (zoom for perspective cameras) controls.pan(deltaX, deltaY); // Pan the camera controls.rotate(deltaAzimuth, deltaPolar); // Rotate around target // Cursor style (r183) controls.cursorStyle = { orbit: "grab", pan: "move", dolly: "zoom-in" }; ``` ### FlyControls ```javascript import { FlyControls } from "three/addons/controls/FlyControls.js"; const controls = new FlyControls(camera, renderer.domElement); controls.movementSpeed = 10; controls.rollSpeed = Math.PI / 24; controls.dragToLook = true; // Update with delta function animate() { controls.update(clock.getDelta()); renderer.render(scene, camera); } ``` ### FirstPersonControls ```javascript import { FirstPersonControls } from "three/addons/controls/FirstPersonControls.js"; const controls = new FirstPersonControls(camera, renderer.domElement); controls.movementSpeed = 10; controls.lookSpeed = 0.1; controls.lookVertical = true; controls.constrainVertical = true; controls.verticalMin = Math.PI / 4; controls.verticalMax = (Math.PI * 3) / 4; function animate() { controls.update(clock.getDelta()); } ``` ### PointerLockControls ```javascript import { PointerLockControls } from "three/addons/controls/PointerLockControls.js"; const controls = new PointerLockControls(camera, document.body); // Lock pointer on click document.addEventListener("click", () => { controls.lock(); }); controls.addEventListener("lock", () => { console.log("Pointer locked"); }); controls.addEventListener("unlock", () => { console.log("Pointer unlocked"); }); // Movement const velocity = new THREE.Vector3(); const direction = new THREE.Vector3(); const moveForward = false; const moveBackward = false; document.addEventListener("keydown", (event) => { switch (event.code) { case "KeyW": moveForward = true; break; case "KeyS": moveBackward = true; break; } }); function animate() { if (controls.isLocked) { direction.z = Number(moveForward) - Number(moveBackward); direction.normalize(); velocity.z -= direction.z * 0.1; velocity.z *= 0.9; // Friction controls.moveForward(-velocity.z); } } ``` ### TrackballControls ```javascript import { TrackballControls } from "three/addons/controls/TrackballControls.js"; const controls = new TrackballControls(camera, renderer.domElement); controls.rotateSpeed = 2.0; controls.zoomSpeed = 1.2; controls.panSpeed = 0.8; controls.staticMoving = true; function animate() { controls.update(); } ``` ### MapControls ```javascript import { MapControls } from "three/addons/controls/MapControls.js"; const controls = new MapControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; controls.screenSpacePanning = false; controls.maxPolarAngle = Math.PI / 2; ``` ## TransformControls Gizmo for moving/rotating/scaling objects. ```javascript import { TransformControls } from "three/addons/controls/TransformControls.js"; const transformControls = new TransformControls(camera, renderer.domElement); scene.add(transformControls); // Attach to object transformControls.attach(selectedMesh); // Switch modes transformControls.setMode("translate"); // 'translate', 'rotate', 'scale' // Change space transformControls.setSpace("local"); // 'local', 'world' // Size transformControls.setSize(1); // Events transformControls.addEventListener("dragging-changed", (event) => { // Disable orbit controls while dragging orbitControls.enabled = !event.value; }); transformControls.addEventListener("change", () => { renderer.render(scene, camera); }); // Keyboard shortcuts window.addEventListener("keydown", (event) => { switch (event.key) { case "g": transformControls.setMode("translate"); break; case "r": transformControls.setMode("rotate"); break; case "s": transformControls.setMode("scale"); break; case "Escape": transformControls.detach(); break; } }); ``` ## DragControls Drag objects directly. ```javascript import { DragControls } from "three/addons/controls/DragControls.js"; const draggableObjects = [mesh1, mesh2, mesh3]; const dragControls = new DragControls( draggableObjects, camera, renderer.domElement, ); dragControls.addEventListener("dragstart", (event) => { orbitControls.enabled = false; event.object.material.emissive.set(0xaaaaaa); }); dragControls.addEventListener("drag", (event) => { // Constrain to ground plane event.object.position.y = 0; }); dragControls.addEventListener("dragend", (event) => { orbitControls.enabled = true; event.object.material.emissive.set(0x000000); }); ``` ## Selection System ### Click to Select ```javascript const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); let selectedObject = null; function onMouseDown(event) { mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(selectableObjects); // Deselect previous if (selectedObject) { selectedObject.material.emissive.set(0x000000); } // Select new if (intersects.length > 0) { selectedObject = intersects[0].object; selectedObject.material.emissive.set(0x444444); } else { selectedObject = null; } } ``` ### Box Selection ```javascript import { SelectionBox } from "three/addons/interactive/SelectionBox.js"; import { SelectionHelper } from "three/addons/interactive/SelectionHelper.js"; const selectionBox = new SelectionBox(camera, scene); const selectionHelper = new SelectionHelper(renderer, "selectBox"); // CSS class document.addEventListener("pointerdown", (event) => { selectionBox.startPoint.set( (event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5, ); }); document.addEventListener("pointermove", (event) => { if (selectionHelper.isDown) { selectionBox.endPoint.set( (event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5, ); } }); document.addEventListener("pointerup", (event) => {
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub