package alternativa.engine3d.primitives { import alternativa.engine3d.*; import alternativa.engine3d.core.Face; import alternativa.engine3d.core.Mesh; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Surface; import flash.geom.Point; use namespace alternativa3d; /** * Геоплоскость. */ public class GeoPlane extends Mesh { /** * Создает геоплоскость. *

Геоплоскость это плоскость с сетчатой структурой граней.

*

Примитив после создания содержит в cебе одну или две поверхности, в зависимости от значения параметров. * При значении reverse установленном в true примитив будет содержать грань - "back". * При значении reverse установленном в false примитив будет содержать грань - "front". * Параметр twoSided указывает методу создать обе поверхности.

* * @param width ширина. Размерность по оси X. Не может быть меньше нуля. * @param length длина. Размерность по оси Y. Не может быть меньше нуля. * @param widthSegments количество сегментов по ширине * @param lengthSegments количество сегментов по длине * @param twoSided если значение параметра равно true, то создаётся двусторонняя поверхность * @param reverse флаг инвертирования нормалей */ public function GeoPlane(width:Number = 100, length:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, twoSided:Boolean = true, reverse:Boolean = false) { super(); if ((widthSegments == 0) || (lengthSegments == 0)) { return; } width = (width < 0)? 0 : width; length = (length < 0)? 0 : length; // Середина var wh:Number = width/2; var hh:Number = length/2; // Размеры сегмента var ws:Number = width/widthSegments; var hs:Number = length/lengthSegments; // Размеры UV-сегмента var us:Number = 1/widthSegments; var vs:Number = 1/lengthSegments; // Создание точек var x:uint; var y:uint; var frontUV:Array = new Array(); var backUV:Array = ((lengthSegments & 1) == 0) ? null : new Array(); for (y = 0; y <= lengthSegments; y++) { frontUV[y] = new Array(); if (backUV != null) { backUV[y] = new Array(); } for (x = 0; x <= widthSegments; x++) { if ((y & 1) == 0) { // Если чётный ряд createVertex(x*ws - wh, y*hs - hh, 0, y + "_" + x); frontUV[y][x] = new Point(x*us, y*vs); if (backUV != null) { backUV[y][x] = new Point(x*us, 1 - y*vs); } } else { // Если нечётный ряд if (x == 0) { // Первая точка createVertex(-wh, y*hs - hh, 0, y + "_" + x); frontUV[y][x] = new Point(0, y*vs); if (backUV != null) { backUV[y][x] = new Point(0, 1 - y*vs); } } else { createVertex(x*ws - wh - ws/2, y*hs - hh, 0, y + "_" + x); frontUV[y][x] = new Point((x - 0.5)*us, y*vs); if (backUV != null) { backUV[y][x] = new Point((x - 0.5)*us, 1 - y*vs); } if (x == widthSegments) { // Последняя точка createVertex(wh, y*hs - hh, 0, y + "_" + (x + 1)); frontUV[y][x + 1] = new Point(1, y*vs); if (backUV != null) { backUV[y][x + 1] = new Point(1, 1 - y*vs); } } } } } } // Создание поверхностей var front:Surface; var back:Surface; if (twoSided || !reverse) { front = createSurface(null, "front"); } if (twoSided || reverse) { back = createSurface(null, "back"); } // Создание полигонов var face:Face; for (y = 0; y < lengthSegments; y++) { for (var n:uint = 0; n <= (widthSegments << 1); n++) { x = n >> 1; if ((y & 1) == 0) { // Если чётный ряд if ((n & 1) == 0) { // Если остриём вверх if (twoSided || !reverse) { face = createFace([y + "_" + x, (y + 1) + "_" + (x + 1), (y + 1) + "_" + x]); setUVsToFace(frontUV[y][x], frontUV[y + 1][x + 1], frontUV[y + 1][x], face); front.addFace(face); } if (twoSided || reverse) { face = createFace([y + "_" + x, (y + 1) + "_" + x, (y + 1) + "_" + (x + 1)]); if (backUV != null) { setUVsToFace(backUV[y][x], backUV[y + 1][x], backUV[y + 1][x + 1], face); } else { setUVsToFace(frontUV[lengthSegments - y][x], frontUV[lengthSegments - y - 1][x], frontUV[lengthSegments - y - 1][x + 1], face); } back.addFace(face); } } else { // Если остриём вниз if (twoSided || !reverse) { face = createFace([y + "_" + x, y + "_" + (x + 1), (y + 1) + "_" + (x + 1)]); setUVsToFace(frontUV[y][x], frontUV[y][x + 1], frontUV[y + 1][x + 1], face); front.addFace(face); } if (twoSided || reverse) { face = createFace([y + "_" + x, (y + 1) + "_" + (x + 1), y + "_" + (x + 1)]); if (backUV != null) { setUVsToFace(backUV[y][x], backUV[y + 1][x + 1], backUV[y][x + 1], face); } else { setUVsToFace(frontUV[lengthSegments - y][x], frontUV[lengthSegments - y - 1][x + 1], frontUV[lengthSegments - y][x + 1], face); } back.addFace(face); } } } else { // Если нечётный ряд if ((n & 1) == 0) { // Если остриём вниз if (twoSided || !reverse) { face = createFace([y + "_" + x, y + "_" + (x + 1), (y + 1) + "_" + x]); setUVsToFace(frontUV[y][x], frontUV[y][x + 1], frontUV[y + 1][x], face); front.addFace(face); } if (twoSided || reverse) { face = createFace([y + "_" + x, (y + 1) + "_" + x, y + "_" + (x + 1)]); if (backUV != null) { setUVsToFace(backUV[y][x], backUV[y + 1][x], backUV[y][x + 1], face); } else { setUVsToFace(frontUV[lengthSegments - y][x], frontUV[lengthSegments - y - 1][x], frontUV[lengthSegments - y][x + 1], face); } back.addFace(face); } } else { // Если остриём вверх if (twoSided || !reverse) { face = createFace([y + "_" + (x + 1), (y + 1) + "_" + (x + 1), (y + 1) + "_" + x]); setUVsToFace(frontUV[y][x+1], frontUV[y + 1][x + 1], frontUV[y + 1][x], face); front.addFace(face); } if (twoSided || reverse) { face = createFace([y + "_" + (x + 1), (y + 1) + "_" + x, (y + 1) + "_" + (x + 1)]); if (backUV != null) { setUVsToFace(backUV[y][x + 1], backUV[y + 1][x], backUV[y + 1][x + 1], face); } else { setUVsToFace(frontUV[lengthSegments - y][x + 1], frontUV[lengthSegments - y - 1][x], frontUV[lengthSegments - y - 1][x + 1], face); } back.addFace(face); } } } } } } /** * @inheritDoc */ protected override function createEmptyObject():Object3D { return new GeoPlane(0, 0, 0); } } }