大家好,本文實現了相機碰撞檢測,使相機不穿牆壁、物體,並給出了思路和代碼,感謝大家~
關鍵詞:數字孿生、three.js、Web3D、WebGL、相機碰撞、遊戲相機
我正在承接Web3D數字孿生項目,具體介紹可看承接各種Web3D業務
實現前:
移動第三人稱相機時,相機可能會穿入到物體、牆壁中,影響視野
現在進行下面的改進:
- 只要相機和人物之間有物體,就平滑拉進
- 如果沒有物體,則恢復默認的距離
- 如果在拉進時,人物往相機反方向移動,則可以移動到默認的距離而保持相機不動;再遠相機就會跟隨了
實現後效果如下:
實現原理
大概的實現原理如下:
從人物往相機發送射線,與場景進行相交檢測;
如果最近相交點小於默認距離,則說明相機被遮擋,將相機沿着相機到人物的方向平滑移動
代碼:
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(...))