mirror of
https://github.com/MapMakersAndProgrammers/alternativa3d-archive.git
synced 2025-10-26 09:49:07 -07:00
144 lines
7.1 KiB
ActionScript
144 lines
7.1 KiB
ActionScript
package alternativa.engine3d.primitives {
|
||
import alternativa.engine3d.*;
|
||
import alternativa.engine3d.core.Mesh;
|
||
import alternativa.engine3d.core.Object3D;
|
||
import alternativa.engine3d.core.Surface;
|
||
import alternativa.engine3d.core.Vertex;
|
||
import alternativa.utils.MathUtils;
|
||
import alternativa.engine3d.core.Face;
|
||
import flash.geom.Point;
|
||
|
||
use namespace alternativa3d;
|
||
|
||
/**
|
||
* Сфера.
|
||
*/
|
||
public class Sphere extends Mesh {
|
||
|
||
/**
|
||
* Создает сферу.
|
||
* <p>После создания примитив содержит в себе одну поверхность с идентификатором по умолчанию.</p>
|
||
* <p>По умолчанию параметр <code>triangulate</code> установлен в <code>false</code> и на сферу нельзя наложить текстуру.
|
||
* Только при установленном <code>triangulate</code> в <code>true</code> это возможно.</p>
|
||
*
|
||
* @param radius Радиус сферы. Не может быть меньше нуля.
|
||
* @param radialSegments количество сегментов по экватору сферы
|
||
* @param heightSegments количество сегментов по высоте
|
||
* @param reverse флаг инвертирования нормалей. При параметре установленном в <code>true</code> нормали направлены внутрь сферы.
|
||
* @param triangulate флаг триангуляции. Если указано значение <code>true</code>, грани будут триангулированы,
|
||
* и будет возможно наложить на примитив текстуру.
|
||
*/
|
||
public function Sphere(radius:Number = 100, radialSegments:uint = 8, heightSegments:uint = 8, reverse:Boolean = false, triangulate:Boolean = false) {
|
||
if ((radialSegments < 3) || (heightSegments < 2)) {
|
||
return;
|
||
}
|
||
radius = (radius < 0)? 0 : radius;
|
||
|
||
var poleUp:Vertex = createVertex(0, 0, radius, "poleUp");
|
||
var poleDown:Vertex = createVertex(0, 0, -radius, "poleDown");
|
||
|
||
const radialAngle:Number = MathUtils.DEG360/radialSegments;
|
||
const heightAngle:Number = MathUtils.DEG360/(heightSegments << 1);
|
||
|
||
var radial:uint;
|
||
var segment:uint;
|
||
|
||
// Создание вершин
|
||
for (segment = 1; segment < heightSegments; segment++) {
|
||
var currentHeightAngle:Number = heightAngle*segment;
|
||
var segmentRadius:Number = Math.sin(currentHeightAngle)*radius;
|
||
var segmentZ:Number = Math.cos(currentHeightAngle)*radius;
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
var currentRadialAngle:Number = radialAngle*radial;
|
||
createVertex(-Math.sin(currentRadialAngle)*segmentRadius, Math.cos(currentRadialAngle)*segmentRadius, segmentZ, radial + "_" + segment);
|
||
}
|
||
}
|
||
|
||
// Создание граней и поверхности
|
||
var surface:Surface = createSurface();
|
||
|
||
var prevRadial:uint = radialSegments - 1;
|
||
var lastSegmentString:String = "_" + (heightSegments - 1);
|
||
|
||
var uStep:Number = 1/radialSegments;
|
||
var vStep:Number = 1/heightSegments;
|
||
|
||
var face:Face;
|
||
|
||
// Для триангуляции
|
||
var aUV:Point;
|
||
var cUV:Point;
|
||
|
||
var u:Number;
|
||
|
||
if (reverse) {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
// Грани верхнего полюса
|
||
surface.addFace(createFace([poleUp, radial + "_1", prevRadial + "_1"], prevRadial + "_0"));
|
||
// Грани нижнего полюса
|
||
surface.addFace(createFace([radial + lastSegmentString, poleDown, prevRadial + lastSegmentString], prevRadial + lastSegmentString));
|
||
|
||
// Если включена триангуляция
|
||
if (triangulate) {
|
||
// Триангулируем середину и просчитываем маппинг
|
||
u = uStep*prevRadial;
|
||
setUVsToFace(new Point(1 - u, 1), new Point(1 - u - uStep, 1 - vStep), new Point(1 - u, 1 - vStep), prevRadial + "_0");
|
||
// Грани середки
|
||
for (segment = 1; segment < (heightSegments - 1); segment++) {
|
||
aUV = new Point(1 - u - uStep, 1 - (vStep*(segment + 1)));
|
||
cUV = new Point(1 - u, 1 - vStep*segment);
|
||
surface.addFace(createFace([radial + "_" + (segment + 1), prevRadial + "_" + (segment + 1), prevRadial + "_" + segment], prevRadial + "_" + segment + ":0"));
|
||
surface.addFace(createFace([prevRadial + "_" + segment, radial + "_" + segment, radial + "_" + (segment + 1)], prevRadial + "_" + segment + ":1"));
|
||
setUVsToFace(aUV, new Point(1 - u, 1 - (vStep*(segment + 1))), cUV, prevRadial + "_" + segment + ":0");
|
||
setUVsToFace(cUV, new Point(1 - u - uStep, 1 - (vStep*segment)), aUV, prevRadial + "_" + segment + ":1");
|
||
}
|
||
setUVsToFace(new Point(1 - u - uStep, vStep), new Point(1 - u, 0), new Point(1 - u, vStep), prevRadial + lastSegmentString);
|
||
|
||
} else {
|
||
// Просто создаем середину
|
||
// Грани середки
|
||
for (segment = 1; segment < (heightSegments - 1); segment++) {
|
||
surface.addFace(createFace([radial + "_" + (segment + 1), prevRadial + "_" + (segment + 1), prevRadial + "_" + segment, radial + "_" + segment], prevRadial + "_" + segment));
|
||
}
|
||
}
|
||
prevRadial = (radial == 0) ? 0 : prevRadial + 1;
|
||
}
|
||
} else {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
// Грани верхнего полюса
|
||
surface.addFace(createFace([poleUp, prevRadial + "_1", radial + "_1"], prevRadial + "_0"));
|
||
// Грани нижнего полюса
|
||
surface.addFace(createFace([prevRadial + lastSegmentString, poleDown, radial + lastSegmentString], prevRadial + lastSegmentString));
|
||
|
||
if (triangulate) {
|
||
u = uStep*prevRadial;
|
||
setUVsToFace(new Point(u, 1), new Point(u, 1 - vStep), new Point(u + uStep, 1 - vStep), prevRadial + "_0");
|
||
// Грани середки
|
||
for (segment = 1; segment < (heightSegments - 1); segment++) {
|
||
aUV = new Point(u, 1 - (vStep*segment));
|
||
cUV = new Point(u + uStep, 1 - vStep * (segment + 1));
|
||
surface.addFace(createFace([prevRadial + "_" + segment, prevRadial + "_" + (segment + 1), radial + "_" + (segment + 1)], prevRadial + "_" + segment + ":0"));
|
||
surface.addFace(createFace([radial + "_" + (segment + 1), radial + "_" + segment, prevRadial + "_" + segment], prevRadial + "_" + segment + ":1"));
|
||
setUVsToFace(aUV, new Point(u, 1 - (vStep*(segment + 1))), cUV, prevRadial + "_" + segment + ":0");
|
||
setUVsToFace(cUV, new Point(u + uStep, 1 - (vStep*segment)), aUV, prevRadial + "_" + segment + ":1");
|
||
}
|
||
setUVsToFace(new Point(u, vStep), new Point(u, 0), new Point(u + uStep, vStep), prevRadial + lastSegmentString);
|
||
} else {
|
||
// Грани середки
|
||
for (segment = 1; segment < (heightSegments - 1); segment++) {
|
||
surface.addFace(createFace([prevRadial + "_" + segment, prevRadial + "_" + (segment + 1), radial + "_" + (segment + 1), radial + "_" + segment], prevRadial + "_" + segment));
|
||
}
|
||
}
|
||
prevRadial = (radial == 0) ? 0 : prevRadial + 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @inheritDoc
|
||
*/
|
||
protected override function createEmptyObject():Object3D {
|
||
return new Sphere(0, 0);
|
||
}
|
||
}
|
||
} |