二维的坐标旋转绕Z轴旋转,物体只有x、y坐标会变化(风车旋转),三维中还可以绕x和y轴旋转。
绕x轴旋转:只有y、z坐标会变化(轮胎滚动)。
绕y轴旋转,只有x,z坐标会变化(唱片机)。
二维:
x1 = x * Math.cos(angle) - y * Math.sin(angle)
y1 = y * Math.cos(angle) + y * Math.sin(angle)
三维绕x轴:
y1 = y * Math.cos(angleX) - z * Math.sin(angleX)
z1 = z * Math.cos(angleX) + y * Math.sin(angleX)
三维绕y轴:
x1 = x * Math.cos(angleY) - z * Math.sin(angleY)
z1 = z * Math.cos(angleY) + x * Math.sin(angleY)
import { parseColor, captureMouse } from '../common/utils.js'
let canvas = document.getElementById('canvas')
let width = canvas.width = 500
let height = canvas.height = 500
let ctx = canvas.getContext('2d')
let balls = createBall(50)
let fl = 250
let vpX = width / 2
let vpY = height / 2
let mouse = captureMouse(canvas)
let angleY
let angleX
function createBall (nums) {
let balls = []
while (nums--) {
balls.push(new Ball3d({
radius: Math.random() * 10 + 10,
lineWidth: 0,
color: parseColor(Math.random() * 0xffffff),
xpos: Math.random() * width - width / 2,
ypos: Math.random() * height - height / 2,
zpos: Math.random() * 400 - 200
}))
}
return balls
}
// 绕X轴旋转小球
function rotateX (ball, angle) {
let cos = Math.cos(angle)
let sin = Math.sin(angle)
let y1 = ball.ypos * cos - ball.zpos * sin
let z1 = ball.zpos * cos + ball.ypos * sin
ball.ypos = y1
ball.zpos = z1
}
// 绕Y轴旋转小球
function rotateY (ball, angle) {
let sin = Math.sin(angle)
let cos = Math.cos(angle)
let x1 = ball.xpos * cos - ball.zpos * sin
let z1 = ball.zpos * cos + ball.xpos * sin
ball.xpos = x1
ball.zpos = z1
}
// 透视
function setPerspective (ball) {
if (ball.zpos > -fl) {
let scale = fl / (fl + ball.zpos)
ball.scaleX = ball.scaleY = scale
ball.x = vpX + ball.xpos * scale
ball.y = vpY + ball.ypos * scale
ball.visible = true
} else {
ball.visible = false
}
}
function move (ball) {
rotateX(ball, angleX)
rotateY(ball, angleY)
setPerspective(ball)
}
// 排序,让zpos值大的球在前面
function zsort (a, b) {
return b.zpos - a.zpos
}
function draw (ball) {
if (ball.visible) {
ball.draw(ctx)
}
}
;(function drawFrame () {
window.requestAnimationFrame(drawFrame)
ctx.clearRect(0, 0, width, height)
// 根据鼠标坐标计算出角度
angleY = (mouse.x - vpX) * 0.0005
angleX = (mouse.y - vpY) * 0.0005
balls.sort(zsort)
balls.forEach(move)
balls.forEach(draw)
})();