      1 /**
      2  * Hilo
      3  * Copyright 2015 alibaba.com
      4  * Licensed under the MIT License
      5  */
      6
      7 /**
      8  * @class Camera3d 伪3D虚拟摄像机。
      9  * @module hilo/game/Camera3d
     10  * @requires hilo/core/Class
     11  * @requires hilo/util/util
     12  * @property {Number} fv 镜头视点距离（屏幕视点相对眼睛距离，绝对了坐标缩放比例）。
     13  * @property {Number} fx 镜头视点X（屏幕视点相对屏幕左上角X距离）。
     14  * @property {Number} fy 镜头视点Y（屏幕视点相对屏幕左上角Y距离）。
     15  * @property {Object} stage 3D对象所在容器，可以是stage或container，结合ticker时是必须参数，用来Z深度排序。
     16  * @property {Number} x 镜头三维坐标x。
     17  * @property {Number} y 镜头三维坐标y。
     18  * @property {Number} z 镜头三维坐标z。
     19  * @property {Number} rotationX X轴旋转角度。
     20  * @property {Number} rotationY Y轴旋转角度。
     21  * @property {Number} rotationZ Z轴旋转角度。
     22  */
     23 var Camera3d = (function(){
     24
     25 	var degtorad = Math.PI / 180;
     26
     27 	//Rotate the axis.
     28 	function rotateX(x, y, z, ca, sa) {//rotate x
     29 		return {
     30 			x: x,
     31 			y: y * ca - z * sa,
     32 			z: y * sa + z * ca
     33 		};
     34 	}
     35 	function rotateY(x, y, z, ca, sa) {//rotate y
     36 		return {
     37 			x: x * ca - z * sa,
     38 			y: y,
     39 			z: x * sa + z * ca
     40 		};
     41 	}
     42 	function rotateZ(x, y, z, ca, sa) {//rotate z
     43 		return {
     44 			x: x * ca - y * sa,
     45 			y: x * sa + y * ca,
     46 			z: z
     47 		};
     48 	}
     49
     50 	var Camera3d = Class.create(/** @lends Camera3d.prototype */{
     51
     52 		constructor: function(properties){
     53 			properties.x = properties.x || 0;
     54 			properties.y = properties.y || 0;
     55 			properties.z = properties.z || 0;
     56 			properties.rotationX = properties.rotationX || 0;
     57 			properties.rotationY = properties.rotationY || 0;
     58 			properties.rotationZ = properties.rotationZ || 0;
     59
     60         	util.copy(this, properties);
     61 		},
     62
     63 	    /**
     64          * 仿射矩阵位移变换，不同于直接修改Camera3d.x/y/z. 是在Camera3d依次做坐标位移 - 旋转变换 后，再加上一个位移变换。主要功能可以做Zoomin/out 功能
     65 	     * @param {Number} x x坐标
     66 	     * @param {Number} y y坐标
     67 	     * @param {Number} z z坐标
     68 	     */
     69 		translate : function(x,y,z){
     70 			this.tx = x;
     71 			this.ty = y;
     72 			this.tz = z;
     73 		},
     74
     75 	    /**
     76          * 旋转X轴方向角度，相当于欧拉角系统的 beta。
     77 	     * @param {Number} angle 旋转角度。
     78 	     */
     79 		rotateX : function(angle){
     80 			this.rotationX = angle;
     81 		},
     82
     83 	    /**
     84          * 旋转Y轴方向角度，相当于欧拉角系统的 gamma。
     85 	     * @param {Number} angle 旋转角度。
     86 	     */
     87 		rotateY : function(angle){
     88 			this.rotationY = angle;
     89 		},
     90
     91 	    /**
     92          * 旋转Z轴方向角度，相当于欧拉角系统的 alpha。
     93 	     * @param {Number} angle 旋转角度。
     94 	     */
     95 		rotateZ : function(angle){
     96 			this.rotationZ = angle;
     97 		},
     98
     99 	    /**
    100          * 将三维坐标转换投影为二维坐标。
    101 	     * @param {object} vector3D 三维坐标对象，必须含有x, y, z属性。
    102 	     * @param {View} view Hilo.View对象，用于自动转换坐标。
    103          * @returns {Object} 二维坐标对象，包括缩放和z属性，例子:{x:x, y:y, z:z, scale}
    104 	     */
    105 		project : function(vector3D, view){
    106
    107 			var rx = this.rotationX * degtorad,
    108 				ry = this.rotationY * degtorad,
    109 				rz = this.rotationZ * degtorad,
    110
    111 				cosX = Math.cos(rx), sinX = Math.sin(rx),
    112 				cosY = Math.cos(ry), sinY = Math.sin(ry),
    113 				cosZ = Math.cos(rz), sinZ = Math.sin(rz),
    114
    115 				// 旋转变换前的 仿射矩阵位移，
    116 				dx = vector3D.x - this.x,
    117 				dy = vector3D.y - this.y,
    118 				dz = vector3D.z - this.z;
    119
    120 			// 旋转矩阵变换
    121 			var vector = rotateZ(dx, dy, dz, cosZ, sinZ);
    122 			vector = rotateY(vector.x, vector.y, vector.z, cosY, sinY);
    123 			vector = rotateX(vector.x, vector.y, vector.z, cosX, sinX);
    124
    125 			// 最后的仿射矩阵变换
    126 			if(this.tx) vector.x -= this.tx;
    127 			if(this.ty) vector.y -= this.ty;
    128 			if(this.tz) vector.z -= this.tz;
    129
    130 			var	perspective = this.fv / (this.fv + vector.z),
    131 				_x = vector.x * perspective,
    132 				_y = -vector.y * perspective;
    133
    134             var result = {
    135                 x : _x + this.fx,
    136                 y : _y + this.fy,
    137                 z : -vector.z,
    138                 scale : perspective
    139             };
    140
    141 			if(view){
    142                 view.x = result.x;
    143                 view.y = result.y;
    144                 view.z = result.z;
    145                 view.scaleX = result.scale;
    146                 view.scaleY = result.scale;
    147 			}
    148
    149             return result;
    150 		},
    151
    152 	    /**
    153          * Z深度排序。
    154 	     */
    155 		sortZ : function(){
    156 			this.stage.children.sort(function(view_a, view_b){
    157                 return view_a.z > view_b.z;
    158             });
    159 		},
    160
    161 	    /**
    162          * Ticker 轮询使用。
    163 	     */
    164 		tick : function(){
    165 			this.sortZ();
    166 		}
    167
    168 	});
    169
    170 	return Camera3d;
    171
    172 })();