更新于 

How to Create Bouncing Ball on MouseClick?鼠标点击创建弹跳小球

要实现鼠标点击掉落小弹球,
实际上就是鼠标点击创建小球cannon物理引擎的结合,
需要注意的是,每一个新建的小球都需要绑定一个CANNON.Body,
需要在创建的同时留好数据的访问入口,

鼠标时间控制小球创建
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
const mouse = new THREE.Vector2()
const planeNormal = new THREE.Vector3()
const plane = new THREE.Plane()
const raycaster = new THREE.Raycaster()
const interSectionPointer = new THREE.Vector3()
const BallList = []

window.onmousemove = function(e){
mouse.x = e.offsetX/window.innerWidth*2 - 1
mouse.y = 1 - e.offsetY/window.innerHeight*2
planeNormal.copy(camera.position)
plane.setFromNormalAndCoplanarPoint(planeNormal, scene.position)
raycaster.setFromCamera(mouse,camera)
raycaster.ray.intersectPlane(plane, interSectionPointer)
}
window.onclick = function(e){
const sphereGeo = new THREE.SphereGeometry(0.2)
const sphereMat = new THREE.MeshStandardMaterial({
color:0xffffff*Math.random(),
metalness:0,
roughness:0
})
const sphereMesh = new THREE.Mesh(sphereGeo,sphereMat)
sphereMesh.position.copy(interSectionPointer)
scene.add(sphereMesh)
sphereMesh.castShadow = true
const ballBody = new CANNON.Body({
shape:new CANNON.Sphere(0.2),
mass:1,
position:interSectionPointer,
material:ballPhyMat
})
world.addBody(ballBody)
BallList.push([sphereMesh,ballBody])
}
材质添加
1
2
3
4
5
6
7
8
9
10
11
12
13
const world = new CANNON.World({
gravity:new CANNON.Vec3(0,-9.89,0)
})
const planePhyMat = new CANNON.Material()
const ballPhyMat = new CANNON.Material()
const planeBallContactMat = new CANNON.ContactMaterial(
planePhyMat,
ballPhyMat,
{
restitution:0.9
}
)
world.addContactMaterial(planeBallContactMat)
动画控制
1
2
3
4
5
6
7
8
9
10
11
12
13
const timeStep = 1/60
function animate() {
world.step(timeStep)
groundMesh.position.copy(groundBody.position)
groundMesh.quaternion.copy(groundBody.quaternion)
BallList.forEach(([mesh,body])=>{
mesh.position.copy(body.position)
mesh.quaternion.copy(body.quaternion)
})
renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);
阴影锯齿

需要注意的是:
如果不做任何处理,此处的球体阴影会因为锯齿变得参差不齐:

渲染器创建时有抗锯齿选项antialias
设置为true的话抗锯齿效果会好一些:

1
const renderer = new THREE.WebGLRenderer({antialias: true});

看视频作者的操作,是将光源的shadow.mapSize属性进行放大:

1
2
pointLight.shadow.mapSize.width = 1024
pointLight.shadow.mapSize.height = 1024

效果确实好了很多。

真的有这么Q弹吗?
真的有这么Q弹吗?