html5缩放,HTML5版3D实验室系列【二】----摄像机、投影、3D旋转以及缩放(演示很多,请自备瓜子眼药水··)

 

【简述】

3D效果分两种,一种是伪3D,一种是3D.

伪3D:是人类按照自己的经验,在二维平面制造出3D的效果。

3D:是通过大量的计算将3D世界中所有点投影到二维平面中。

本系列的所有演示都是3D,非伪3D。本文将穿插图片、公式、代码、演示,让读者深刻理解3D的基本概念极其思想。
 

【对象及概念介绍】

对象一:摄像机。
大家都有一个基本常识,在不同的角度观看到的物体是不同的。摄像机对象有自己的空间的坐标(vidiconX,vidiconY,vidiconZ)。
对象二:显示屏
任何三维物体,都会以二维的形式投影在显示屏上,显示屏垂直于摄像机的观测方向,所以摄像机的空间坐标变化,会导致显示屏的坐标系的变换
对象三:被观察测物体
任何物体都是有无数个点构成,每个点有自己的空间坐标(x,y,z),显示屏介于摄像机和物体之间。
 
为了降低复杂度,本文将显示屏和被观测物体所处的坐标系公用一套(x,y),所有的旋转都是物体旋转,摄像机不动!

缩放原理:摄像机不动,被观察测物体不动,显示屏离摄像机越近,缩放比例越小,显示屏离摄像机越远,缩放比例越大。

【投影分析】

我们来看下面这张图:
3Dp1HTML5版3D实验室系列【二】----摄像机、投影、3D旋转以及缩放(演示很多,请自备瓜子眼药水··)html5缩放
 
因为,我们将显示屏和被观测物体共用一个坐标系,所以,我们可以计算出点(x1,y1,z1)投影到显示屏上的点的缩放比例为:

h / Math.abs(vidicon - z1)

所以投影后的坐标为:
x = x1 * h / Math.abs(vidicon - z);
y=  y1 * h / Math.abs(vidicon - z);
 
有了以上这些知识,我们可以轻松的在Canvas里画一个正方体(再次强调,是根据计算的结果画,非人类经验)。
Your browser does not support the canvas element.

 
【演示】
Your browser does not support the canvas element.
 
 
 
 
 
当然我们可以重构一下,将8个点都放到Array中。

 
现在,我们看到了正方体正常的显示在画布当中,那么我们现在来用演示证明一下缩放原理
缩放原理:摄像机不动,被观察测物体不动,显示屏离摄像机越近,缩放比例越小,显示屏离摄像机越远,缩放比例越大。
Your browser does not support the canvas element.


可以看到,我们定义了两个异步任务reduceDrawCubeAsync 和magnifyDrawCubeAsync ,把它们放到executeAsync 队列当中,
他们会从上倒下,依次执行。

【演示】
Your browser does not support the canvas element.
 
 
 
 
 

【3D旋转】

上面讲了摄像机,投影以及缩放的原理以及实现,下面看旋转。
首先,在三维坐标系当中,任何角度的任何旋转可以拆分成三类:

a.绕X轴方向的旋转,此时,y和z发生变化,x不变。

b.绕Y轴方向的旋转,此时,x和z发生变化,y不变。

a.绕Z轴方向的旋转,此时,x和y发生变化,x不变。

那么x和z到底变化多少呢?我们可以看一下切面图,然后计算出坐标的变化!
3dp23Dp1HTML5版3D实验室系列【二】----摄像机、投影、3D旋转以及缩放(演示很多,请自备瓜子眼药水··)html5缩放
 
或者我们也可以直接翻到大学教材书本第七章【三维旋转矩阵】:
3Dp33dp23Dp1HTML5版3D实验室系列【二】----摄像机、投影、3D旋转以及缩放(演示很多,请自备瓜子眼药水··)html5缩放
 
我们拿绕y轴旋转为例子,如:
//旋转 function rotate(angle) { for (var i = 0; i < Points.length; i++) { var tempX = Points[i].x; Points[i].x = Points[i].x * Math.cos(angle) - Points[i].z * Math.sin(angle); Points[i].z = Points[i].z * Math.cos(angle) + tempX * Math.sin(angle); } }
 
我们要记住,旋转之后的坐标是在坐标系当中的坐标,我们还要讲其投影到显示屏,所以我们应当先旋转---再投影,顺序不能弄反。
定义一个角度转弧度:
function degToRad(a) { return (a / (360 / (2 * Math.PI))); }
立方体颜色变化:
function randomColor() { var arrHex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]; var strHex = "#"; var index; for (var i = 0; i < 6; i++) { index = Math.round(Math.random() * 15); strHex += arrHex[index]; } return strHex; }
旋转控制核心,我们依然用Jscex:
var currentAngle = 0; var drawCube2 = function () { cxt2.clearRect(0, 0, 1200, 1200); init(); rotate(degToRad(currentAngle)) changedistance2(); cxt2.strokeStyle = randomColor(); cxt2.beginPath(); cxt2.moveTo(startX + Points[0].x, startY - Points[0].y); cxt2.lineTo(startX + Points[1].x, startY - Points[1].y); cxt2.lineTo(startX + Points[2].x, startY - Points[2].y); cxt2.lineTo(startX + Points[3].x, startY - Points[3].y); cxt2.lineTo(startX + Points[0].x, startY - Points[0].y); cxt2.moveTo(startX + Points[4].x, startY - Points[4].y); cxt2.lineTo(startX + Points[5].x, startY - Points[5].y); cxt2.lineTo(startX + Points[6].x, startY - Points[6].y); cxt2.lineTo(startX + Points[7].x, startY - Points[7].y); cxt2.lineTo(startX + Points[4].x, startY - Points[4].y); cxt2.moveTo(startX + Points[1].x, startY - Points[1].y); cxt2.lineTo(startX + Points[5].x, startY - Points[5].y); cxt2.moveTo(startX + Points[0].x, startY - Points[0].y); cxt2.lineTo(startX + Points[4].x, startY - Points[4].y); cxt2.moveTo(startX + Points[2].x, startY - Points[2].y); cxt2.lineTo(startX + Points[6].x, startY - Points[6].y); cxt2.moveTo(startX + Points[3].x, startY - Points[3].y); cxt2.lineTo(startX + Points[7].x, startY - Points[7].y); cxt2.stroke(); } drawCube2() var rotateAsync = eval(Jscex.compile("async", function () { while (true) { currentAngle += 5; drawCube2(); $await(Jscex.Async.sleep(100)); } }));
【演示】
Your browser does not support the canvas element.








 

因为任何角度的任何旋转可以拆分成三类,我们可以轻松添加一个绕X轴方向上的旋转:
//旋转 function rotate(angle) { for (var i = 0; i < Points2.length; i++) { var tempX = Points2[i].x; var tempZ = Points2[i].z; Points2[i].x = Points2[i].x * Math.cos(angle) - Points2[i].z * Math.sin(angle); Points2[i].z = Points2[i].z * Math.cos(angle) + tempX * Math.sin(angle); } for (var i = 0; i < Points2.length; i++) { var tempY = Points2[i].y; Points2[i].y = Points2[i].y * Math.cos(angle) - Points2[i].z * Math.sin(angle); Points2[i].z = tempY * Math.sin(angle) + Points2[i].z * Math.cos(angle); } }
 
 
【演示】
Your browser does not support the canvas element.













 

【总结】

本文介绍了摄像机、投影、旋转、缩放等概念,并加以实现。本文为了降低复杂度,摄像机的位置不变,在真实的场景当中,比如一些3D游戏,如魔兽世界,摄像机和物体是都可以改变位置,
那么,我们就应该建立两套坐标体系去适应复杂的场景。3D实验,还有很长的路要走,虽然是别人已经走过的路····
 
续篇会谈及在此基础上加入其他3D物理实验。希望各位支持,并给本人更多意见。
 

下篇预告:【3D碰撞】

 
【javascript异步编程系列】javascript异步编程系列目录
Tags: 

延伸阅读

最新评论

发表评论