mirror of
				https://github.com/MapMakersAndProgrammers/alternativa3d-archive.git
				synced 2025-10-31 01:06:16 -07:00 
			
		
		
		
	more versions added
This commit is contained in:
		
							
								
								
									
										902
									
								
								Alternativa3D5/5.4.1/alternativa/engine3d/core/Camera3D.as
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										902
									
								
								Alternativa3D5/5.4.1/alternativa/engine3d/core/Camera3D.as
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,902 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	import alternativa.engine3d.*; | ||||
| 	import alternativa.engine3d.display.Skin; | ||||
| 	import alternativa.engine3d.display.View; | ||||
| 	import alternativa.engine3d.materials.DrawPoint; | ||||
| 	import alternativa.engine3d.materials.SurfaceMaterial; | ||||
| 	import alternativa.types.Matrix3D; | ||||
| 	import alternativa.types.Point3D; | ||||
| 	import alternativa.types.Set; | ||||
| 	 | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Point; | ||||
| 	import alternativa.utils.MathUtils; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Камера для отображения 3D-сцены на экране. | ||||
| 	 *  | ||||
| 	 * <p> Направление камеры совпадает с её локальной осью Z, поэтому только что созданная камера смотрит вверх в системе | ||||
| 	 * координат родителя. | ||||
| 	 *  | ||||
| 	 * <p> Для отображения видимой через камеру части сцены на экран, к камере должна быть подключёна область вывода — | ||||
| 	 * экземпляр класса <code>alternativa.engine3d.display.View</code>.  | ||||
| 	 *  | ||||
| 	 * @see alternativa.engine3d.display.View | ||||
| 	 */ | ||||
| 	public class Camera3D extends Object3D { | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт матрицы пространства камеры | ||||
| 		 */ | ||||
| 		alternativa3d var calculateMatrixOperation:Operation = new Operation("calculateMatrix", this, calculateMatrix, Operation.CAMERA_CALCULATE_MATRIX); | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт плоскостей отсечения | ||||
| 		 */		 | ||||
| 		alternativa3d var calculatePlanesOperation:Operation = new Operation("calculatePlanes", this, calculatePlanes, Operation.CAMERA_CALCULATE_PLANES); | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Отрисовка | ||||
| 		 */		 | ||||
| 		alternativa3d var renderOperation:Operation = new Operation("render", this, render, Operation.CAMERA_RENDER); | ||||
|  | ||||
| 		// Инкремент количества объектов | ||||
| 		private static var counter:uint = 0; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Поле зрения | ||||
| 		 */ | ||||
| 		alternativa3d var _fov:Number = Math.PI/2; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Фокусное расстояние | ||||
| 		 */ | ||||
| 		alternativa3d var focalLength:Number; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Перспективное искажение | ||||
| 		 */ | ||||
| 		alternativa3d var focalDistortion:Number; | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Флаги рассчитанности UV-матриц | ||||
| 		 */ | ||||
| 		alternativa3d var uvMatricesCalculated:Set = new Set(true); | ||||
| 		 | ||||
| 		// Всмомогательные точки для расчёта UV-матриц | ||||
| 		private var textureA:Point3D = new Point3D(); | ||||
| 		private var textureB:Point3D = new Point3D(); | ||||
| 		private var textureC:Point3D = new Point3D(); | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Вид из камеры | ||||
| 		 */ | ||||
| 		alternativa3d var _view:View; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Режим отрисовки | ||||
| 		 */ | ||||
| 		alternativa3d var _orthographic:Boolean = false; | ||||
| 		private var fullDraw:Boolean; | ||||
| 		 | ||||
| 		// Масштаб | ||||
| 		private var _zoom:Number = 1; | ||||
| 		 | ||||
| 		// Синус половинчатого угла обзора камеры | ||||
| 		private var viewAngle:Number; | ||||
| 		 | ||||
| 		// Направление камеры | ||||
| 		private var direction:Point3D = new Point3D(0, 0, 1); | ||||
| 		 | ||||
| 		// Обратная трансформация камеры | ||||
| 		private var cameraMatrix:Matrix3D = new Matrix3D(); | ||||
|  | ||||
| 		// Скины | ||||
| 		private var firstSkin:Skin; | ||||
| 		private var prevSkin:Skin; | ||||
| 		private var currentSkin:Skin; | ||||
| 		 | ||||
| 		// Плоскости отсечения | ||||
| 		private var leftPlane:Point3D = new Point3D(); | ||||
| 		private var rightPlane:Point3D = new Point3D(); | ||||
| 		private var topPlane:Point3D = new Point3D(); | ||||
| 		private var bottomPlane:Point3D = new Point3D(); | ||||
| 		private var leftOffset:Number; | ||||
| 		private var rightOffset:Number; | ||||
| 		private var topOffset:Number; | ||||
| 		private var bottomOffset:Number; | ||||
| 		 | ||||
| 		// Вспомогательные массивы точек для отрисовки | ||||
| 		private var points1:Array = new Array(); | ||||
| 		private var points2:Array = new Array(); | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создание нового экземпляра камеры. | ||||
| 		 *  | ||||
| 		 * @param name имя экземпляра | ||||
| 		 */ | ||||
| 		public function Camera3D(name:String = null) { | ||||
| 			super(name); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		private function calculateMatrix():void { | ||||
| 			// Расчёт матрицы пространства камеры | ||||
| 			cameraMatrix.copy(transformation); | ||||
| 			cameraMatrix.invert(); | ||||
| 			if (_orthographic) { | ||||
| 				cameraMatrix.scale(_zoom, _zoom, _zoom); | ||||
| 			} | ||||
| 			// Направление камеры | ||||
| 			direction.x = transformation.c; | ||||
| 			direction.y = transformation.g; | ||||
| 			direction.z = transformation.k; | ||||
| 			direction.normalize(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт плоскостей отсечения | ||||
| 		 */ | ||||
| 		private function calculatePlanes():void { | ||||
| 			var halfWidth:Number = _view._width*0.5; | ||||
| 			var halfHeight:Number = _view._height*0.5; | ||||
| 			 | ||||
| 			var aw:Number = transformation.a*halfWidth; | ||||
| 			var ew:Number = transformation.e*halfWidth; | ||||
| 			var iw:Number = transformation.i*halfWidth; | ||||
| 			var bh:Number = transformation.b*halfHeight; | ||||
| 			var fh:Number = transformation.f*halfHeight; | ||||
| 			var jh:Number = transformation.j*halfHeight; | ||||
| 			if (_orthographic) { | ||||
| 				// Расчёт плоскостей отсечения в изометрии | ||||
| 				aw /= _zoom; | ||||
| 				ew /= _zoom; | ||||
| 				iw /= _zoom; | ||||
| 				bh /= _zoom; | ||||
| 				fh /= _zoom; | ||||
| 				jh /= _zoom; | ||||
| 				 | ||||
| 				// Левая плоскость | ||||
| 				leftPlane.x = transformation.f*transformation.k - transformation.j*transformation.g; | ||||
| 				leftPlane.y = transformation.j*transformation.c - transformation.b*transformation.k; | ||||
| 				leftPlane.z = transformation.b*transformation.g - transformation.f*transformation.c; | ||||
| 				leftOffset = (transformation.d - aw)*leftPlane.x + (transformation.h - ew)*leftPlane.y + (transformation.l - iw)*leftPlane.z; | ||||
| 				 | ||||
| 				// Правая плоскость | ||||
| 				rightPlane.x = -leftPlane.x; | ||||
| 				rightPlane.y = -leftPlane.y; | ||||
| 				rightPlane.z = -leftPlane.z; | ||||
| 				rightOffset = (transformation.d + aw)*rightPlane.x + (transformation.h + ew)*rightPlane.y + (transformation.l + iw)*rightPlane.z; | ||||
| 				 | ||||
| 				// Верхняя плоскость | ||||
| 				topPlane.x = transformation.g*transformation.i - transformation.k*transformation.e; | ||||
| 				topPlane.y = transformation.k*transformation.a - transformation.c*transformation.i; | ||||
| 				topPlane.z = transformation.c*transformation.e - transformation.g*transformation.a; | ||||
| 				topOffset = (transformation.d - bh)*topPlane.x + (transformation.h - fh)*topPlane.y + (transformation.l - jh)*topPlane.z; | ||||
| 				 | ||||
| 				// Нижняя плоскость | ||||
| 				bottomPlane.x = -topPlane.x; | ||||
| 				bottomPlane.y = -topPlane.y; | ||||
| 				bottomPlane.z = -topPlane.z; | ||||
| 				bottomOffset = (transformation.d + bh)*bottomPlane.x + (transformation.h + fh)*bottomPlane.y + (transformation.l + jh)*bottomPlane.z; | ||||
| 			} else { | ||||
| 				// Вычисляем расстояние фокуса | ||||
| 				focalLength = Math.sqrt(_view._width*_view._width + _view._height*_view._height)*0.5/Math.tan(0.5*_fov); | ||||
| 				// Вычисляем минимальное (однопиксельное) искажение перспективной коррекции | ||||
| 				focalDistortion = 1/(focalLength*focalLength); | ||||
| 				 | ||||
| 				// Расчёт плоскостей отсечения в перспективе | ||||
| 				var cl:Number = transformation.c*focalLength; | ||||
| 				var gl:Number = transformation.g*focalLength; | ||||
| 				var kl:Number = transformation.k*focalLength; | ||||
| 				 | ||||
| 				// Угловые вектора пирамиды видимости | ||||
| 				var leftTopX:Number = -aw - bh + cl; | ||||
| 				var leftTopY:Number = -ew - fh + gl; | ||||
| 				var leftTopZ:Number = -iw - jh + kl; | ||||
| 				var rightTopX:Number = aw - bh + cl; | ||||
| 				var rightTopY:Number = ew - fh + gl; | ||||
| 				var rightTopZ:Number = iw - jh + kl; | ||||
| 				var leftBottomX:Number = -aw + bh + cl; | ||||
| 				var leftBottomY:Number = -ew + fh + gl; | ||||
| 				var leftBottomZ:Number = -iw + jh + kl; | ||||
| 				var rightBottomX:Number = aw + bh + cl; | ||||
| 				var rightBottomY:Number = ew + fh + gl; | ||||
| 				var rightBottomZ:Number = iw + jh + kl; | ||||
| 				 | ||||
| 				// Левая плоскость | ||||
| 				leftPlane.x = leftBottomY*leftTopZ - leftBottomZ*leftTopY; | ||||
| 				leftPlane.y = leftBottomZ*leftTopX - leftBottomX*leftTopZ; | ||||
| 				leftPlane.z = leftBottomX*leftTopY - leftBottomY*leftTopX; | ||||
| 				leftOffset = transformation.d*leftPlane.x + transformation.h*leftPlane.y + transformation.l*leftPlane.z; | ||||
|  | ||||
| 				// Правая плоскость | ||||
| 				rightPlane.x = rightTopY*rightBottomZ - rightTopZ*rightBottomY; | ||||
| 				rightPlane.y = rightTopZ*rightBottomX - rightTopX*rightBottomZ; | ||||
| 				rightPlane.z = rightTopX*rightBottomY - rightTopY*rightBottomX; | ||||
| 				rightOffset = transformation.d*rightPlane.x + transformation.h*rightPlane.y + transformation.l*rightPlane.z; | ||||
|  | ||||
| 				// Верхняя плоскость | ||||
| 				topPlane.x = leftTopY*rightTopZ - leftTopZ*rightTopY; | ||||
| 				topPlane.y = leftTopZ*rightTopX - leftTopX*rightTopZ; | ||||
| 				topPlane.z = leftTopX*rightTopY - leftTopY*rightTopX; | ||||
| 				topOffset = transformation.d*topPlane.x + transformation.h*topPlane.y + transformation.l*topPlane.z; | ||||
|  | ||||
| 				// Нижняя плоскость | ||||
| 				bottomPlane.x = rightBottomY*leftBottomZ - rightBottomZ*leftBottomY; | ||||
| 				bottomPlane.y = rightBottomZ*leftBottomX - rightBottomX*leftBottomZ; | ||||
| 				bottomPlane.z = rightBottomX*leftBottomY - rightBottomY*leftBottomX; | ||||
| 				bottomOffset = transformation.d*bottomPlane.x + transformation.h*bottomPlane.y + transformation.l*bottomPlane.z; | ||||
| 				 | ||||
| 				 | ||||
| 				// Расчёт угла конуса | ||||
| 				var length:Number = Math.sqrt(leftTopX*leftTopX + leftTopY*leftTopY + leftTopZ*leftTopZ); | ||||
| 				leftTopX /= length; | ||||
| 				leftTopY /= length; | ||||
| 				leftTopZ /= length; | ||||
| 				length = Math.sqrt(rightTopX*rightTopX + rightTopY*rightTopY + rightTopZ*rightTopZ); | ||||
| 				rightTopX /= length; | ||||
| 				rightTopY /= length; | ||||
| 				rightTopZ /= length; | ||||
| 				length = Math.sqrt(leftBottomX*leftBottomX + leftBottomY*leftBottomY + leftBottomZ*leftBottomZ); | ||||
| 				leftBottomX /= length; | ||||
| 				leftBottomY /= length; | ||||
| 				leftBottomZ /= length; | ||||
| 				length = Math.sqrt(rightBottomX*rightBottomX + rightBottomY*rightBottomY + rightBottomZ*rightBottomZ); | ||||
| 				rightBottomX /= length; | ||||
| 				rightBottomY /= length; | ||||
| 				rightBottomZ /= length; | ||||
|  | ||||
| 				viewAngle = leftTopX*direction.x + leftTopY*direction.y + leftTopZ*direction.z; | ||||
| 				var dot:Number = rightTopX*direction.x + rightTopY*direction.y + rightTopZ*direction.z; | ||||
| 				viewAngle = (dot < viewAngle) ? dot : viewAngle; | ||||
| 				dot = leftBottomX*direction.x + leftBottomY*direction.y + leftBottomZ*direction.z; | ||||
| 				viewAngle = (dot < viewAngle) ? dot : viewAngle; | ||||
| 				dot = rightBottomX*direction.x + rightBottomY*direction.y + rightBottomZ*direction.z; | ||||
| 				viewAngle = (dot < viewAngle) ? dot : viewAngle; | ||||
| 				 | ||||
| 				viewAngle = Math.sin(Math.acos(viewAngle)); | ||||
| 			} | ||||
| 		} | ||||
| 			 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		private function render():void { | ||||
| 			// Режим отрисовки | ||||
| 			fullDraw = (calculateMatrixOperation.queued || calculatePlanesOperation.queued); | ||||
|  | ||||
| 			// Очистка рассчитанных текстурных матриц | ||||
| 			uvMatricesCalculated.clear(); | ||||
| 			 | ||||
| 			// Отрисовка | ||||
| 			prevSkin = null; | ||||
| 			currentSkin = firstSkin; | ||||
| 			renderBSPNode(_scene.bsp); | ||||
|  | ||||
| 			// Удаление ненужных скинов | ||||
| 			while (currentSkin != null) { | ||||
|  				removeCurrentSkin(); | ||||
| 	 		} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		private function renderBSPNode(node:BSPNode):void { | ||||
| 			if (node != null) { | ||||
| 				var primitive:*; | ||||
| 				var normal:Point3D = node.normal; | ||||
| 				var cameraAngle:Number = direction.x*normal.x + direction.y*normal.y + direction.z*normal.z; | ||||
| 				var cameraOffset:Number; | ||||
| 				if (!_orthographic) { | ||||
| 					 cameraOffset = globalCoords.x*normal.x + globalCoords.y*normal.y + globalCoords.z*normal.z - node.offset; | ||||
| 				} | ||||
| 				if (node.primitive != null) { | ||||
| 					// В ноде только базовый примитив | ||||
| 					if (_orthographic ? (cameraAngle < 0) : (cameraOffset > 0)) { | ||||
| 						// Камера спереди ноды | ||||
| 						if (_orthographic || cameraAngle < viewAngle) { | ||||
| 							renderBSPNode(node.back); | ||||
| 							drawSkin(node.primitive); | ||||
| 						} | ||||
| 						renderBSPNode(node.front); | ||||
| 					} else { | ||||
| 						// Камера сзади ноды | ||||
| 						if (_orthographic || cameraAngle > -viewAngle) { | ||||
| 							renderBSPNode(node.front); | ||||
| 						} | ||||
| 						renderBSPNode(node.back); | ||||
| 					} | ||||
| 				} else { | ||||
| 					// В ноде несколько примитивов | ||||
| 					if (_orthographic ? (cameraAngle < 0) : (cameraOffset > 0)) { | ||||
| 						// Камера спереди ноды | ||||
| 						if (_orthographic || cameraAngle < viewAngle) { | ||||
| 							renderBSPNode(node.back); | ||||
| 							for (primitive in node.frontPrimitives) { | ||||
| 								drawSkin(primitive); | ||||
| 							} | ||||
| 						} | ||||
| 						renderBSPNode(node.front); | ||||
| 					} else { | ||||
| 						// Камера сзади ноды | ||||
| 						if (_orthographic || cameraAngle > -viewAngle) { | ||||
| 							renderBSPNode(node.front); | ||||
| 							for (primitive in node.backPrimitives) { | ||||
| 								drawSkin(primitive); | ||||
| 							} | ||||
| 						} | ||||
| 						renderBSPNode(node.back); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Отрисовка скина примитива | ||||
| 		 */ | ||||
|  		private function drawSkin(primitive:PolyPrimitive):void { | ||||
|  			if (!fullDraw && currentSkin != null && currentSkin.primitive == primitive && !_scene.changedPrimitives[primitive]) { | ||||
| 	 			// Пропуск скина | ||||
| 				prevSkin = currentSkin; | ||||
| 				currentSkin = currentSkin.nextSkin; | ||||
| 			} else { | ||||
| 	 			// Проверка поверхности  | ||||
| 	 			var surface:Surface = primitive.face._surface; | ||||
| 	 			if (surface == null) { | ||||
| 	 				return; | ||||
| 	 			} | ||||
| 	 			// Проверка материала | ||||
| 	 			var material:SurfaceMaterial = surface._material; | ||||
|  				if (material == null || !material.canDraw(primitive)) { | ||||
|  					return; | ||||
|  				} | ||||
|  				// Отсечение выходящих за окно просмотра частей | ||||
|  				var i:uint; | ||||
|  				var length:uint = primitive.num; | ||||
|  				var primitivePoint:Point3D; | ||||
|  				var primitiveUV:Point; | ||||
|  				var point:DrawPoint; | ||||
|  				var useUV:Boolean = !_orthographic && material.useUV && primitive.face.uvMatrixBase;  | ||||
|  				if (useUV) { | ||||
|  					// Формируем список точек и UV-координат полигона | ||||
| 					for (i = 0; i < length; i++) { | ||||
| 						primitivePoint = primitive.points[i]; | ||||
| 						primitiveUV = primitive.uvs[i]; | ||||
| 						point = points1[i]; | ||||
| 						if (point == null) { | ||||
| 							points1[i] = new DrawPoint(primitivePoint.x, primitivePoint.y, primitivePoint.z, primitiveUV.x, primitiveUV.y); | ||||
| 						} else { | ||||
| 							point.x = primitivePoint.x; | ||||
| 							point.y = primitivePoint.y; | ||||
| 							point.z = primitivePoint.z; | ||||
| 							point.u = primitiveUV.x; | ||||
| 							point.v = primitiveUV.y; | ||||
| 						} | ||||
| 	 				} | ||||
|  				} else { | ||||
| 	 				// Формируем список точек полигона | ||||
| 					for (i = 0; i < length; i++) {	 | ||||
| 						primitivePoint = primitive.points[i]; | ||||
| 						point = points1[i]; | ||||
| 						if (point == null) { | ||||
| 							points1[i] = new DrawPoint(primitivePoint.x, primitivePoint.y, primitivePoint.z); | ||||
| 						} else { | ||||
| 							point.x = primitivePoint.x; | ||||
| 							point.y = primitivePoint.y; | ||||
| 							point.z = primitivePoint.z; | ||||
| 						} | ||||
| 	 				} | ||||
| 	 			} | ||||
|  				// Отсечение по левой стороне | ||||
|  				length = clip(length, points1, points2, leftPlane, leftOffset, useUV); | ||||
|  				if (length < 3) { | ||||
|  					return; | ||||
|  				} | ||||
|  				// Отсечение по правой стороне | ||||
|  				length = clip(length, points2, points1, rightPlane, rightOffset, useUV); | ||||
|  				if (length < 3) { | ||||
|  					return; | ||||
|  				} | ||||
|  				// Отсечение по верхней стороне | ||||
|  				length = clip(length, points1, points2, topPlane, topOffset, useUV); | ||||
|  				if (length < 3) { | ||||
|  					return; | ||||
|  				} | ||||
|  				// Отсечение по нижней стороне | ||||
|  				length = clip(length, points2, points1, bottomPlane, bottomOffset, useUV); | ||||
|  				if (length < 3) { | ||||
|  					return; | ||||
|  				} | ||||
| 	 					 | ||||
|  				if (fullDraw || _scene.changedPrimitives[primitive]) { | ||||
|  | ||||
| 					// Если конец списка скинов | ||||
|  					if (currentSkin == null) { | ||||
| 						// Добавляем скин в конец  | ||||
|  						addCurrentSkin(); | ||||
|  					} else { | ||||
|  						if (fullDraw || _scene.changedPrimitives[currentSkin.primitive]) { | ||||
| 							// Очистка скина | ||||
| 							currentSkin.material.clear(currentSkin); | ||||
| 	 					} else { | ||||
| 							// Вставка скина перед текущим | ||||
| 	 						insertCurrentSkin(); | ||||
| 	 					} | ||||
|  					} | ||||
|  					 | ||||
|  					// Переводим координаты в систему камеры | ||||
|  					var x:Number; | ||||
| 	 				var y:Number; | ||||
| 	 				var z:Number; | ||||
|  					for (i = 0; i < length; i++) { | ||||
|  						point = points1[i]; | ||||
|  						x = point.x; | ||||
|  						y = point.y; | ||||
|  						z = point.z; | ||||
|  						point.x = cameraMatrix.a*x + cameraMatrix.b*y + cameraMatrix.c*z + cameraMatrix.d; | ||||
| 						point.y = cameraMatrix.e*x + cameraMatrix.f*y + cameraMatrix.g*z + cameraMatrix.h; | ||||
| 						point.z = cameraMatrix.i*x + cameraMatrix.j*y + cameraMatrix.k*z + cameraMatrix.l; | ||||
|  					} | ||||
|  					 | ||||
| 					// Назначаем скину примитив и материал | ||||
| 					currentSkin.primitive = primitive; | ||||
| 					currentSkin.material = material; | ||||
| 					material.draw(this, currentSkin, length, points1); | ||||
| 					 | ||||
| 		 			// Переключаемся на следующий скин | ||||
| 		 			prevSkin = currentSkin; | ||||
| 		 			currentSkin = currentSkin.nextSkin; | ||||
|  					 | ||||
|  				} else { | ||||
|  					 | ||||
| 					// Удаление ненужных скинов | ||||
| 					while (currentSkin != null && _scene.changedPrimitives[currentSkin.primitive]) { | ||||
| 		 				removeCurrentSkin(); | ||||
| 		 			} | ||||
| 	 | ||||
| 		 			// Переключение на следующий скин | ||||
| 		 			if (currentSkin != null) { | ||||
| 			 			prevSkin = currentSkin; | ||||
| 		 				currentSkin = currentSkin.nextSkin; | ||||
| 		 			} | ||||
|  					 | ||||
|  				} | ||||
|  			} | ||||
|  		} | ||||
|  		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Отсечение полигона плоскостью. | ||||
| 		 */ | ||||
| 		private function clip(length:uint, points1:Array, points2:Array, plane:Point3D, offset:Number, calculateUV:Boolean):uint { | ||||
| 			var i:uint; | ||||
| 			var k:Number; | ||||
| 			var index:uint = 0; | ||||
| 			var point:DrawPoint; | ||||
| 			var point1:DrawPoint; | ||||
| 			var point2:DrawPoint; | ||||
| 			var offset1:Number; | ||||
| 			var offset2:Number; | ||||
| 			 | ||||
| 			point1 = points1[length - 1]; | ||||
| 			offset1 = plane.x*point1.x + plane.y*point1.y + plane.z*point1.z - offset; | ||||
| 			 | ||||
| 			if (calculateUV) { | ||||
|  | ||||
| 				for (i = 0; i < length; i++) { | ||||
| 	 | ||||
| 					point2 = points1[i]; | ||||
| 					offset2 = plane.x*point2.x + plane.y*point2.y + plane.z*point2.z - offset; | ||||
| 					 | ||||
| 					if (offset2 > 0) { | ||||
| 						if (offset1 <= 0) { | ||||
| 							k = offset2/(offset2 - offset1); | ||||
| 							point = points2[index]; | ||||
| 							if (point == null) { | ||||
| 								point = new DrawPoint(point2.x - (point2.x - point1.x)*k, point2.y - (point2.y - point1.y)*k, point2.z - (point2.z - point1.z)*k, point2.u - (point2.u - point1.u)*k, point2.v - (point2.v - point1.v)*k); | ||||
| 								points2[index] = point; | ||||
| 							} else { | ||||
| 								point.x = point2.x - (point2.x - point1.x)*k; | ||||
| 								point.y = point2.y - (point2.y - point1.y)*k; | ||||
| 								point.z = point2.z - (point2.z - point1.z)*k; | ||||
| 								point.u = point2.u - (point2.u - point1.u)*k; | ||||
| 								point.v = point2.v - (point2.v - point1.v)*k; | ||||
| 							} | ||||
| 							index++; | ||||
| 						} | ||||
| 						point = points2[index]; | ||||
| 						if (point == null) { | ||||
| 							point = new DrawPoint(point2.x, point2.y, point2.z, point2.u, point2.v); | ||||
| 							points2[index] = point; | ||||
| 						} else { | ||||
| 							point.x = point2.x; | ||||
| 							point.y = point2.y; | ||||
| 							point.z = point2.z; | ||||
| 							point.u = point2.u; | ||||
| 							point.v = point2.v; | ||||
| 						} | ||||
| 						index++; | ||||
| 					} else { | ||||
| 						if (offset1 > 0) { | ||||
| 							k = offset2/(offset2 - offset1); | ||||
| 							point = points2[index]; | ||||
| 							if (point == null) { | ||||
| 								point = new DrawPoint(point2.x - (point2.x - point1.x)*k, point2.y - (point2.y - point1.y)*k, point2.z - (point2.z - point1.z)*k, point2.u - (point2.u - point1.u)*k, point2.v - (point2.v - point1.v)*k); | ||||
| 								points2[index] = point; | ||||
| 							} else { | ||||
| 								point.x = point2.x - (point2.x - point1.x)*k; | ||||
| 								point.y = point2.y - (point2.y - point1.y)*k; | ||||
| 								point.z = point2.z - (point2.z - point1.z)*k; | ||||
| 								point.u = point2.u - (point2.u - point1.u)*k; | ||||
| 								point.v = point2.v - (point2.v - point1.v)*k; | ||||
| 							} | ||||
| 							index++; | ||||
| 						} | ||||
| 					} | ||||
| 					offset1 = offset2; | ||||
| 					point1 = point2; | ||||
| 				} | ||||
| 				 | ||||
| 			} else { | ||||
| 	 | ||||
| 				for (i = 0; i < length; i++) { | ||||
| 	 | ||||
| 					point2 = points1[i]; | ||||
| 					offset2 = plane.x*point2.x + plane.y*point2.y + plane.z*point2.z - offset; | ||||
| 					 | ||||
| 					if (offset2 > 0) { | ||||
| 						if (offset1 <= 0) { | ||||
| 							k = offset2/(offset2 - offset1); | ||||
| 							point = points2[index]; | ||||
| 							if (point == null) { | ||||
| 								point = new DrawPoint(point2.x - (point2.x - point1.x)*k, point2.y - (point2.y - point1.y)*k, point2.z - (point2.z - point1.z)*k); | ||||
| 								points2[index] = point; | ||||
| 							} else { | ||||
| 								point.x = point2.x - (point2.x - point1.x)*k; | ||||
| 								point.y = point2.y - (point2.y - point1.y)*k; | ||||
| 								point.z = point2.z - (point2.z - point1.z)*k; | ||||
| 							} | ||||
| 							index++; | ||||
| 						} | ||||
| 						point = points2[index]; | ||||
| 						if (point == null) { | ||||
| 							point = new DrawPoint(point2.x, point2.y, point2.z); | ||||
| 							points2[index] = point; | ||||
| 						} else { | ||||
| 							point.x = point2.x; | ||||
| 							point.y = point2.y; | ||||
| 							point.z = point2.z; | ||||
| 						} | ||||
| 						index++; | ||||
| 					} else { | ||||
| 						if (offset1 > 0) { | ||||
| 							k = offset2/(offset2 - offset1); | ||||
| 							point = points2[index]; | ||||
| 							if (point == null) { | ||||
| 								point = new DrawPoint(point2.x - (point2.x - point1.x)*k, point2.y - (point2.y - point1.y)*k, point2.z - (point2.z - point1.z)*k); | ||||
| 								points2[index] = point; | ||||
| 							} else { | ||||
| 								point.x = point2.x - (point2.x - point1.x)*k; | ||||
| 								point.y = point2.y - (point2.y - point1.y)*k; | ||||
| 								point.z = point2.z - (point2.z - point1.z)*k; | ||||
| 							} | ||||
| 							index++; | ||||
| 						} | ||||
| 					} | ||||
| 					offset1 = offset2; | ||||
| 					point1 = point2; | ||||
| 				} | ||||
| 			} | ||||
| 			return index; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Добавление текущего скина. | ||||
| 		 */ | ||||
| 		private function addCurrentSkin():void { | ||||
|  			currentSkin = Skin.createSkin(); | ||||
|  			_view.canvas.addChild(currentSkin); | ||||
|  			if (prevSkin == null) { | ||||
|  				firstSkin = currentSkin; | ||||
|  			} else { | ||||
|  				prevSkin.nextSkin = currentSkin; | ||||
|  			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Вставляем под текущий скин. | ||||
| 		 */ | ||||
| 		private function insertCurrentSkin():void { | ||||
| 			var skin:Skin = Skin.createSkin(); | ||||
|  			_view.canvas.addChildAt(skin, _view.canvas.getChildIndex(currentSkin)); | ||||
|  			skin.nextSkin = currentSkin; | ||||
|  			if (prevSkin == null) { | ||||
|  				firstSkin = skin; | ||||
|  			} else { | ||||
|  				prevSkin.nextSkin = skin; | ||||
|  			} | ||||
|  			currentSkin = skin; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Удаляет текущий скин. | ||||
| 		 */ | ||||
| 		private function removeCurrentSkin():void { | ||||
| 			// Сохраняем следующий | ||||
| 			var next:Skin = currentSkin.nextSkin; | ||||
| 			// Удаляем из канваса | ||||
| 			_view.canvas.removeChild(currentSkin); | ||||
| 			// Очистка скина | ||||
| 			if (currentSkin.material != null) { | ||||
| 				currentSkin.material.clear(currentSkin); | ||||
| 			} | ||||
| 			// Зачищаем ссылки | ||||
| 			currentSkin.nextSkin = null; | ||||
| 			currentSkin.primitive = null; | ||||
| 			currentSkin.material = null; | ||||
| 			// Удаляем | ||||
| 			Skin.destroySkin(currentSkin); | ||||
| 			// Следующий устанавливаем текущим | ||||
| 			currentSkin = next; | ||||
| 			// Устанавливаем связь от предыдущего скина | ||||
| 			if (prevSkin == null) { | ||||
| 		 		firstSkin = currentSkin; | ||||
| 		 	} else { | ||||
| 		 		prevSkin.nextSkin = currentSkin; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */		 | ||||
| 		alternativa3d function calculateUVMatrix(face:Face, width:uint, height:uint):void { | ||||
|  | ||||
| 			// Расчёт точек базового примитива в координатах камеры | ||||
| 			var point:Point3D = face.primitive.points[0]; | ||||
| 			textureA.x = cameraMatrix.a*point.x + cameraMatrix.b*point.y + cameraMatrix.c*point.z; | ||||
| 			textureA.y = cameraMatrix.e*point.x + cameraMatrix.f*point.y + cameraMatrix.g*point.z; | ||||
| 			point = face.primitive.points[1]; | ||||
| 			textureB.x = cameraMatrix.a*point.x + cameraMatrix.b*point.y + cameraMatrix.c*point.z; | ||||
| 			textureB.y = cameraMatrix.e*point.x + cameraMatrix.f*point.y + cameraMatrix.g*point.z; | ||||
| 			point = face.primitive.points[2]; | ||||
| 			textureC.x = cameraMatrix.a*point.x + cameraMatrix.b*point.y + cameraMatrix.c*point.z; | ||||
| 			textureC.y = cameraMatrix.e*point.x + cameraMatrix.f*point.y + cameraMatrix.g*point.z; | ||||
| 			 | ||||
| 			// Находим AB и AC | ||||
| 			var abx:Number = textureB.x - textureA.x; | ||||
| 			var aby:Number = textureB.y - textureA.y; | ||||
| 			var acx:Number = textureC.x - textureA.x; | ||||
| 			var acy:Number = textureC.y - textureA.y; | ||||
|  | ||||
| 			// Расчёт текстурной матрицы | ||||
| 			var uvMatrixBase:Matrix = face.uvMatrixBase; | ||||
| 			var uvMatrix:Matrix = face.uvMatrix; | ||||
| 			uvMatrix.a = (uvMatrixBase.a*abx + uvMatrixBase.b*acx)/width; | ||||
| 			uvMatrix.b = (uvMatrixBase.a*aby + uvMatrixBase.b*acy)/width; | ||||
| 			uvMatrix.c = -(uvMatrixBase.c*abx + uvMatrixBase.d*acx)/height; | ||||
| 			uvMatrix.d = -(uvMatrixBase.c*aby + uvMatrixBase.d*acy)/height; | ||||
| 			uvMatrix.tx = (uvMatrixBase.tx + uvMatrixBase.c)*abx + (uvMatrixBase.ty + uvMatrixBase.d)*acx + textureA.x + cameraMatrix.d; | ||||
| 			uvMatrix.ty = (uvMatrixBase.tx + uvMatrixBase.c)*aby + (uvMatrixBase.ty + uvMatrixBase.d)*acy + textureA.y + cameraMatrix.h; | ||||
| 			 | ||||
| 			// Помечаем, как рассчитанную | ||||
| 			uvMatricesCalculated[face] = true; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Поле вывода, в котором происходит отрисовка камеры. | ||||
| 		 */ | ||||
| 		public function get view():View { | ||||
| 			return _view; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		public function set view(value:View):void { | ||||
| 			if (value != _view) { | ||||
| 				if (_view != null) { | ||||
| 					_view.camera = null; | ||||
| 				} | ||||
| 				if (value != null) { | ||||
| 					value.camera = this; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Включение режима аксонометрической проекции. | ||||
| 		 *  | ||||
| 		 * @default false | ||||
| 		 */		 | ||||
| 		public function get orthographic():Boolean { | ||||
| 			return _orthographic; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */		 | ||||
| 		public function set orthographic(value:Boolean):void { | ||||
| 			if (_orthographic != value) { | ||||
| 				// Отправляем сигнал об изменении типа камеры | ||||
| 				addOperationToScene(calculateMatrixOperation); | ||||
| 				// Сохраняем новое значение | ||||
| 				_orthographic = value; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Угол поля зрения в радианах в режиме перспективной проекции. При изменении FOV изменяется фокусное расстояние | ||||
| 		 * камеры по формуле <code>f = d/tan(fov/2)</code>, где <code>d</code> является половиной диагонали поля вывода. | ||||
| 		 * Угол зрения ограничен диапазоном 0-180 градусов. | ||||
| 		 */ | ||||
| 		public function get fov():Number { | ||||
| 			return _fov; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		public function set fov(value:Number):void { | ||||
| 			value = (value < 0) ? 0 : ((value > (Math.PI - 0.0001)) ? (Math.PI - 0.0001) : value); | ||||
| 			if (_fov != value) { | ||||
| 				// Если перспектива | ||||
| 				if (!_orthographic) { | ||||
| 					// Отправляем сигнал об изменении плоскостей отсечения | ||||
| 					addOperationToScene(calculatePlanesOperation); | ||||
| 				} | ||||
| 				// Сохраняем новое значение | ||||
| 				_fov = value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Коэффициент увеличения изображения в режиме аксонометрической проекции. | ||||
| 		 */ | ||||
| 		public function get zoom():Number { | ||||
| 			return _zoom; | ||||
| 		}		 | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		public function set zoom(value:Number):void { | ||||
| 			value = (value < 0) ? 0 : value; | ||||
| 			if (_zoom != value) { | ||||
| 				// Если изометрия | ||||
| 				if (_orthographic) { | ||||
| 					// Отправляем сигнал об изменении zoom | ||||
| 					addOperationToScene(calculateMatrixOperation); | ||||
| 				} | ||||
| 				// Сохраняем новое значение | ||||
| 				_zoom = value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @inheritDoc | ||||
| 		 */ | ||||
| 		override protected function addToScene(scene:Scene3D):void { | ||||
| 			super.addToScene(scene); | ||||
| 			if (_view != null) { | ||||
| 				// Отправляем операцию расчёта плоскостей отсечения | ||||
| 				scene.addOperation(calculatePlanesOperation); | ||||
| 				// Подписываемся на сигналы сцены | ||||
| 				scene.changePrimitivesOperation.addSequel(renderOperation); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @inheritDoc | ||||
| 		 */ | ||||
| 		override protected function removeFromScene(scene:Scene3D):void { | ||||
| 			super.removeFromScene(scene); | ||||
| 			 | ||||
| 			// Удаляем все операции из очереди | ||||
| 			scene.removeOperation(calculateMatrixOperation); | ||||
| 			scene.removeOperation(calculatePlanesOperation); | ||||
| 			scene.removeOperation(renderOperation); | ||||
| 			 | ||||
| 			if (_view != null) { | ||||
| 				// Отписываемся от сигналов сцены | ||||
| 				scene.changePrimitivesOperation.removeSequel(renderOperation); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		alternativa3d function addToView(view:View):void { | ||||
| 			// Сохраняем первый скин | ||||
| 			firstSkin = (view.canvas.numChildren > 0) ? Skin(view.canvas.getChildAt(0)) : null; | ||||
| 			 | ||||
| 			// Подписка на свои операции | ||||
|  | ||||
| 			// При изменении камеры пересчёт матрицы | ||||
| 			calculateTransformationOperation.addSequel(calculateMatrixOperation); | ||||
| 			// При изменении матрицы или FOV пересчёт плоскостей отсечения | ||||
| 			calculateMatrixOperation.addSequel(calculatePlanesOperation); | ||||
| 			// При изменении плоскостей перерисовка | ||||
| 			calculatePlanesOperation.addSequel(renderOperation); | ||||
|  | ||||
| 			if (_scene != null) { | ||||
| 				// Отправляем сигнал перерисовки | ||||
| 				_scene.addOperation(calculateMatrixOperation); | ||||
| 				// Подписываемся на сигналы сцены | ||||
| 				_scene.changePrimitivesOperation.addSequel(renderOperation); | ||||
| 			} | ||||
| 			 | ||||
| 			// Сохраняем вид | ||||
| 			_view = view; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		alternativa3d function removeFromView(view:View):void { | ||||
| 			// Сброс ссылки на первый скин | ||||
| 			firstSkin = null; | ||||
| 			 | ||||
| 			// Отписка от своих операций | ||||
|  | ||||
| 			// При изменении камеры пересчёт матрицы | ||||
| 			calculateTransformationOperation.removeSequel(calculateMatrixOperation); | ||||
| 			// При изменении матрицы или FOV пересчёт плоскостей отсечения | ||||
| 			calculateMatrixOperation.removeSequel(calculatePlanesOperation); | ||||
| 			// При изменении плоскостей перерисовка | ||||
| 			calculatePlanesOperation.removeSequel(renderOperation); | ||||
| 			 | ||||
| 			if (_scene != null) { | ||||
| 				// Удаляем все операции из очереди | ||||
| 				_scene.removeOperation(calculateMatrixOperation); | ||||
| 				_scene.removeOperation(calculatePlanesOperation); | ||||
| 				_scene.removeOperation(renderOperation); | ||||
| 				// Отписываемся от сигналов сцены | ||||
| 				_scene.changePrimitivesOperation.removeSequel(renderOperation); | ||||
| 			} | ||||
| 			// Удаляем ссылку на вид | ||||
| 			_view = null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @inheritDoc | ||||
| 		 */ | ||||
| 		override protected function defaultName():String { | ||||
| 			return "camera" + ++counter; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @inheritDoc | ||||
| 		 */ | ||||
| 		protected override function createEmptyObject():Object3D { | ||||
| 			return new Camera3D(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @inheritDoc | ||||
| 		 */ | ||||
| 		protected override function clonePropertiesFrom(source:Object3D):void { | ||||
| 			super.clonePropertiesFrom(source); | ||||
| 			 | ||||
| 			var src:Camera3D = Camera3D(source); | ||||
| 			orthographic = src._orthographic; | ||||
| 			zoom = src._zoom; | ||||
| 			fov = src._fov; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Tubix
					Tubix