Co-Pilot / 辅助式
更新于 a month ago

threejs-interaction

CCloudAI-X
0.8k
CloudAI-X/threejs-skills/skills/threejs-interaction
82
Agent 评分

💡 摘要

此技能使用Three.js启用交互式3D体验,具有射线投射和相机控制等功能。

🎯 适合人群

创建交互式3D应用程序的Web开发人员寻找用户输入处理的游戏开发人员教授3D图形编程的教育工作者实施3D界面的UI/UX设计师探索3D建模和交互的爱好者

🤖 AI 吐槽:看起来很能打,但别让配置把人劝退。

安全分析低风险

风险:Low。建议检查:权限范围、数据流向与依赖风险。以最小权限运行,并在生产环境启用前审计代码与依赖。


name: threejs-interaction description: Three.js interaction - raycasting, controls, mouse/touch input, object selection. Use when handling user input, implementing click detection, adding camera controls, or creating interactive 3D experiences.

Three.js Interaction

Quick Start

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

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

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

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

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

// 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

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); }

FlyControls

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

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

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

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

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.

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.

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

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

import { SelectionBox } from "three/addons/interac
五维分析
清晰度9/10
创新性7/10
实用性9/10
完整性8/10
可维护性8/10
优缺点分析

优点

  • 全面的射线投射和交互功能
  • 多种相机控制选项以灵活性
  • 结构良好的代码示例,便于实现

缺点

  • 缺乏详细的安装说明
  • 没有清晰的实际应用示例
  • 可以受益于更多高级用例

相关技能

pytorch

S
toolCode Lib / 代码库
92/ 100

“它是深度学习的瑞士军刀,但祝你好运能从47种安装方法里找到那个不会搞崩你系统的那一个。”

agno

S
toolCode Lib / 代码库
90/ 100

“它承诺成为智能体领域的Kubernetes,但得看开发者有没有耐心学习又一个编排层。”

nuxt-skills

S
toolCo-Pilot / 辅助式
90/ 100

“这本质上是一份组织良好的小抄,能把你的 AI 助手变成一只 Nuxt 框架的复读机。”

免责声明:本内容来源于 GitHub 开源项目,仅供展示和评分分析使用。

版权归原作者所有 CloudAI-X.