1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
| <template> <div></div> </template> <script setup> import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import * as CANNON from "cannon-es"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; // 初始化物理世界 const world = new CANNON.World(); // 设置重力 world.gravity.set(0, -9.82, 0); // 初始化3D场景 const scene = new THREE.Scene(); // 初始化相机 const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.set(0, 0, 10); camera.lookAt(0, 0, 0); // 初始化渲染器 const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 初始化控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; let phyMeshes = []; let meshes = []; // 设置碰撞组,数值要用2的幂 const GROUP1 = 1; const GROUP2 = 2; const GROUP3 = 4; const GROUP4 = 8; // 设置立方体材质 const boxMaterialCon = new CANNON.Material("boxMaterial"); boxMaterialCon.friction = 0.2; boxMaterialCon.restitution = 0.1; // 创建一个平面 const planeShape1 = new CANNON.Plane(); // 创建一个刚体 const planeBody1 = new CANNON.Body({ mass: 0, shape: planeShape1, position: new CANNON.Vec3(0, 0, 0), type: CANNON.Body.STATIC, material: boxMaterialCon, collisionFilterGroup: GROUP1, collisionFilterMask: GROUP1 | GROUP2 | GROUP3, }); planeBody1.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2); // 将刚体添加到物理世界 world.addBody(planeBody1); // 创建一个物理世界的平面 // const planeShape = new CANNON.Plane(); const planeShape = new CANNON.Box(new CANNON.Vec3(5, 0.1, 5)); // 创建一个刚体 const planeBody = new CANNON.Body({ // mass: 0, shape: planeShape, position: new CANNON.Vec3(0, -0.1, 0), type: CANNON.Body.STATIC, material: boxMaterialCon, collisionFilterGroup: GROUP1, collisionFilterMask: GROUP1 | GROUP2 | GROUP3, }); // planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), 0.1); // 将刚体添加到物理世界 world.addBody(planeBody); // 创建一个平面几何体 // const planeGeometry = new THREE.PlaneGeometry(10, 10); const planeGeometry = new THREE.BoxGeometry(10, 0.2, 10); // 创建一个平面材质 const planeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 }); // 创建一个平面网格 const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); // x轴旋转90度 // planeMesh.rotation.x = 0.1; // 将网格添加到3D场景 scene.add(planeMesh); // 创建由2个球加1个圆柱体组成的胶囊体 // 创建body const capsuleBody = new CANNON.Body({ mass: 1, position: new CANNON.Vec3(0, 5, 0), material: boxMaterialCon, collisionFilterGroup: GROUP2, collisionFilterMask: GROUP1 | GROUP2 | GROUP3, }); // 创建一个球体几何体 const sphereShape = new CANNON.Sphere(0.5); // 创建一个圆柱体几何体 const cylinderShape = new CANNON.Cylinder(0.5, 0.5, 1.5, 20); // 将球体和圆柱体添加到body capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, 0.75, 0)); capsuleBody.addShape(cylinderShape, new CANNON.Vec3(0, 0, 0)); capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, -0.75, 0)); capsuleBody.velocity.set(1, 0, 0); // 将body添加到物理世界 world.addBody(capsuleBody); phyMeshes.push(capsuleBody); // 创建胶囊体网格 const capsuleGeometry = new THREE.CylinderGeometry(0.5, 0.5, 1.5, 20); const capsuleMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const capsuleMesh = new THREE.Mesh(capsuleGeometry, capsuleMaterial); capsuleMesh.position.copy(capsuleBody.position); capsuleMesh.quaternion.copy(capsuleBody.quaternion); scene.add(capsuleMesh); meshes.push(capsuleMesh); // 创建一个球体 const sphereGeometry = new THREE.SphereGeometry(0.5, 20, 20); const sphereMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff }); const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial); sphereMesh.position.set(0, 0.75, 0); capsuleMesh.add(sphereMesh); const sphereMesh2 = new THREE.Mesh(sphereGeometry, sphereMaterial); sphereMesh2.position.set(0, -0.75, 0); capsuleMesh.add(sphereMesh2); // 加载模型 const loader = new GLTFLoader(); loader.load("./model/lion.gltf", (gltf) => { // console.log(gltf); let lion = gltf.scene.children[0]; console.log(lion); lion.material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); scene.add(lion); meshes.push(lion); // 设置trimeshbody const trimeshShape = new CANNON.Trimesh( lion.geometry.attributes.position.array, lion.geometry.index.array ); let trimeshBody = new CANNON.Body({ mass: 1, position: new CANNON.Vec3(0, 2, 0), material: boxMaterialCon, collisionFilterGroup: GROUP2, collisionFilterMask: GROUP1 | GROUP2 | GROUP3, // shape: trimeshShape, }); trimeshBody.addShape(trimeshShape); // 添加到物理世界 world.addBody(trimeshBody); phyMeshes.push(trimeshBody); }); // 渲染 let clock = new THREE.Clock(); function animate() { let delta = clock.getDelta(); world.step(1 / 60, delta); for (let i = 0; i < phyMeshes.length; i++) { meshes[i].position.copy(phyMeshes[i].position); meshes[i].quaternion.copy(phyMeshes[i].quaternion); } controls.update(); renderer.render(scene, camera); requestAnimationFrame(animate); } animate(); </script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } canvas { width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; } </style>
|