import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import gsap from 'gsap'
import * as dat from 'dat.gui'
import * as CANNON from 'cannon-es' const scene = new THREE. Scene ( ) const camera = new THREE. PerspectiveCamera ( 75 , window. innerWidth / window. innerHeight, 0.1 , 300 )
camera. position. set ( 0 , 0 , 18 )
scene. add ( camera) const cubeArr = [ ]
const cubeWorldMaterial = new CANNON. Material ( 'cube' )
const hitSound = new Audio ( '../public/assets/metalHit.mp3' ) const createCube = ( ) => { const cubeGeometry = new THREE. BoxGeometry ( 1 , 1 , 1 ) const cubeMaterial = new THREE. MeshStandardMaterial ( ) const cube = new THREE. Mesh ( cubeGeometry, cubeMaterial) cube. castShadow = true scene. add ( cube) const cubeShape = new CANNON. Box ( new CANNON. Vec3 ( 0.5 , 0.5 , 0.5 ) ) const cubeBody = new CANNON. Body ( { shape : cubeShape, position : new CANNON. Vec3 ( 0 , 0 , 0 ) , mass : 1 , material : cubeWorldMaterial } ) cubeBody. applyLocalForce ( new CANNON. Vec3 ( 300 , 0 , 0 ) , new CANNON. Vec3 ( 0 , 0 , 0 ) ) world. addBody ( cubeBody) const hitEvent = e => { const impactStrength = e. contact. getImpactVelocityAlongNormal ( ) if ( impactStrength > 2 ) { hitSound. currentTime = 0 hitSound. volume = impactStrength / 12 hitSound. play ( ) } } cubeBody. addEventListener ( 'collide' , hitEvent) cubeArr. push ( { mesh : cube, body : cubeBody} )
} window. addEventListener ( 'click' , createCube)
const floor = new THREE. Mesh ( new THREE. PlaneGeometry ( 20 , 20 ) , new THREE. MeshStandardMaterial ( ) )
floor. position. set ( 0 , - 5 , 0 )
floor. rotation. x = - Math. PI / 2
floor. receiveShadow = true
scene. add ( floor) ` 创建物理世界 `
const world = new CANNON. World ( )
` 设置物理世界的重力,重力被设置为仅在Y轴(竖直向下)上有作用,大小为-9.8(模拟地球表面的重力加速度) `
world. gravity. set ( 0 , - 9.8 , 0 )
const floorShape = new CANNON. Plane ( )
const floorBody = new CANNON. Body ( )
const floorMaterial = new CANNON. Material ( 'floor' )
floorBody. material = floorMaterial` 当质量为0时,可以使物体保持不动这里, ` floorBody` 作为地面,不能动,所以,把它的质量设置为0,就行了 `
floorBody. mass = 0
floorBody. addShape ( floorShape)
floorBody. position. set ( 0 , - 5 , 0 )
floorBody. quaternion. setFromAxisAngle ( new CANNON. Vec3 ( 1 , 0 , 0 ) , - Math. PI / 2 )
world. addBody ( floorBody) ` 设置,2种材质的碰撞参数 `
const defaultContactMaterial = new CANNON. ContactMaterial ( cubeWorldMaterial, floorMaterial, { friction : 0.1 , ` 摩擦力 ` restitution : 0.7 ` 弹性 `
} ) ` 将,材料的关联设置,添加到物理世界 `
world. addContactMaterial ( defaultContactMaterial) ` 设置,物理世界,碰撞的默认材质,,如果物理世界的物体没有设置这个,就用这个 `
world. defaultContactMaterial = defaultContactMaterial
const renderer = new THREE. WebGLRenderer ( { alpha : true } )
renderer. setSize ( window. innerWidth, window. innerHeight)
renderer. shadowMap. enabled = true
document. body. appendChild ( renderer. domElement)
const ambientLight = new THREE. AmbientLight ( 0xffffff , 0.5 )
scene. add ( ambientLight)
const directionalLight = new THREE. DirectionalLight ( 0xffffff , 0.5 )
directionalLight. castShadow = true
directionalLight. position. set ( 0 , 8 , 0 )
scene. add ( directionalLight)
const directionalLightHelp = new THREE. DirectionalLightHelper ( directionalLight)
scene. add ( directionalLightHelp)
const controls = new OrbitControls ( camera, renderer. domElement)
controls. enableDamping = true
const axesHelper = new THREE. AxesHelper ( 5 )
scene. add ( axesHelper) const clock = new THREE. Clock ( ) const render = ( ) => { let deltaTime = clock. getDelta ( ) world. step ( 1 / 120 , deltaTime) cubeArr. forEach ( item => { item. mesh. position. copy ( item. body. position) item. mesh. quaternion. copy ( item. body. quaternion) } ) renderer. render ( scene, camera) requestAnimationFrame ( render)
}
render ( ) window. addEventListener ( 'resize' , ( ) => { camera. aspect = window. innerWidth / window. innerHeightcamera. updateProjectionMatrix ( ) renderer. setSize ( window. innerWidth, window. innerHeight) renderer. setPixelRatio ( window. devicePixelRatio)
} )