mirror of
https://github.com/MapMakersAndProgrammers/alternativa3d-archive.git
synced 2025-10-26 09:49:07 -07:00
264 lines
12 KiB
ActionScript
264 lines
12 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 Cone extends Mesh {
|
||
|
||
/**
|
||
* Создает примитив усеченный конус или цилиндр.
|
||
* <p>Различные значения параметров позволяют создавать различные примитивы.
|
||
* Так при установленном параметре <code>topRadius = 0</code> или <code>bottomRadius = 0</code> будет построен конус. При установленном </code>bottomRadius = topRadius</code> будет построен цилиндр.</p>
|
||
* <p>По умолчанию параметр <code>triangulate</code> установлен в <code>false</code> и на примитив не может быть наложена текстура.
|
||
* Только при установленном параметре <code>triangulate</code> в <code>true</code> это возможно.</p>
|
||
* <p>После создания примитив всегда содержит в себе поверхность <code>"side"</code>.
|
||
* При установленном параметре <code>bottomRadius</code> не равном нулю в примитиве создается поверхность <code>"bottom"</code>,
|
||
* при установленном параметре <code>topRadius</code> в примитиве создается поверхность <code>"top"</code>.
|
||
* На каждую из поверхностей может быть наложен свой материал</p>
|
||
*
|
||
* @param height высота примтива. Размерность по оси Z. Не может быть меньше нуля.
|
||
* @param bottomRadius нижний радиус примитива
|
||
* @param topRadius верхний радиус примтива
|
||
* @param heightSegments количество сегментов по высоте примитива
|
||
* @param radialSegments количество сегментов по радиусу примтива
|
||
* @param reverse задает направление нормалей. При значении <code>true</code> нормли будут направлены внутрь примитива.
|
||
* @param triangulate флаг триангуляции. При значении <code>true</code> все четырехугольные грани примитива будут триангулированы
|
||
* и появится возможность наложить на примитив текстуру.
|
||
*/
|
||
public function Cone(height:Number = 100, bottomRadius:Number = 100, topRadius:Number = 0, heightSegments:uint = 1, radialSegments:uint = 12, reverse:Boolean = false, triangulate:Boolean = false) {
|
||
|
||
if ((radialSegments < 3) || (heightSegments < 1) || (heightSegments == 1 && topRadius == 0 && bottomRadius == 0)) {
|
||
return;
|
||
}
|
||
height = (height < 0)? 0 : height;
|
||
bottomRadius = (bottomRadius < 0)? 0 : bottomRadius;
|
||
topRadius = (topRadius < 0)? 0 : topRadius;
|
||
|
||
const radialSegment:Number = MathUtils.DEG360/radialSegments;
|
||
const radiusSegment:Number = (bottomRadius - topRadius)/heightSegments;
|
||
const heightSegment:Number = height/heightSegments;
|
||
const halfHeight:Number = height*0.5
|
||
const uSegment:Number = 1/radialSegments;
|
||
const vSegment:Number = 1/heightSegments;
|
||
|
||
// Создание вершин
|
||
if (topRadius == 0 || triangulate) {
|
||
var poleUp:Vertex = createVertex(0, 0, halfHeight, "poleUp");
|
||
}
|
||
if (bottomRadius == 0 || triangulate) {
|
||
var poleDown:Vertex = createVertex(0, 0, -halfHeight, "poleDown");
|
||
}
|
||
|
||
var radial:uint;
|
||
var segment:uint;
|
||
|
||
var topSegment:uint = heightSegments - int(topRadius == 0);
|
||
var bottomSegment:uint = int(bottomRadius == 0) ;
|
||
for (segment = bottomSegment; segment <= topSegment; segment++) {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
var currentAngle:Number = radialSegment*radial;
|
||
var currentRadius:Number = bottomRadius - (radiusSegment*segment);
|
||
createVertex(Math.cos(currentAngle)*currentRadius, Math.sin(currentAngle)*currentRadius, heightSegment*segment - halfHeight, radial + "_" + segment);
|
||
}
|
||
}
|
||
|
||
// Создание граней и поверхности
|
||
var face:Face;
|
||
|
||
var points:Array;
|
||
|
||
var side:Surface = createSurface(null, "side");
|
||
|
||
if (topRadius == 0) {
|
||
// Создание граней у верхнего полюса
|
||
var prevRadial:uint = radialSegments - 1;
|
||
var centerUV:Point = new Point(0.5, 1);
|
||
var v:Number = topSegment*vSegment;
|
||
if (reverse) {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleUp, radial + "_" + topSegment, prevRadial + "_" + topSegment], prevRadial + "_" + topSegment);
|
||
if (triangulate) {
|
||
setUVsToFace(centerUV, new Point(1 - (prevRadial + 1)*uSegment, v) , new Point(1 - prevRadial*uSegment, v), face);
|
||
}
|
||
side.addFace(face);
|
||
prevRadial = radial;
|
||
}
|
||
} else {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleUp, prevRadial + "_" + topSegment, radial + "_" + topSegment], prevRadial + "_" + topSegment);
|
||
if (triangulate) {
|
||
setUVsToFace(centerUV, new Point(prevRadial*uSegment, v), new Point((prevRadial + 1)*uSegment, v), face);
|
||
}
|
||
side.addFace(face);
|
||
prevRadial = radial;
|
||
}
|
||
}
|
||
} else {
|
||
// Создание граней верхней крышки
|
||
var top:Surface = createSurface(null, "top");
|
||
if (triangulate) {
|
||
prevRadial = radialSegments - 1;
|
||
centerUV = new Point(0.5, 0.5);
|
||
var UV:Point;
|
||
var prevUV:Point;
|
||
if (reverse) {
|
||
prevUV = new Point(0.5 - Math.cos(-radialSegment)*0.5, Math.sin(-radialSegment)*0.5 + 0.5);
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleUp, radial + "_" + topSegment, prevRadial + "_" + topSegment], "top_" + prevRadial);
|
||
currentAngle = radial * radialSegment;
|
||
UV = new Point(0.5 - Math.cos(currentAngle)*0.5, Math.sin(currentAngle)*0.5 + 0.5);
|
||
setUVsToFace(centerUV, UV, prevUV, face);
|
||
top.addFace(face);
|
||
prevUV = UV;
|
||
prevRadial = radial;
|
||
}
|
||
} else {
|
||
prevUV = new Point(Math.cos(-radialSegment)*0.5 + 0.5, Math.sin(-radialSegment)*0.5 + 0.5);
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleUp, prevRadial + "_" + topSegment, radial + "_" + topSegment], "top_" + prevRadial);
|
||
currentAngle = radial*radialSegment;
|
||
UV = new Point(Math.cos(currentAngle)*0.5 + 0.5, Math.sin(currentAngle)*0.5 + 0.5);
|
||
setUVsToFace(centerUV, prevUV, UV, face);
|
||
top.addFace(face);
|
||
prevUV = UV;
|
||
prevRadial = radial;
|
||
}
|
||
}
|
||
} else {
|
||
points = new Array();
|
||
if (reverse) {
|
||
for (radial = (radialSegments - 1); radial < uint(-1); radial--) {
|
||
points.push(radial + "_" + topSegment);
|
||
}
|
||
} else {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
points.push(radial + "_" + topSegment);
|
||
}
|
||
}
|
||
top.addFace(createFace(points, "top"));
|
||
}
|
||
}
|
||
// Создание боковых граней
|
||
var face2:Face;
|
||
var aUV:Point;
|
||
var cUV:Point;
|
||
for (segment = bottomSegment; segment < topSegment; segment++) {
|
||
prevRadial = radialSegments - 1;
|
||
v = segment * vSegment;
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
if (triangulate) {
|
||
if (reverse) {
|
||
face = createFace([radial + "_" + (segment + 1), radial + "_" + segment, prevRadial + "_" + segment], prevRadial + "_" + segment + ":0");
|
||
face2 = createFace([prevRadial + "_" + segment, prevRadial + "_" + (segment + 1), radial + "_" + (segment + 1)], prevRadial + "_" + segment + ":1");
|
||
aUV = new Point(1 - (prevRadial + 1)*uSegment, v + vSegment)
|
||
cUV = new Point(1 - prevRadial*uSegment, v);
|
||
setUVsToFace(aUV, new Point(1 - (prevRadial + 1)*uSegment, v), cUV, face);
|
||
setUVsToFace(cUV, new Point(1 - prevRadial*uSegment, v + vSegment), aUV, face2);
|
||
} else {
|
||
face = createFace([prevRadial + "_" + segment, radial + "_" + segment, radial + "_" + (segment + 1)], prevRadial + "_" + segment + ":0");
|
||
face2 = createFace([radial + "_" + (segment + 1), prevRadial + "_" + (segment + 1), prevRadial + "_" + segment], prevRadial + "_" + segment + ":1");
|
||
aUV = new Point(prevRadial*uSegment, v)
|
||
cUV = new Point((prevRadial + 1)*uSegment, v + vSegment);
|
||
setUVsToFace(aUV, new Point((prevRadial + 1)*uSegment, v), cUV, face);
|
||
setUVsToFace(cUV, new Point(prevRadial*uSegment, v + vSegment), aUV, face2);
|
||
}
|
||
side.addFace(face);
|
||
side.addFace(face2);
|
||
} else {
|
||
if (reverse) {
|
||
side.addFace(createFace([prevRadial + "_" + segment, prevRadial + "_" + (segment + 1), radial + "_" + (segment + 1), radial + "_" + segment], prevRadial + "_" + segment));
|
||
} else {
|
||
side.addFace(createFace([prevRadial + "_" + segment, radial + "_" + segment, radial + "_" + (segment + 1), prevRadial + "_" + (segment + 1)], prevRadial + "_" + segment));
|
||
}
|
||
}
|
||
prevRadial = radial;
|
||
}
|
||
}
|
||
|
||
if (bottomRadius == 0) {
|
||
// Создание граней у нижнего полюса
|
||
prevRadial = radialSegments - 1;
|
||
centerUV = new Point(0.5, 0);
|
||
v = bottomSegment*vSegment;
|
||
if (reverse) {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleDown, prevRadial + "_" + bottomSegment, radial + "_" + bottomSegment], prevRadial + "_0");
|
||
if (triangulate) {
|
||
setUVsToFace(centerUV, new Point(1 - prevRadial*uSegment, v), new Point(1 - (prevRadial + 1)*uSegment, v), face);
|
||
}
|
||
side.addFace(face);
|
||
prevRadial = radial;
|
||
}
|
||
} else {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleDown, radial + "_" + bottomSegment, prevRadial + "_" + bottomSegment], prevRadial + "_0");
|
||
if (triangulate) {
|
||
setUVsToFace(centerUV, new Point((prevRadial + 1)*uSegment, v), new Point(prevRadial*uSegment, v), face);
|
||
}
|
||
side.addFace(face);
|
||
prevRadial = radial;
|
||
}
|
||
}
|
||
} else {
|
||
// Создание граней нижней крышки
|
||
var bottom:Surface = createSurface(null, "bottom");
|
||
if (triangulate) {
|
||
prevRadial = radialSegments - 1;
|
||
centerUV = new Point(0.5, 0.5);
|
||
if (reverse) {
|
||
prevUV = new Point(Math.cos(-radialSegment)*0.5 + 0.5, Math.sin(-radialSegment)*0.5 + 0.5);
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleDown, prevRadial + "_" + bottomSegment, radial + "_" + bottomSegment], "bottom_" + prevRadial);
|
||
currentAngle = radial*radialSegment;
|
||
UV = new Point(Math.cos(currentAngle)*0.5 + 0.5, Math.sin(currentAngle)*0.5 + 0.5);
|
||
setUVsToFace(centerUV, prevUV, UV, face);
|
||
bottom.addFace(face);
|
||
prevUV = UV;
|
||
prevRadial = radial;
|
||
}
|
||
} else {
|
||
prevUV = new Point(0.5 - Math.cos(-radialSegment)*0.5, Math.sin(-radialSegment)*0.5 + 0.5);
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
face = createFace([poleDown, radial + "_" + bottomSegment, prevRadial + "_" + bottomSegment], "bottom_" + prevRadial);
|
||
currentAngle = radial * radialSegment;
|
||
UV = new Point(0.5 - Math.cos(currentAngle)*0.5, Math.sin(currentAngle)*0.5 + 0.5);
|
||
setUVsToFace(centerUV, UV, prevUV, face);
|
||
bottom.addFace(face);
|
||
prevUV = UV;
|
||
prevRadial = radial;
|
||
}
|
||
}
|
||
} else {
|
||
points = new Array();
|
||
if (reverse) {
|
||
for (radial = 0; radial < radialSegments; radial++) {
|
||
points.push(radial + "_" + bottomSegment);
|
||
}
|
||
} else {
|
||
for (radial = (radialSegments - 1); radial < uint(-1); radial--) {
|
||
points.push(radial + "_" + bottomSegment);
|
||
}
|
||
}
|
||
bottom.addFace(createFace(points, "bottom"));
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @inheritDoc
|
||
*/
|
||
protected override function createEmptyObject():Object3D {
|
||
return new Cone(0, 0, 0, 0);
|
||
}
|
||
}
|
||
} |