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:
		
							
								
								
									
										921
									
								
								Alternativa3D5/5.4.1/alternativa/engine3d/core/Face.as
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										921
									
								
								Alternativa3D5/5.4.1/alternativa/engine3d/core/Face.as
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,921 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	import alternativa.engine3d.*; | ||||
| 	import alternativa.types.Point3D; | ||||
| 	import alternativa.types.Set; | ||||
|  | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Point; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
|  | ||||
| 	/** | ||||
| 	 * Грань, образованная тремя или более вершинами. Грани являются составными частями полигональных объектов. Каждая грань | ||||
| 	 * содержит информацию об объекте и поверхности, которым она принадлежит. Для обеспечения возможности наложения | ||||
| 	 * текстуры на грань, первым трём её вершинам могут быть заданы UV-координаты, на основании которых расчитывается | ||||
| 	 * матрица трансформации текстуры. | ||||
| 	 */ | ||||
| 	final public class Face { | ||||
| 		// Операции | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт глобальной нормали плоскости грани. | ||||
| 		 */		 | ||||
| 		alternativa3d var calculateNormalOperation:Operation = new Operation("calculateNormal", this, calculateNormal, Operation.FACE_CALCULATE_NORMAL); | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт UV-координат (выполняется до трансформации, чтобы UV корректно разбились при построении BSP). | ||||
| 		 */		  | ||||
| 		alternativa3d var calculateUVOperation:Operation = new Operation("calculateUV", this, calculateUV, Operation.FACE_CALCULATE_UV); | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Обновление примитива в сцене. | ||||
| 		 */		  | ||||
| 		alternativa3d var updatePrimitiveOperation:Operation = new Operation("updatePrimitive", this, updatePrimitive, Operation.FACE_UPDATE_PRIMITIVE); | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Обновление материала. | ||||
| 		 */		  | ||||
| 		alternativa3d var updateMaterialOperation:Operation = new Operation("updateMaterial", this, updateMaterial, Operation.FACE_UPDATE_MATERIAL); | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт UV для фрагментов (выполняется после трансформации, если её не было). | ||||
| 		 */ | ||||
| 		alternativa3d var calculateFragmentsUVOperation:Operation = new Operation("calculateFragmentsUV", this, calculateFragmentsUV, Operation.FACE_CALCULATE_FRAGMENTS_UV); | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Меш | ||||
| 		 */ | ||||
| 		alternativa3d var _mesh:Mesh; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Поверхность | ||||
| 		 */		 | ||||
| 		alternativa3d var _surface:Surface; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Вершины грани | ||||
| 		 */ | ||||
| 		alternativa3d var _vertices:Array; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Количество вершин | ||||
| 		 */ | ||||
| 		alternativa3d var _verticesCount:uint; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Примитив | ||||
| 		 */ | ||||
| 		alternativa3d var primitive:PolyPrimitive; | ||||
|  | ||||
| 		// UV-координаты | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */		 | ||||
| 		alternativa3d var _aUV:Point; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */		 | ||||
| 		alternativa3d var _bUV:Point; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */		 | ||||
| 		alternativa3d var _cUV:Point; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Коэффициенты базовой UV-матрицы | ||||
| 		 */ | ||||
| 		alternativa3d var uvMatrixBase:Matrix; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * UV Матрица перевода текстурных координат в изометрическую камеру.  | ||||
| 		 */ | ||||
| 		alternativa3d var uvMatrix:Matrix; | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Нормаль плоскости | ||||
| 		 */ | ||||
| 		alternativa3d var globalNormal:Point3D = new Point3D(); | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Смещение плоскости | ||||
| 		 */		 | ||||
| 		alternativa3d var globalOffset:Number; | ||||
|  | ||||
| 		/** | ||||
| 		 * Создание экземпляра грани. | ||||
| 		 *  | ||||
| 		 * @param vertices массив объектов типа <code>alternativa.engine3d.core.Vertex</code>, задающий вершины грани в | ||||
| 		 * порядке обхода лицевой стороны грани против часовой стрелки. | ||||
| 		 *  | ||||
| 		 * @see Vertex | ||||
| 		 */				 | ||||
| 		public function Face(vertices:Array) { | ||||
| 			// Сохраняем вершины | ||||
| 			_vertices = vertices; | ||||
| 			_verticesCount = vertices.length; | ||||
|  | ||||
| 			// Создаём оригинальный примитив | ||||
| 			primitive = PolyPrimitive.createPolyPrimitive(); | ||||
| 			primitive.face = this; | ||||
| 			primitive.num = _verticesCount; | ||||
| 			 | ||||
| 			// Обрабатываем вершины | ||||
| 			for (var i:uint = 0; i < _verticesCount; i++) { | ||||
| 				var vertex:Vertex = vertices[i]; | ||||
| 				// Добавляем координаты вершины в примитив | ||||
| 				primitive.points.push(vertex.globalCoords); | ||||
| 				// Добавляем пустые UV-координаты в примитив | ||||
| 				primitive.uvs.push(null); | ||||
| 				// Добавляем вершину в грань | ||||
| 				vertex.addToFace(this); | ||||
| 			} | ||||
|  | ||||
| 			// Расчёт нормали | ||||
| 			calculateNormalOperation.addSequel(updatePrimitiveOperation); | ||||
| 			 | ||||
| 			// Расчёт UV грани инициирует расчёт UV фрагментов и перерисовку | ||||
| 			calculateUVOperation.addSequel(calculateFragmentsUVOperation); | ||||
| 			calculateUVOperation.addSequel(updateMaterialOperation); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт нормали в глобальных координатах | ||||
| 		 */ | ||||
| 		private function calculateNormal():void { | ||||
| 			// Вектор AB | ||||
| 			var vertex:Vertex = _vertices[0]; | ||||
| 			var av:Point3D = vertex.globalCoords; | ||||
| 			vertex = _vertices[1]; | ||||
| 			var bv:Point3D = vertex.globalCoords; | ||||
| 			var abx:Number = bv.x - av.x; | ||||
| 			var aby:Number = bv.y - av.y; | ||||
| 			var abz:Number = bv.z - av.z; | ||||
| 			// Вектор AC | ||||
| 			vertex = _vertices[2]; | ||||
| 			var cv:Point3D = vertex.globalCoords; | ||||
| 			var acx:Number = cv.x - av.x; | ||||
| 			var acy:Number = cv.y - av.y; | ||||
| 			var acz:Number = cv.z - av.z; | ||||
| 			// Перпендикуляр к плоскости | ||||
| 			globalNormal.x = acz*aby - acy*abz; | ||||
| 			globalNormal.y = acx*abz - acz*abx; | ||||
| 			globalNormal.z = acy*abx - acx*aby; | ||||
| 			// Нормализация перпендикуляра | ||||
| 			globalNormal.normalize(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчитывает глобальное смещение плоскости грани. | ||||
| 		 * Помечает конечные примитивы на удаление, а базовый на добавление в сцене.   | ||||
| 		 */ | ||||
| 		private function updatePrimitive():void { | ||||
| 			// Расчёт смещения | ||||
| 			var vertex:Vertex = _vertices[0]; | ||||
| 			globalOffset = vertex.globalCoords.x*globalNormal.x + vertex.globalCoords.y*globalNormal.y + vertex.globalCoords.z*globalNormal.z; | ||||
|  | ||||
| 			removePrimitive(primitive); | ||||
| 			primitive.mobility = _mesh.inheritedMobility; | ||||
| 			_mesh._scene.addPrimitives.push(primitive); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Рекурсивно проходит по фрагментам примитива и отправляет конечные фрагменты на удаление из сцены  | ||||
| 		 */ | ||||
| 		private function removePrimitive(primitive:PolyPrimitive):void { | ||||
| 			if (primitive.backFragment != null) { | ||||
| 				removePrimitive(primitive.backFragment); | ||||
| 				removePrimitive(primitive.frontFragment); | ||||
| 				primitive.backFragment = null; | ||||
| 				primitive.frontFragment = null; | ||||
| 				if (primitive != this.primitive) { | ||||
| 					primitive.parent = null; | ||||
| 					primitive.sibling = null; | ||||
| 					PolyPrimitive.destroyPolyPrimitive(primitive); | ||||
| 				} | ||||
| 			} else { | ||||
| 				// Если примитив в BSP-дереве | ||||
| 				if (primitive.node != null) { | ||||
| 					// Удаление примитива | ||||
| 					_mesh._scene.removeBSPPrimitive(primitive); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Пометка на перерисовку фрагментов грани. | ||||
| 		 */ | ||||
| 		private function updateMaterial():void { | ||||
| 			if (!updatePrimitiveOperation.queued) { | ||||
| 				changePrimitive(primitive); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Рекурсивно проходит по фрагментам примитива и отправляет конечные фрагменты на перерисовку | ||||
| 		 */ | ||||
| 		private function changePrimitive(primitive:PolyPrimitive):void { | ||||
| 			if (primitive.backFragment != null) { | ||||
| 				changePrimitive(primitive.backFragment); | ||||
| 				changePrimitive(primitive.frontFragment); | ||||
| 			} else { | ||||
| 				_mesh._scene.changedPrimitives[primitive] = true; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт UV-матрицы на основании первых трёх UV-координат. | ||||
| 		 * Расчёт UV-координат для оставшихся точек.  | ||||
| 		 */ | ||||
| 		private function calculateUV():void { | ||||
| 			var i:uint; | ||||
| 			// Расчёт UV-матрицы | ||||
| 			if (_aUV != null && _bUV != null && _cUV != null) { | ||||
| 				var abu:Number = _bUV.x - _aUV.x; | ||||
| 				var abv:Number = _bUV.y - _aUV.y; | ||||
| 				var acu:Number = _cUV.x - _aUV.x; | ||||
| 				var acv:Number = _cUV.y - _aUV.y; | ||||
| 				var det:Number = abu*acv - abv*acu; | ||||
| 				if (det != 0) { | ||||
| 					if (uvMatrixBase == null) { | ||||
| 						uvMatrixBase = new Matrix(); | ||||
| 						uvMatrix = new Matrix(); | ||||
| 					} | ||||
| 					uvMatrixBase.a = acv/det; | ||||
| 					uvMatrixBase.b = -abv/det; | ||||
| 					uvMatrixBase.c = -acu/det; | ||||
| 					uvMatrixBase.d = abu/det; | ||||
| 					uvMatrixBase.tx = -(uvMatrixBase.a*_aUV.x + uvMatrixBase.c*_aUV.y); | ||||
| 					uvMatrixBase.ty = -(uvMatrixBase.b*_aUV.x + uvMatrixBase.d*_aUV.y); | ||||
| 					 | ||||
| 					// Заполняем UV в базовом примитиве | ||||
| 					primitive.uvs[0] = _aUV; | ||||
| 					primitive.uvs[1] = _bUV; | ||||
| 					primitive.uvs[2] = _cUV; | ||||
| 					 | ||||
| 					// Расчёт недостающих UV | ||||
| 					if (_verticesCount > 3) { | ||||
| 						var a:Point3D = primitive.points[0]; | ||||
| 						var b:Point3D = primitive.points[1]; | ||||
| 						var c:Point3D = primitive.points[2]; | ||||
|  | ||||
| 						var ab1:Number; | ||||
| 						var ab2:Number; | ||||
| 						var ac1:Number; | ||||
| 						var ac2:Number; | ||||
| 						var ad1:Number; | ||||
| 						var ad2:Number; | ||||
| 						var abk:Number; | ||||
| 						var ack:Number; | ||||
| 						 | ||||
| 						var uv:Point; | ||||
| 						var point:Point3D; | ||||
| 						 | ||||
| 						// Выбор наиболее подходящих осей для расчёта | ||||
| 						if (((globalNormal.x < 0) ? -globalNormal.x : globalNormal.x) > ((globalNormal.y < 0) ? -globalNormal.y : globalNormal.y)) { | ||||
| 							if (((globalNormal.x < 0) ? -globalNormal.x : globalNormal.x) > ((globalNormal.z < 0) ? -globalNormal.z : globalNormal.z)) { | ||||
| 								// Ось X | ||||
| 								ab1 = b.y - a.y; | ||||
| 								ab2 = b.z - a.z; | ||||
| 								ac1 = c.y - a.y; | ||||
| 								ac2 = c.z - a.z; | ||||
| 								det = ab1*ac2 - ac1*ab2; | ||||
| 								for (i = 3; i < _verticesCount; i++) { | ||||
| 									point = primitive.points[i]; | ||||
| 									ad1 = point.y - a.y; | ||||
| 									ad2 = point.z - a.z; | ||||
| 									abk = (ad1*ac2 - ac1*ad2)/det; | ||||
| 									ack = (ab1*ad2 - ad1*ab2)/det; | ||||
| 									uv = primitive.uvs[i]; | ||||
| 									if (uv == null) { | ||||
| 										uv = new Point(); | ||||
| 										primitive.uvs[i] = uv; | ||||
| 									} | ||||
| 									uv.x = _aUV.x + abu*abk + acu*ack; | ||||
| 									uv.y = _aUV.y + abv*abk + acv*ack; | ||||
| 								} | ||||
| 							} else { | ||||
| 								// Ось Z | ||||
| 								ab1 = b.x - a.x; | ||||
| 								ab2 = b.y - a.y; | ||||
| 								ac1 = c.x - a.x; | ||||
| 								ac2 = c.y - a.y; | ||||
| 								det = ab1*ac2 - ac1*ab2; | ||||
| 								for (i = 3; i < _verticesCount; i++) { | ||||
| 									point = primitive.points[i]; | ||||
| 									ad1 = point.x - a.x; | ||||
| 									ad2 = point.y - a.y; | ||||
| 									abk = (ad1*ac2 - ac1*ad2)/det; | ||||
| 									ack = (ab1*ad2 - ad1*ab2)/det; | ||||
| 									uv = primitive.uvs[i]; | ||||
| 									if (uv == null) { | ||||
| 										uv = new Point(); | ||||
| 										primitive.uvs[i] = uv; | ||||
| 									} | ||||
| 									uv.x = _aUV.x + abu*abk + acu*ack; | ||||
| 									uv.y = _aUV.y + abv*abk + acv*ack; | ||||
| 								} | ||||
| 							} | ||||
| 						} else { | ||||
| 							if (((globalNormal.y < 0) ? -globalNormal.y : globalNormal.y) > ((globalNormal.z < 0) ? -globalNormal.z : globalNormal.z)) { | ||||
| 								// Ось Y | ||||
| 								ab1 = b.x - a.x; | ||||
| 								ab2 = b.z - a.z; | ||||
| 								ac1 = c.x - a.x; | ||||
| 								ac2 = c.z - a.z; | ||||
| 								det = ab1*ac2 - ac1*ab2; | ||||
| 								for (i = 3; i < _verticesCount; i++) { | ||||
| 									point = primitive.points[i]; | ||||
| 									ad1 = point.x - a.x; | ||||
| 									ad2 = point.z - a.z; | ||||
| 									abk = (ad1*ac2 - ac1*ad2)/det; | ||||
| 									ack = (ab1*ad2 - ad1*ab2)/det; | ||||
| 									uv = primitive.uvs[i]; | ||||
| 									if (uv == null) { | ||||
| 										uv = new Point(); | ||||
| 										primitive.uvs[i] = uv; | ||||
| 									} | ||||
| 									uv.x = _aUV.x + abu*abk + acu*ack; | ||||
| 									uv.y = _aUV.y + abv*abk + acv*ack; | ||||
| 								} | ||||
| 							} else { | ||||
| 								// Ось Z | ||||
| 								ab1 = b.x - a.x; | ||||
| 								ab2 = b.y - a.y; | ||||
| 								ac1 = c.x - a.x; | ||||
| 								ac2 = c.y - a.y; | ||||
| 								det = ab1*ac2 - ac1*ab2; | ||||
| 								for (i = 3; i < _verticesCount; i++) { | ||||
| 									point = primitive.points[i]; | ||||
| 									ad1 = point.x - a.x; | ||||
| 									ad2 = point.y - a.y; | ||||
| 									abk = (ad1*ac2 - ac1*ad2)/det; | ||||
| 									ack = (ab1*ad2 - ad1*ab2)/det; | ||||
| 									uv = primitive.uvs[i]; | ||||
| 									if (uv == null) { | ||||
| 										uv = new Point(); | ||||
| 										primitive.uvs[i] = uv; | ||||
| 									} | ||||
| 									uv.x = _aUV.x + abu*abk + acu*ack; | ||||
| 									uv.y = _aUV.y + abv*abk + acv*ack; | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					// Удаляем UV-матрицу | ||||
| 					uvMatrixBase = null; | ||||
| 					uvMatrix = null; | ||||
| 					// Удаляем UV-координаты из базового примитива | ||||
| 					for (i = 0; i < _verticesCount; i++) { | ||||
| 						primitive.uvs[i] = null; | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				// Удаляем UV-матрицу | ||||
| 				uvMatrixBase = null; | ||||
| 				uvMatrix = null; | ||||
| 				// Удаляем UV-координаты из базового примитива | ||||
| 				for (i = 0; i < _verticesCount; i++) { | ||||
| 					primitive.uvs[i] = null; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 * Расчёт UV-координат для фрагментов примитива, если не было трансформации | ||||
| 		 */ | ||||
| 		private function calculateFragmentsUV():void { | ||||
| 			// Если в этом цикле не было трансформации  | ||||
| 			if (!updatePrimitiveOperation.queued) { | ||||
| 				if (uvMatrixBase != null) { | ||||
| 					// Рассчитываем UV в примитиве  | ||||
| 					calculatePrimitiveUV(primitive); | ||||
| 				} else { | ||||
| 					// Удаляем UV в примитиве | ||||
| 					removePrimitiveUV(primitive); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт UV для точек базового примитива. | ||||
| 		 *  | ||||
| 		 * @param primitive | ||||
| 		 */ | ||||
| 		private function calculatePrimitiveUV(primitive:PolyPrimitive):void { | ||||
| 			if (primitive.backFragment	!= null) { | ||||
| 				var points:Array = primitive.points; | ||||
| 				var backPoints:Array = primitive.backFragment.points; | ||||
| 				var frontPoints:Array = primitive.frontFragment.points; | ||||
| 				var uvs:Array = primitive.uvs; | ||||
| 				var backUVs:Array = primitive.backFragment.uvs; | ||||
| 				var frontUVs:Array = primitive.frontFragment.uvs; | ||||
| 				var index1:uint = 0; | ||||
| 				var index2:uint = 0; | ||||
| 				var point:Point3D; | ||||
| 				var uv:Point; | ||||
| 				var uv1:Point; | ||||
| 				var uv2:Point; | ||||
| 				var t:Number; | ||||
| 				var firstSplit:Boolean = true; | ||||
| 				for (var i:uint = 0; i < primitive.num; i++) { | ||||
| 					var split:Boolean = true; | ||||
| 					point = points[i]; | ||||
| 					if (point == frontPoints[index2]) { | ||||
| 						if (frontUVs[index2] == null) { | ||||
| 							frontUVs[index2] = uvs[i]; | ||||
| 						} | ||||
| 						split = false; | ||||
| 						index2++; | ||||
| 					} | ||||
| 					if (point == backPoints[index1]) { | ||||
| 						if (backUVs[index1] == null) { | ||||
| 							backUVs[index1] = uvs[i]; | ||||
| 						} | ||||
| 						split = false; | ||||
| 						index1++; | ||||
| 					} | ||||
| 					 | ||||
|  					if (split) { | ||||
| 						uv1 = uvs[(i == 0) ? (primitive.num - 1) : (i - 1)]; | ||||
| 						uv2 = uvs[i]; | ||||
| 						t = (firstSplit) ? primitive.splitTime1 : primitive.splitTime2; | ||||
| 						uv = frontUVs[index2]; | ||||
| 						if (uv == null) { | ||||
| 							uv = new Point(uv1.x + (uv2.x - uv1.x)*t, uv1.y + (uv2.y - uv1.y)*t); | ||||
| 							frontUVs[index2] = uv; | ||||
| 							backUVs[index1] = uv; | ||||
| 						} else { | ||||
| 							uv.x = uv1.x + (uv2.x - uv1.x)*t; | ||||
| 							uv.y = uv1.y + (uv2.y - uv1.y)*t; | ||||
| 						} | ||||
| 						firstSplit = false; | ||||
| 						index2++; | ||||
| 						index1++; | ||||
| 						if (point == frontPoints[index2]) { | ||||
| 							if (frontUVs[index2] == null) { | ||||
| 								frontUVs[index2] = uvs[i]; | ||||
| 							} | ||||
| 							index2++; | ||||
| 						} | ||||
| 						if (point == backPoints[index1]) { | ||||
| 							if (backUVs[index1] == null) { | ||||
| 								backUVs[index1] = uvs[i]; | ||||
| 							} | ||||
| 							index1++; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				// Проверяем рассечение последнего ребра | ||||
| 				if (index2 < primitive.frontFragment.num) { | ||||
| 					uv1 = uvs[primitive.num - 1]; | ||||
| 					uv2 = uvs[0]; | ||||
| 					t = (firstSplit) ? primitive.splitTime1 : primitive.splitTime2; | ||||
| 					uv = frontUVs[index2]; | ||||
| 					if (uv == null) { | ||||
| 						uv = new Point(uv1.x + (uv2.x - uv1.x)*t, uv1.y + (uv2.y - uv1.y)*t); | ||||
| 						frontUVs[index2] = uv; | ||||
| 						backUVs[index1] = uv; | ||||
| 					} else { | ||||
| 						uv.x = uv1.x + (uv2.x - uv1.x)*t; | ||||
| 						uv.y = uv1.y + (uv2.y - uv1.y)*t; | ||||
| 					} | ||||
| 				} | ||||
| 				 | ||||
| 				calculatePrimitiveUV(primitive.backFragment); | ||||
| 				calculatePrimitiveUV(primitive.frontFragment); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Удаление UV в примитиве и его фрагментах | ||||
| 		 * @param primitive | ||||
| 		 */ | ||||
| 		private function removePrimitiveUV(primitive:PolyPrimitive):void { | ||||
| 			// Очищаем список UV | ||||
| 			for (var i:uint = 0; i < primitive.num; i++) { | ||||
| 				primitive.uvs[i] = null; | ||||
| 			} | ||||
| 			// Если есть фрагменты, удаляем UV в них | ||||
| 			if (primitive.backFragment != null) { | ||||
| 				removePrimitiveUV(primitive.backFragment); | ||||
| 				removePrimitiveUV(primitive.frontFragment); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Массив вершин грани, представленных объектами класса <code>alternativa.engine3d.core.Vertex</code>. | ||||
| 		 *  | ||||
| 		 * @see Vertex | ||||
| 		 */ | ||||
| 		public function get vertices():Array { | ||||
| 			return new Array().concat(_vertices); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Количество вершин грани.  | ||||
| 		 */ | ||||
| 		public function get verticesCount():uint { | ||||
| 			return _verticesCount; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Полигональный объект, которому принадлежит грань. | ||||
| 		 */ | ||||
| 		public function get mesh():Mesh { | ||||
| 			return _mesh; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Поверхность, которой принадлежит грань. | ||||
| 		 */ | ||||
| 		public function get surface():Surface { | ||||
| 			return _surface; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Идентификатор грани в полигональном объекте. В случае, если грань не принадлежит ни одному объекту, идентификатор | ||||
| 		 * имеет значение <code>null</code>. | ||||
| 		 */ | ||||
| 		public function get id():Object { | ||||
| 			return (_mesh != null) ? _mesh.getFaceId(this) : null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * UV-координаты, соответствующие первой вершине грани. | ||||
| 		 */ | ||||
| 		public function get aUV():Point { | ||||
| 			return (_aUV != null) ? _aUV.clone() : null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * UV-координаты, соответствующие второй вершине грани. | ||||
| 		 */ | ||||
| 		public function get bUV():Point { | ||||
| 			return (_bUV != null) ? _bUV.clone() : null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * UV-координаты, соответствующие третьей вершине грани. | ||||
| 		 */ | ||||
| 		public function get cUV():Point { | ||||
| 			return (_cUV != null) ? _cUV.clone() : null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		public function set aUV(value:Point):void { | ||||
| 			if (_aUV != null) { | ||||
| 				if (value != null) { | ||||
| 					if (!_aUV.equals(value)) {   | ||||
| 						_aUV.x = value.x; | ||||
| 						_aUV.y = value.y; | ||||
| 						if (_mesh != null) { | ||||
| 							_mesh.addOperationToScene(calculateUVOperation); | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					_aUV = null; | ||||
| 					if (_mesh != null) { | ||||
| 						_mesh.addOperationToScene(calculateUVOperation); | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (value != null) { | ||||
| 					_aUV = value.clone(); | ||||
| 					if (_mesh != null) { | ||||
| 						_mesh.addOperationToScene(calculateUVOperation); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		public function set bUV(value:Point):void { | ||||
| 			if (_bUV != null) { | ||||
| 				if (value != null) { | ||||
| 					if (!_bUV.equals(value)) {   | ||||
| 						_bUV.x = value.x; | ||||
| 						_bUV.y = value.y; | ||||
| 						if (_mesh != null) { | ||||
| 							_mesh.addOperationToScene(calculateUVOperation); | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					_bUV = null; | ||||
| 					if (_mesh != null) { | ||||
| 						_mesh.addOperationToScene(calculateUVOperation); | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (value != null) { | ||||
| 					_bUV = value.clone(); | ||||
| 					if (_mesh != null) { | ||||
| 						_mesh.addOperationToScene(calculateUVOperation); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		public function set cUV(value:Point):void { | ||||
| 			if (_cUV != null) { | ||||
| 				if (value != null) { | ||||
| 					if (!_cUV.equals(value)) {   | ||||
| 						_cUV.x = value.x; | ||||
| 						_cUV.y = value.y; | ||||
| 						if (_mesh != null) { | ||||
| 							_mesh.addOperationToScene(calculateUVOperation); | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					_cUV = null; | ||||
| 					if (_mesh != null) { | ||||
| 						_mesh.addOperationToScene(calculateUVOperation); | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (value != null) { | ||||
| 					_cUV = value.clone(); | ||||
| 					if (_mesh != null) { | ||||
| 						_mesh.addOperationToScene(calculateUVOperation); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Нормаль в локальной системе координат. | ||||
| 		 */ | ||||
| 		public function get normal():Point3D { | ||||
| 			var res:Point3D = new Point3D(); | ||||
| 			var vertex:Vertex = _vertices[0]; | ||||
| 			var av:Point3D = vertex.coords; | ||||
| 			vertex = _vertices[1]; | ||||
| 			var bv:Point3D = vertex.coords; | ||||
| 			var abx:Number = bv.x - av.x; | ||||
| 			var aby:Number = bv.y - av.y; | ||||
| 			var abz:Number = bv.z - av.z; | ||||
| 			vertex = _vertices[2]; | ||||
| 			var cv:Point3D = vertex.coords; | ||||
| 			var acx:Number = cv.x - av.x; | ||||
| 			var acy:Number = cv.y - av.y; | ||||
| 			var acz:Number = cv.z - av.z; | ||||
| 			res.x = acz*aby - acy*abz; | ||||
| 			res.y = acx*abz - acz*abx; | ||||
| 			res.z = acy*abx - acx*aby; | ||||
| 			if (res.x != 0 || res.y != 0 || res.z != 0) { | ||||
| 				var k:Number = Math.sqrt(res.x*res.x + res.y*res.y + res.z*res.z); | ||||
| 				res.x /= k; | ||||
| 				res.y /= k; | ||||
| 				res.z /= k; | ||||
| 			} | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Расчёт UV-координат для произвольной точки в системе координат объекта, которому принадлежит грань. | ||||
| 		 *  | ||||
| 		 * @param point точка в плоскости грани, для которой производится расчёт UV-координат | ||||
| 		 * @return UV-координаты заданной точки | ||||
| 		 */		 | ||||
| 		public function getUV(point:Point3D):Point { | ||||
| 			return getUVFast(point, normal); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Расчёт UV-координат для произвольной точки в локальной системе координат без расчёта  | ||||
| 		 * локальной нормали грани. Используется для оптимизации. | ||||
| 		 *  | ||||
| 		 * @param point точка в плоскости грани, для которой производится расчёт UV-координат | ||||
| 		 * @param normal нормаль плоскости грани в локальной системе координат | ||||
| 		 * @return UV-координаты заданной точки | ||||
| 		 */ | ||||
| 		alternativa3d function getUVFast(point:Point3D, normal:Point3D):Point { | ||||
| 			if (_aUV == null || _bUV == null || _cUV == null) { | ||||
| 				return null; | ||||
| 			} | ||||
|  | ||||
| 			// Выбор наиболее длинной оси нормали | ||||
| 			var dir:uint;  | ||||
| 			if (((normal.x < 0) ? -normal.x : normal.x) > ((normal.y < 0) ? -normal.y : normal.y)) { | ||||
| 				if (((normal.x < 0) ? -normal.x : normal.x) > ((normal.z < 0) ? -normal.z : normal.z)) { | ||||
| 					dir = 0; | ||||
| 				} else { | ||||
| 					dir = 2; | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (((normal.y < 0) ? -normal.y : normal.y) > ((normal.z < 0) ? -normal.z : normal.z)) { | ||||
| 					dir = 1; | ||||
| 				} else { | ||||
| 					dir = 2; | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			// Расчёт соотношения по векторам AB и AC | ||||
| 			var v:Vertex = _vertices[0]; | ||||
| 			var a:Point3D = v._coords; | ||||
| 			v = _vertices[1]; | ||||
| 			var b:Point3D = v._coords; | ||||
| 			v = _vertices[2]; | ||||
| 			var c:Point3D = v._coords; | ||||
| 						 | ||||
| 			var ab1:Number = (dir == 0) ? (b.y - a.y) : (b.x - a.x); | ||||
| 			var ab2:Number = (dir == 2) ? (b.y - a.y) : (b.z - a.z); | ||||
| 			var ac1:Number = (dir == 0) ? (c.y - a.y) : (c.x - a.x); | ||||
| 			var ac2:Number = (dir == 2) ? (c.y - a.y) : (c.z - a.z); | ||||
| 			var det:Number = ab1*ac2 - ac1*ab2; | ||||
| 				 | ||||
| 			var ad1:Number = (dir == 0) ? (point.y - a.y) : (point.x - a.x); | ||||
| 			var ad2:Number = (dir == 2) ? (point.y - a.y) : (point.z - a.z); | ||||
| 			var abk:Number = (ad1*ac2 - ac1*ad2)/det; | ||||
| 			var ack:Number = (ab1*ad2 - ad1*ab2)/det; | ||||
| 			 | ||||
| 			// Интерполяция по UV первых точек | ||||
| 			var abu:Number = _bUV.x - _aUV.x; | ||||
| 			var abv:Number = _bUV.y - _aUV.y; | ||||
| 			var acu:Number = _cUV.x - _aUV.x; | ||||
| 			var acv:Number = _cUV.y - _aUV.y; | ||||
| 							 | ||||
| 			return new Point(_aUV.x + abu*abk + acu*ack, _aUV.y + abv*abk + acv*ack); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Множество граней, имеющих общие рёбра с текущей гранью. | ||||
| 		 */ | ||||
| 		public function get edgeJoinedFaces():Set { | ||||
| 			var res:Set = new Set(true); | ||||
| 			// Перебираем точки грани | ||||
| 			for (var i:uint = 0; i < _verticesCount; i++) { | ||||
| 				var a:Vertex = _vertices[i]; | ||||
| 				var b:Vertex = _vertices[(i < _verticesCount - 1) ? (i + 1) : 0]; | ||||
| 				 | ||||
| 				// Перебираем грани текущей точки | ||||
| 				for (var key:* in a._faces) { | ||||
| 					var face:Face = key; | ||||
| 					// Если это другая грань и у неё также есть следующая точка | ||||
| 					if (face != this && face._vertices.indexOf(b) >= 0) { | ||||
| 						// Значит у граней общее ребро | ||||
| 						res[face] = true; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Удаление всех вершин из грани. | ||||
| 		 * Очистка базового примитива.  | ||||
| 		 */ | ||||
| 		alternativa3d function removeVertices():void { | ||||
| 			// Удалить вершины | ||||
| 			for (var i:uint = 0; i < _verticesCount; i++) { | ||||
| 				// Удаляем из списка | ||||
| 				var vertex:Vertex = _vertices.pop(); | ||||
| 				// Удаляем координаты вершины из примитива | ||||
| 				primitive.points.pop(); | ||||
| 				// Удаляем вершину из грани | ||||
| 				vertex.removeFromFace(this); | ||||
| 			} | ||||
| 			// Обнуляем количество вершин | ||||
| 			_verticesCount = 0; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Добавление грани на сцену  | ||||
| 		 * @param scene | ||||
| 		 */ | ||||
| 		alternativa3d function addToScene(scene:Scene3D):void { | ||||
| 			// При добавлении на сцену рассчитываем плоскость и UV | ||||
| 			scene.addOperation(calculateNormalOperation); | ||||
| 			scene.addOperation(calculateUVOperation); | ||||
| 			 | ||||
| 			// Подписываем сцену на операции | ||||
| 			updatePrimitiveOperation.addSequel(scene.calculateBSPOperation); | ||||
| 			updateMaterialOperation.addSequel(scene.changePrimitivesOperation); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Удаление грани из сцены | ||||
| 		 * @param scene | ||||
| 		 */ | ||||
| 		alternativa3d function removeFromScene(scene:Scene3D):void { | ||||
| 			// Удаляем все операции из очереди | ||||
| 			scene.removeOperation(calculateUVOperation); | ||||
| 			scene.removeOperation(calculateFragmentsUVOperation); | ||||
| 			scene.removeOperation(calculateNormalOperation); | ||||
| 			scene.removeOperation(updatePrimitiveOperation); | ||||
| 			scene.removeOperation(updateMaterialOperation); | ||||
|  | ||||
| 			// Удаляем примитивы из сцены | ||||
| 			removePrimitive(primitive); | ||||
|  | ||||
| 			// Посылаем операцию сцены на расчёт BSP | ||||
| 			scene.addOperation(scene.calculateBSPOperation); | ||||
| 					 | ||||
| 			// Отписываем сцену от операций | ||||
| 			updatePrimitiveOperation.removeSequel(scene.calculateBSPOperation); | ||||
| 			updateMaterialOperation.removeSequel(scene.changePrimitivesOperation); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Добавление грани в меш | ||||
| 		 * @param mesh | ||||
| 		 */ | ||||
| 		alternativa3d function addToMesh(mesh:Mesh):void { | ||||
| 			// Подписка на операции меша | ||||
| 			mesh.changeCoordsOperation.addSequel(updatePrimitiveOperation); | ||||
| 			mesh.changeRotationOrScaleOperation.addSequel(calculateNormalOperation); | ||||
| 			mesh.calculateMobilityOperation.addSequel(updatePrimitiveOperation); | ||||
| 			// Сохранить меш | ||||
| 			_mesh = mesh; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Удаление грани из меша | ||||
| 		 * @param mesh | ||||
| 		 */ | ||||
| 		alternativa3d function removeFromMesh(mesh:Mesh):void { | ||||
| 			// Отписка от операций меша | ||||
| 			mesh.changeCoordsOperation.removeSequel(updatePrimitiveOperation); | ||||
| 			mesh.changeRotationOrScaleOperation.removeSequel(calculateNormalOperation); | ||||
| 			mesh.calculateMobilityOperation.removeSequel(updatePrimitiveOperation); | ||||
| 			// Удалить ссылку на меш | ||||
| 			_mesh = null; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Добавление к поверхности | ||||
| 		 *  | ||||
| 		 * @param surface | ||||
| 		 */		 | ||||
| 		alternativa3d function addToSurface(surface:Surface):void { | ||||
| 			// Подписка поверхности на операции | ||||
| 			surface.changeMaterialOperation.addSequel(updateMaterialOperation); | ||||
| 			// Если при смене поверхности изменился материал | ||||
| 			if (_mesh != null && (_surface != null && _surface._material != surface._material || _surface == null && surface._material != null)) { | ||||
| 				// Отправляем сигнал смены материала | ||||
| 				_mesh.addOperationToScene(updateMaterialOperation); | ||||
| 			} | ||||
| 			// Сохранить поверхность | ||||
| 			_surface = surface; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 * Удаление из поверхности | ||||
| 		 *  | ||||
| 		 * @param surface | ||||
| 		 */		 | ||||
| 		alternativa3d function removeFromSurface(surface:Surface):void { | ||||
| 			// Отписка поверхности от операций | ||||
| 			surface.changeMaterialOperation.removeSequel(updateMaterialOperation); | ||||
| 			// Если был материал | ||||
| 			if (surface._material != null) { | ||||
| 				// Отправляем сигнал смены материала | ||||
| 				_mesh.addOperationToScene(updateMaterialOperation); | ||||
| 			} | ||||
| 			// Удалить ссылку на поверхность | ||||
| 			_surface = null; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Строковое представление объекта. | ||||
| 		 *  | ||||
| 		 * @return строковое представление объекта | ||||
| 		 */ | ||||
| 		public function toString():String { | ||||
| 			var res:String = "[Face ID:" + id + ((_verticesCount > 0) ? " vertices:" : ""); | ||||
| 			for (var i:uint = 0; i < _verticesCount; i++) { | ||||
| 				var vertex:Vertex = _vertices[i]; | ||||
| 				res += vertex.id + ((i < _verticesCount - 1) ? ", " : ""); | ||||
| 			} | ||||
| 			res += "]"; | ||||
| 			return res; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Tubix
					Tubix