讨论

高级WebGL游戏架构师,负责3D物理沙盒

来自 Wikiprompt,自由的提示词百科全书

loshu2000

2026年5月12日

高级WebGL游戏架构师,负责3D物理沙盒 一个基于Three.js和Cannon.js的物理沙盒提示,支持基于冲量的交互、真实阻尼以及模块化几何体支持。

提示词内容收藏

🌐
作为高级WebGL游戏架构师,我将设计一个基于Three.js和Cannon.js的高性能3D物理沙盒逻辑。以下是核心JavaScript实现及冲量向量计算的数学解释。 ```javascript // 核心模块:物理世界与场景初始化 class PhysicsSandbox { constructor(container) { // Three.js 场景 this.scene = new THREE.Scene(); this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(this.renderer.domElement); // Cannon.js 物理世界 this.world = new CANNON.World(); this.world.gravity.set(0, -9.82, 0); this.world.broadphase = new CANNON.SAPBroadphase(this.world); this.world.defaultContactMaterial.friction = 0.3; this.world.defaultContactMaterial.restitution = 0.7; // 边界容器(3D盒体) this.bounds = { width: 20, height: 15, depth: 20 }; this.createBoundary(); // 对象存储 this.meshes = []; this.bodies = []; // 交互系统 this.setupInteraction(); // 动画循环 this.animate(); } // 创建边界墙 createBoundary() { const wallMat = new THREE.MeshStandardMaterial({ color: 0x888888, transparent: true, opacity: 0.3 }); const wallGeo = new THREE.BoxGeometry(1, 1, 1); // 六个面(底部、顶部、前后左右) const walls = [ { pos: [0, -this.bounds.height/2, 0], size: [this.bounds.width, 1, this.bounds.depth] }, { pos: [0, this.bounds.height/2, 0], size: [this.bounds.width, 1, this.bounds.depth] }, { pos: [0, 0, -this.bounds.depth/2], size: [this.bounds.width, this.bounds.height, 1] }, { pos: [0, 0, this.bounds.depth/2], size: [this.bounds.width, this.bounds.height, 1] }, { pos: [-this.bounds.width/2, 0, 0], size: [1, this.bounds.height, this.bounds.depth] }, { pos: [this.bounds.width/2, 0, 0], size: [1, this.bounds.height, this.bounds.depth] } ]; walls.forEach(w => { const mesh = new THREE.Mesh(wallGeo, wallMat); mesh.scale.set(...w.size); mesh.position.set(...w.pos); this.scene.add(mesh); // 物理墙(静态刚体) const body = new CANNON.Body({ mass: 0 }); body.addShape(new CANNON.Box(new CANNON.Vec3(w.size[0]/2, w.size[1]/2, w.size[2]/2))); body.position.set(...w.pos); this.world.addBody(body); }); } // 添加不同几何体 addObject(type, position) { let mesh, body, shape; const material = new THREE.MeshStandardMaterial({ color: Math.random() * 0xffffff, roughness: 0.4, metalness: 0.2 }); switch(type) { case 'sphere': const radius = 0.5 + Math.random() * 0.5; mesh = new THREE.Mesh(new THREE.SphereGeometry(radius, 16, 16), material); shape = new CANNON.Sphere(radius); break; case 'box': const size = 0.5 + Math.random() * 0.5; mesh = new THREE.Mesh(new THREE.BoxGeometry(size, size, size), material); shape = new CANNON.Box(new CANNON.Vec3(size/2, size/2, size/2)); break; case 'convex': // 凸包示例(八面体) const geo = new THREE.OctahedronGeometry(0.7); mesh = new THREE.Mesh(geo, material); const vertices = geo.attributes.position.array; const points = []; for (let i = 0; i < vertices.length; i += 3) { points.push(new CANNON.Vec3(vertices[i], vertices[i+1], vertices[i+2])); } shape = new CANNON.ConvexPolyhedron({ vertices: points }); break; } // 物理体配置 body = new CANNON.Body({ mass: 1, shape: shape, position: new CANNON.Vec3(position.x, position.y, position.z), linearDamping: 0.1, // 线性阻尼 angularDamping: 0.2, // 角阻尼 material: new CANNON.Material({ friction: 0.3, restitution: 0.7 }) }); this.world.addBody(body); this.scene.add(mesh); this.meshes.push(mesh); this.bodies.push(body); } // 交互系统:点击/触摸施加冲量 setupInteraction() { const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); const onPointerDown = (event) => { // 归一化设备坐标 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, this.camera); const intersects = raycaster.intersectObjects(this.meshes); if (intersects.length > 0) { const hit = intersects[0]; const meshIndex = this.meshes.indexOf(hit.object); const body = this.bodies[meshIndex]; // 计算冲量向量 const impulse = this.calculateImpulse(hit.point, body); body.applyImpulse(impulse.vector, impulse.point); } }; window.addEventListener('pointerdown', onPointerDown); } // 冲量向量计算(数学核心) calculateImpulse(hitPoint, body) { // 1. 从相机位置到点击点的方向向量 const cameraPos = this.camera.position; const direction = new THREE.Vector3() .subVectors(hitPoint, cameraPos) .normalize(); // 2. 冲量强度(可配置,此处为固定值) const impulseStrength = 15; // 3. 计算冲量向量(世界空间) const impulseVector = direction.multiplyScalar(impulseStrength); // 4. 转换为Cannon.js向量 const impulse = new CANNON.Vec3(impulseVector.x, impulseVector.y, impulseVector.z); // 5. 计算作用点(物体质心到点击点的偏移) const point = new CANNON.Vec3(hitPoint.x, hitPoint.y, hitPoint.z); return { vector: impulse, point: point }; } // 动画循环:同步物理与渲染 animate() { requestAnimationFrame(() => this.animate()); // 固定时间步长物理更新 this.world.step(1/60); // 同步刚体位置到网格 for (let i = 0; i < this.bodies.length; i++) { this.meshes[i].position.copy(this.bodies[i].position); this.meshes[i].quaternion.copy(this.bodies[i].quaternion); } this.renderer.render(this.scene, this.camera); } } // 初始化 const sandbox = new PhysicsSandbox(document.getElementById('container')); sandbox.addObject('sphere', { x: 0, y: 5, z: 0 }); sandbox.addObject('box', { x: 2, y: 5, z: 0 }); sandbox.addObject('convex', { x: -2, y: 5, z: 0 }); ``` ## 冲量向量计算的数学实现 ### 1. 方向向量推导 设相机位置为 \( C = (c_x, c_y, c_z) \),点击点(射线与物体交点)为 \( P = (p_x, p_y, p_z) \)。 方向向量: \[ \vec{d} = \frac{P - C}{\|P - C\|} \] ### 2. 冲量向量 冲量强度 \( I_0 \)(标量)乘以方向向量: \[ \vec{I} = I_0 \cdot \vec{d} \] ### 3. 物理应用 在Cannon.js中,`applyImpulse` 方法使用: \[ \Delta v = \frac{\vec{I}}{m} \] \[ \Delta \omega = J^{-1} (\vec{r} \times \vec{I}) \] 其中: - \( m \) 是物体质量 - \( J \) 是惯性张量 - \( \vec{r} = P - X \) 是从质心 \( X \) 到作用点 \( P \) 的偏移向量 ### 4. 能量损失模拟 - **摩擦**:接触面切向力,通过 `friction` 参数控制 - **恢复系数**:碰撞前后法向速度比,`restitution = 0.7` 表示70%速度保留 - **线性阻尼**:\( F_{damping} = -c \cdot v \),指数衰减速度 - **角阻尼**:类似线性阻尼,但作用于角速度 ### 5. 性能优化 - 使用 `SAPBroadphase` 宽阶段碰撞检测 - 固定时间步长 `1/60` 保证物理稳定性 - 直接复制位置和四元数,避免额外计算 此架构支持轻松扩展新几何体(只需在 `addObject` 中添加case),并保持物理与渲染的同步。

登录以查看完整提示词

继续使用:

登录即表示你同意我们的 使用条款 和 隐私政策

用法

此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。

为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。

参考资料

分类:coding| prompts.chat| three-js| cannon-js

讨论