基于对 3D 旋转矩阵的一些研究,我制作了这个 jsfiddle,它本身并不能很好地工作,因为你不能在外部视频或图像上使用 'ctx.getImageData()' (但如果你想尝试本地托管的视频源上的相同代码,它应该可以正常工作)。
大多数 3D 魔法发生在两个矩阵乘法中。对于图像的每个点,xyz 坐标乘以函数“rotatePoint”中的旋转矩阵,该函数将点“xyz”从原点“p”沿单位向量“u”的方向转换为旋转轴通过“theta”弧度。
function rotatePoint(xyz,p,u,rho,phi){
return new Vector(
((p.x*(u.y*u.y+u.z*u.z)-u.x*(p.y*u.y+p.z*u.z-u.x*xyz.x-u.y*xyz.y-u.z*xyz.z))*(1-rho)+xyz.x*rho+(-p.z*u.y+p.y*u.z-u.z*xyz.y+u.y*xyz.z)*phi)|0,
((p.y*(u.x*u.x+u.z*u.z)-u.y*(p.x*u.x+p.z*u.z-u.x*xyz.x-u.y*xyz.y-u.z*xyz.z))*(1-rho)+xyz.y*rho+( p.z*u.x-p.x*u.z+u.z*xyz.x-u.x*xyz.z)*phi)|0,
((p.z*(u.x*u.x+u.y*u.y)-u.z*(p.x*u.x+p.y*u.y-u.x*xyz.x-u.y*xyz.y-u.z*xyz.z))*(1-rho)+xyz.z*rho+(-p.y*u.x+p.x*u.y-u.y*xyz.x+u.x*xyz.y)*phi)|0)
}
其中“rho”是 sin(theta),“phi”是 cos(theta),theta 是旋转角度。
最后点乘以透视矩阵,在下面的函数中,将点从世界坐标转换为屏幕坐标。
function perspective(xyz){
return {
x : ((this.camera.e.z*(xyz.x-this.camera.e.x))/(this.camera.e.z+xyz.z)+this.camera.e.x)|0,
y : ((this.camera.e.z*(xyz.y-this.camera.e.y))/(this.camera.e.z+xyz.z)+this.camera.e.y)|0
}
}
现在,所有这些在大多数情况下都可以正常工作。但无论出于何种原因,3D 旋转都会导致图像沿旋转轴无限重复。这是一个示例屏幕截图:
有人知道为什么会这样吗?