本文重点为:
- 摄像机旋转时X轴Z轴坐标与鼠标X坐标的关系
- 摄像机的旋转角度怎么根据鼠标X坐标计算,
本案例设定为: 左右旋转到画布边界时,看到物体背面即可
效果:
画布的大小单独设为一个对象
// Sizes
const sizes = {
width: 800,
height: 600
}
网格对象是一个0.5 X 0.5 X 0.5的正方体,每个面颜色不一致,代码:
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(0.5, 0.5, 0.5,),
[
new THREE.MeshBasicMaterial({ color: 0xff0000 }),
new THREE.MeshBasicMaterial({ color: 0x00ff00 }),
new THREE.MeshBasicMaterial({ color: 0x0000ff }),
new THREE.MeshBasicMaterial({ color: 0xffff00 }),
new THREE.MeshBasicMaterial({ color: 0x00ffff }),
new THREE.MeshBasicMaterial({ color: 0xff00ff }),
]
)
透视摄像机代码:
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.01, 1000)
// 摄像头的z轴位置默认先放在1
camera.position.z = 1
camera.lookAt(mesh.position)
鼠标移动时,在画布中的位置, 用cursor变量定义:
/**
* cursor
*/
const cursor = {
x: 0,
y: 0
}
// 鼠标位置的计算不做过多解释,自行百度
window.addEventListener('mousemove', (event) => {
cursor.x = event.clientX / sizes.width - 0.5
cursor.y = - (event.clientY / sizes.height - 0.5)
})
在window.requestAnimationFrame()中设置照相机位置,画布重新渲染
const tick = () => {
// 重点解释这两句
camera.position.x = Math.sin(cursor.x * Math.PI * 2 )
camera.position.z = Math.cos(cursor.x * Math.PI * 2 )
camera.lookAt(mesh.position)
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
下面是对于计算摄像头位置以及如何根据鼠标位置计算出旋转角度的理解:
前提已知
1、Π = 180°
2、摄像机左右查看物体,且要看到背面的话,需要同时变化X轴以及Z轴坐标
理解1: 对照鼠标具体的5个坐标, 得到摄像机的位置与旋转角度
鼠标位置变化时,摄像机旋转位置如下:
由上面图片可以得出关于旋转角度、鼠标X轴位置、相机X轴位置、相机Z轴位置的对应关系表:
旋转角度 | 鼠标X位置 | 相机 x位置 | 相机 z位置 |
---|---|---|---|
0° | 0 | 0 | 1 |
90° | 0.25 | 1 | 0 |
180° | 0.5 | 0 | -1 |
-90° | -0.25 | -1 | 0 |
-180° | -0.5 | 0 | -1 |
可以猜测以下结论:
- 相机X位置 = sin(旋转角度)
- 相机Z位置 = cos(旋转角度)
理解2: 根据相机距中心的位置为1、已知旋转角度a, 计算出相机x坐标 与 相机z的坐标,如下图:
由上图, 可以看出:
x = sin(a) * 1
z = cos(a) * 1
最终确定以下结论:
- 相机X位置 = sin(旋转角度) * 摄像机距离立方体中心点位置
- 相机Z位置 = cos(旋转角度) * 摄像机距离立方体中心点位置
理解3: 鼠标位置与旋转角度的关系
根据理解1中鼠标X轴移动位置与角度的变化:
鼠标X位置 | 旋转角度a |
---|---|
0 | 0° |
0.25 | 90° |
0.5 | 180° |
-0.25 | -90° |
-0.5 | -180° |
可以得出结论:
旋转角度 = 360° * 鼠标X坐标
最终可以正式解释,为什么摄像机坐标是由那两行代码得出
最终代码如下:
import * as THREE from 'three'
/**
* cursor
*/
const cursor = {
x: 0,
y: 0
}
window.addEventListener('mousemove', (event) => {
cursor.x = event.clientX / sizes.width - 0.5
cursor.y = - (event.clientY / sizes.height - 0.5)
})
/**
* Base
*/
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Sizes
const sizes = {
width: 800,
height: 600
}
// Scene
const scene = new THREE.Scene()
// Object
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(0.5, 0.5, 0.5,),
[
new THREE.MeshBasicMaterial({ color: 0xff0000 }),
new THREE.MeshBasicMaterial({ color: 0x00ff00 }),
new THREE.MeshBasicMaterial({ color: 0x0000ff }),
new THREE.MeshBasicMaterial({ color: 0xffff00 }),
new THREE.MeshBasicMaterial({ color: 0x00ffff }),
new THREE.MeshBasicMaterial({ color: 0xff00ff }),
]
)
scene.add(mesh)
const axesHelper = new THREE.AxesHelper()
scene.add(axesHelper)
// Camera
// 角度 宽高比 near fear
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.01, 1000)
camera.position.z = 1
camera.lookAt(mesh.position)
scene.add(camera)
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
const tick = () => {
camera.position.x = Math.sin(cursor.x * Math.PI * 2 )
camera.position.z = Math.cos(cursor.x * Math.PI * 2 )
camera.lookAt(mesh.position)
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()