大家好,本文实现了相机碰撞检测,使相机不穿墙壁、物体,并给出了思路和代码,感谢大家~
关键词:数字孪生、three.js、Web3D、WebGL、相机碰撞、游戏相机
我正在承接Web3D数字孪生项目,具体介绍可看承接各种Web3D业务
目录
实现前:
移动第三人称相机时,相机可能会穿入到物体、墙壁中,影响视野
现在进行下面的改进:
- 只要相机和人物之间有物体,就平滑拉进
- 如果没有物体,则恢复默认的距离
- 如果在拉进时,人物往相机反方向移动,则可以移动到默认的距离而保持相机不动;再远相机就会跟随了
实现后效果如下:
实现原理
大概的实现原理如下:
从人物往相机发送射线,与场景进行相交检测;
如果最近相交点小于默认距离,则说明相机被遮挡,将相机沿着相机到人物的方向平滑移动
代码:
ts
import { Raycaster, Scene, Vector3 } from "three"
type cameraVelocity = Vector3
export let handleCameraCollision = (raycaster: Raycaster, scene: Scene, defaultDistance: number, playerWorldPosition: Vector3, cameraCurrentWorldPosition: Vector3): cameraVelocity => {
let playerToCameraDirection = cameraCurrentWorldPosition.clone().sub(playerWorldPosition).normalize()
raycaster.set(playerWorldPosition, playerToCameraDirection)
let intersects = raycaster.intersectObject(scene, true)
let cameraToPlayerDistance = cameraCurrentWorldPosition.clone().distanceTo(playerWorldPosition)
//实现"如果没有物体,则恢复默认的距离"和"如果在拉进时,人物往相机反方向移动,则可以移动到默认的距离而保持相机不动;再远相机就会跟随了"
if (cameraToPlayerDistance < defaultDistance
&& (
intersects.length == 0
|| intersects[0].distance > cameraToPlayerDistance
)
) {
let speed
if (intersects.length == 0 || intersects[0].distance > defaultDistance) {
speed = defaultDistance / cameraToPlayerDistance
}
else {
speed = intersects[0].distance / cameraToPlayerDistance
if (intersects[0].distance + speed > cameraToPlayerDistance) {
speed = 0
}
}
return playerToCameraDirection.clone().multiplyScalar(speed)
}
if (intersects.length == 0 || intersects[0].distance >= cameraToPlayerDistance) {
return new Vector3(0, 0, 0)
}
let cameraToPlayerDirection = playerWorldPosition.clone().sub(cameraCurrentWorldPosition).normalize()
let speed = cameraToPlayerDistance / intersects[0].distance
return cameraToPlayerDirection.multiplyScalar(speed)
}
...
camera.position.add(handleCameraCollision(...))