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 указывает методу создать обе поверхности.
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);
}
}
}