Files
alternativa3d-archive/Alternativa3D5/5.3/alternativa/engine3d/primitives/Cone.as
Pyogenics c58621fb99 Add A3D5
2024-09-28 17:29:26 +01:00

264 lines
12 KiB
ActionScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}