more versions added

This commit is contained in:
Tubix
2024-10-05 12:11:16 +01:00
parent 413f563f33
commit c32c7e8c34
7661 changed files with 1343635 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
K 25
svn:wc:ra_dav:version-url
V 102
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives
END
Plane.as
K 25
svn:wc:ra_dav:version-url
V 111
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives/Plane.as
END
GeoSphere.as
K 25
svn:wc:ra_dav:version-url
V 115
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives/GeoSphere.as
END
Cone.as
K 25
svn:wc:ra_dav:version-url
V 110
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives/Cone.as
END
Sphere.as
K 25
svn:wc:ra_dav:version-url
V 112
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives/Sphere.as
END
Box.as
K 25
svn:wc:ra_dav:version-url
V 109
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives/Box.as
END
GeoPlane.as
K 25
svn:wc:ra_dav:version-url
V 114
/!svn/ver/497/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives/GeoPlane.as
END

View File

@@ -0,0 +1,100 @@
8
dir
46043
http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/5.4.1/alternativa/engine3d/primitives
http://svndev.alternativaplatform.com
2008-08-25T13:44:47.077292Z
176
int
svn:special svn:externals svn:needs-lock
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
Plane.as
file
2010-10-28T04:31:16.000000Z
b4c9c0e49de8cd3f4040482cb679d638
2008-08-25T13:44:47.077292Z
176
int
GeoSphere.as
file
2010-10-28T04:31:16.000000Z
8abcc53f0a951d85fde9466754beb2f9
2008-08-25T13:44:47.077292Z
176
int
Cone.as
file
2010-10-28T04:31:16.000000Z
1a4abe159a3bd66b895545b0768399a9
2008-08-25T13:44:47.077292Z
176
int
Sphere.as
file
2010-10-28T04:31:16.000000Z
307a9a635773182ee6de473ff6fab9d9
2008-08-25T13:44:47.077292Z
176
int
Box.as
file
2010-10-28T04:31:16.000000Z
be9c2bf9df095181eacdee4e3c5a66e1
2008-08-25T13:44:47.077292Z
176
int
GeoPlane.as
file
2010-10-28T04:31:16.000000Z
1ff3ee62127da83b17c3e4a163979d14
2008-08-25T13:44:47.077292Z
176
int

View File

@@ -0,0 +1 @@
8

View File

@@ -0,0 +1,316 @@
package alternativa.engine3d.primitives {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Mesh;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Surface;
import flash.geom.Point;
use namespace alternativa3d;
/**
* Прямоугольный параллелепипед.
*/
public class Box extends Mesh {
/**
* Создание нового параллелепипеда.
* <p>Параллелепипед после создания будет содержать в себе шесть поверхностей.
* <code>"front"</code>, <code>"back"</code>, <code>"left"</code>, <code>"right"</code>, <code>"top"</code>, <code>"bottom"</code>
* на каждую из которых может быть установлен свой материал.</p>
*
* @param width ширина. Размерность по оси X. Не может быть меньше нуля.
* @param length длина. Размерность по оси Y. Не может быть меньше нуля.
* @param height высота. Размерность по оси Z. Не может быть меньше нуля.
* @param widthSegments количество сегментов по ширине
* @param lengthSegments количество сегментов по длине
* @param heightSegments количество сегментов по по высоте
* @param reverse задает направление нормалей граней. Если указано значение <code>true</code>, то нормали будут направлены внутрь фигуры.
* @param triangulate флаг триангуляции. Если указано значение <code>true</code>, четырехугольники в параллелепипеде будут триангулированы.
*/
public function Box(width:Number = 100, length:Number = 100, height:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, heightSegments:uint = 1, reverse:Boolean = false, triangulate:Boolean = false) {
super();
if ((widthSegments == 0) || (lengthSegments == 0) || (heightSegments == 0)) {
return;
}
width = (width < 0)? 0 : width;
length = (length < 0)? 0 : length;
height = (height < 0)? 0 : height;
var wh:Number = width/2;
var lh:Number = length/2;
var hh:Number = height/2;
var ws:Number = width/widthSegments;
var ls:Number = length/lengthSegments;
var hs:Number = height/heightSegments;
var x:int;
var y:int;
var z:int;
// Создание точек
for (x = 0; x <= widthSegments; x++) {
for (y = 0; y <= lengthSegments; y++) {
for (z = 0; z <= heightSegments; z++) {
if (x == 0 || x == widthSegments || y == 0 || y == lengthSegments || z == 0 || z == heightSegments) {
createVertex(x*ws - wh, y*ls - lh, z*hs - hh, x + "_" + y + "_" + z);
}
}
}
}
// Создание поверхностей
var front:Surface = createSurface(null, "front");
var back:Surface = createSurface(null, "back");
var left:Surface = createSurface(null, "left");
var right:Surface = createSurface(null, "right");
var top:Surface = createSurface(null, "top");
var bottom:Surface = createSurface(null, "bottom");
// Создание граней
var wd:Number = 1/widthSegments;
var ld:Number = 1/lengthSegments;
var hd:Number = 1/heightSegments;
var faceId:String;
// Для оптимизаций UV при триангуляции
var aUV:Point;
var cUV:Point;
// Построение верхней грани
for (y = 0; y < lengthSegments; y++) {
for (x = 0; x < widthSegments; x++) {
faceId = "top_"+x+"_"+y;
if (reverse) {
if (triangulate) {
aUV = new Point(x*wd, (lengthSegments - y)*ld);
cUV = new Point((x + 1)*wd, (lengthSegments - y - 1)*ld);
createFace([x + "_" + y + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments], faceId + ":1");
setUVsToFace(aUV, new Point(x*wd, (lengthSegments - y - 1)*ld), cUV, faceId + ":1");
createFace([(x + 1) + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments, x + "_" + y + "_" + heightSegments], faceId + ":0");
setUVsToFace(cUV, new Point((x + 1)*wd, (lengthSegments - y)*ld), aUV, faceId + ":0");
} else {
createFace([x + "_" + y + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments], faceId);
setUVsToFace(new Point(x*wd, (lengthSegments - y)*ld), new Point(x*wd, (lengthSegments - y - 1)*ld), new Point((x + 1)*wd, (lengthSegments - y - 1)*ld), faceId);
}
} else {
if (triangulate) {
aUV = new Point(x*wd, y*ld);
cUV = new Point((x + 1)*wd, (y + 1)*ld);
createFace([x + "_" + y + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments], faceId + ":0");
setUVsToFace(aUV, new Point((x + 1)*wd, y*ld), cUV, faceId + ":0");
createFace([(x + 1) + "_" + (y + 1) + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments, x + "_" + y + "_" + heightSegments], faceId + ":1");
setUVsToFace(cUV, new Point(x*wd, (y + 1)*ld), aUV, faceId + ":1");
} else {
createFace([x + "_" + y + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments], faceId);
setUVsToFace(new Point(x*wd, y*ld), new Point((x + 1)*wd, y*ld), new Point((x + 1)*wd, (y + 1)*ld), faceId);
}
}
if (triangulate) {
top.addFace(faceId + ":0");
top.addFace(faceId + ":1");
} else {
top.addFace(faceId);
}
}
}
// Построение нижней грани
for (y = 0; y < lengthSegments; y++) {
for (x = 0; x < widthSegments; x++) {
faceId = "bottom_" + x + "_" + y;
if (reverse) {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, (lengthSegments - y)*ld);
cUV = new Point((widthSegments - x - 1)*wd, (lengthSegments - y - 1)*ld);
createFace([x + "_" + y + "_" + 0, (x + 1) + "_" + y + "_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0], faceId + ":0");
setUVsToFace(aUV, new Point((widthSegments - x - 1)*wd, (lengthSegments - y)*ld), cUV, faceId + ":0");
createFace([(x + 1) + "_" + (y + 1) + "_" + 0, x + "_" + (y + 1) + "_" + 0, x + "_" + y + "_" + 0], faceId + ":1");
setUVsToFace(cUV, new Point((widthSegments - x)*wd, (lengthSegments - y - 1)*ld), aUV, faceId + ":1");
} else {
createFace([x + "_" + y + "_"+0, (x + 1) + "_" + y + "_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0, x + "_" + (y + 1) + "_" + 0], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, (lengthSegments - y)*ld), new Point((widthSegments - x - 1)*wd, (lengthSegments - y)*ld), new Point((widthSegments - x - 1)*wd, (lengthSegments - y - 1)*ld), faceId);
}
} else {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, y*ld);
cUV = new Point((widthSegments - x - 1)*wd, (y + 1)*ld);
createFace([x + "_" + y + "_" + 0, x + "_" + (y + 1) + "_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0], faceId + ":1");
setUVsToFace(aUV, new Point((widthSegments - x)*wd, (y + 1)*ld), cUV, faceId + ":1");
createFace([(x + 1) + "_" + (y + 1) + "_" + 0, (x + 1) + "_" + y + "_" + 0, x + "_" + y + "_" + 0], faceId + ":0");
setUVsToFace(cUV, new Point((widthSegments - x - 1)*wd, y*ld), aUV, faceId + ":0");
} else {
createFace([x + "_" + y + "_" + 0, x + "_" + (y + 1) +"_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0, (x + 1) + "_" + y + "_" + 0], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, y*ld), new Point((widthSegments - x)*wd, (y + 1)*ld), new Point((widthSegments - x - 1)*wd, (y + 1)*ld), faceId);
}
}
if (triangulate) {
bottom.addFace(faceId + ":0");
bottom.addFace(faceId + ":1");
} else {
bottom.addFace(faceId);
}
}
}
// Построение фронтальной грани
for (z = 0; z < heightSegments; z++) {
for (x = 0; x < widthSegments; x++) {
faceId = "front_"+x+"_"+z;
if (reverse) {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, z*hd);
cUV = new Point((widthSegments - x - 1)*wd, (z + 1)*hd);
createFace([x + "_" + 0 + "_" + z, x + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + (z + 1)], faceId + ":1");
setUVsToFace(aUV, new Point((widthSegments - x)*wd, (z + 1)*hd), cUV, faceId + ":1");
createFace([(x + 1) + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + z, x + "_" + 0 + "_" + z], faceId + ":0");
setUVsToFace(cUV, new Point((widthSegments - x - 1)*wd, z*hd), aUV, faceId + ":0");
} else {
createFace([x + "_" + 0 + "_" + z, x + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + z], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, z*hd), new Point((widthSegments - x)*wd, (z + 1)*hd), new Point((widthSegments - x - 1)*wd, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point(x*wd, z*hd);
cUV = new Point((x + 1)*wd, (z + 1)*hd);
createFace([x + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + (z + 1)], faceId + ":0");
setUVsToFace(aUV, new Point((x + 1)*wd, z*hd), cUV, faceId + ":0");
createFace([(x + 1) + "_" + 0 + "_" + (z + 1), x + "_" + 0 + "_" + (z + 1), x + "_" + 0 + "_" + z], faceId + ":1");
setUVsToFace(cUV, new Point(x*wd, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([x + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + (z + 1), x + "_" + 0 + "_" + (z + 1)], faceId);
setUVsToFace(new Point(x*wd, z*hd), new Point((x + 1)*wd, z*hd), new Point((x + 1)*wd, (z + 1)*hd), faceId);
}
}
if (triangulate) {
front.addFace(faceId + ":0");
front.addFace(faceId + ":1");
} else {
front.addFace(faceId);
}
}
}
// Построение задней грани
for (z = 0; z < heightSegments; z++) {
for (x = 0; x < widthSegments; x++) {
faceId = "back_"+x+"_"+z;
if (reverse) {
if (triangulate) {
aUV = new Point(x * wd, (z + 1) * hd);
cUV = new Point((x + 1) * wd, z * hd);
createFace([x + "_" + lengthSegments+"_" + (z + 1), x + "_"+lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + z], faceId + ":0");
setUVsToFace(aUV, new Point(x * wd, z * hd), cUV, faceId + ":0");
createFace([(x + 1) + "_" + lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + (z + 1), x + "_" + lengthSegments + "_" + (z + 1)], faceId + ":1");
setUVsToFace(cUV, new Point((x + 1) * wd, (z + 1) * hd), aUV, faceId + ":1");
} else {
createFace([x + "_" + lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + (z + 1), x + "_" + lengthSegments + "_" + (z + 1)], faceId);
setUVsToFace(new Point(x*wd, z*hd), new Point((x + 1)*wd, z*hd), new Point((x + 1)*wd, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, (z + 1)*hd);
cUV = new Point((widthSegments - x - 1)*wd, z*hd);
createFace([x + "_" + lengthSegments + "_" + z, x + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + z], faceId + ":0");
setUVsToFace(new Point((widthSegments - x)*wd, z*hd), aUV, cUV, faceId + ":0");
createFace([x + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + z], faceId + ":1");
setUVsToFace(aUV, new Point((widthSegments - x - 1)*wd, (z + 1)*hd), cUV, faceId + ":1");
} else {
createFace([x + "_" + lengthSegments + "_" + z, x + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + z], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, z*hd), new Point((widthSegments - x)*wd, (z + 1)*hd), new Point((widthSegments - x - 1)*wd, (z + 1)*hd), faceId);
}
}
if (triangulate) {
back.addFace(faceId + ":0");
back.addFace(faceId + ":1");
} else {
back.addFace(faceId);
}
}
}
// Построение левой грани
for (y = 0; y < lengthSegments; y++) {
for (z = 0; z < heightSegments; z++) {
faceId = "left_" + y + "_" + z;
if (reverse) {
if (triangulate) {
aUV = new Point(y*ld, (z + 1)*hd);
cUV = new Point((y + 1)*ld, z*hd);
createFace([0 + "_" + y + "_" + (z + 1), 0 + "_" + y + "_" + z, 0 + "_" + (y + 1) + "_" + z], faceId + ":0");
setUVsToFace(aUV, new Point(y*ld, z*hd), cUV, faceId + ":0");
createFace([0 + "_" + (y + 1) + "_" + z, 0 + "_" + (y + 1) + "_" + (z + 1), 0 + "_" + y + "_" + (z + 1)], faceId + ":1");
setUVsToFace(cUV, new Point((y + 1)*ld, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([0 + "_" + y + "_" + z, 0 + "_" + (y + 1) + "_" + z, 0 + "_" + (y + 1) + "_" + (z + 1), 0 + "_" + y + "_" + (z + 1)], faceId);
setUVsToFace(new Point(y*ld, z*hd), new Point((y + 1)*ld, z*hd), new Point((y + 1)*ld, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point((lengthSegments - y - 1)*ld, z*hd);
cUV = new Point((lengthSegments - y)*ld, (z + 1)*hd);
createFace([0 + "_" + (y + 1) + "_" + z, 0 + "_" + y + "_" + z, 0 + "_" + y + "_" + (z + 1)], faceId + ":0");
setUVsToFace(aUV, new Point((lengthSegments - y)*ld, z*hd), cUV, faceId + ":0");
createFace([0 + "_" + y + "_" + (z + 1), 0 + "_" + ((y + 1)) + "_" + (z + 1), 0 + "_" + (y + 1) + "_" + z], faceId + ":1");
setUVsToFace(cUV, new Point((lengthSegments - y - 1)*ld, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([0 + "_" + y + "_" + z, 0 + "_" + y + "_" + (z + 1), 0 + "_" + ((y + 1)) + "_" + (z + 1), 0 + "_" + ((y + 1)) + "_" + z], faceId);
setUVsToFace(new Point((lengthSegments - y)*ld, z*hd), new Point((lengthSegments - y)*ld, (z + 1)*hd), new Point((lengthSegments - y - 1)*ld, (z + 1)*hd), faceId);
}
}
if (triangulate) {
left.addFace(faceId + ":0");
left.addFace(faceId + ":1");
} else {
left.addFace(faceId);
}
}
}
// Построение правой грани
for (y = 0; y < lengthSegments; y++) {
for (z = 0; z < heightSegments; z++) {
faceId = "right_" + y + "_" + z;
if (reverse) {
if (triangulate) {
aUV = new Point((lengthSegments - y)*ld, z*hd);
cUV = new Point((lengthSegments - y - 1)*ld, (z + 1)*hd);
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + y + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + (z + 1)], faceId + ":1");
setUVsToFace(aUV, new Point((lengthSegments - y)*ld, (z + 1)*hd), cUV, faceId + ":1");
createFace([widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + z, widthSegments + "_" + y + "_" + z], faceId + ":0");
setUVsToFace(cUV, new Point((lengthSegments - y - 1)*ld, z*hd), aUV, faceId + ":0");
} else {
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + y + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + z], faceId);
setUVsToFace(new Point((lengthSegments - y)*ld, z*hd), new Point((lengthSegments - y)*ld, (z + 1)*hd), new Point((lengthSegments - y - 1)*ld, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point(y*ld, z*hd);
cUV = new Point((y + 1)*ld, (z + 1)*hd);
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + (y + 1) + "_" + z, widthSegments + "_" + (y + 1) + "_" + (z + 1)], faceId + ":0");
setUVsToFace(aUV, new Point((y + 1)*ld, z*hd), cUV, faceId + ":0");
createFace([widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + y + "_" + (z + 1), widthSegments + "_" + y + "_" + z], faceId + ":1");
setUVsToFace(cUV, new Point(y*ld, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + (y + 1) + "_" + z, widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + y + "_" + (z + 1)], faceId);
setUVsToFace(new Point(y*ld, z*hd), new Point((y + 1)*ld, z*hd), new Point((y + 1)*ld, (z + 1)*hd), faceId);
}
}
if (triangulate) {
right.addFace(faceId + ":0");
right.addFace(faceId + ":1");
} else {
right.addFace(faceId);
}
}
}
}
/**
* @inheritDoc
*/
protected override function createEmptyObject():Object3D {
return new Box(0, 0, 0, 0);
}
}
}

View File

@@ -0,0 +1,264 @@
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);
}
}
}

View File

@@ -0,0 +1,197 @@
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 {
/**
* Создает геоплоскость.
* <p>Геоплоскость это плоскость с сетчатой структурой граней.</p>
* <p>Примитив после создания содержит в cебе одну или две поверхности, в зависимости от значения параметров.
* При значении <code>reverse</code> установленном в <code>true</code> примитив будет содержать грань - <code>"back"</code>.
* При значении <code>reverse</code> установленном в <code>false</code> примитив будет содержать грань - <code>"front"</code>.
* Параметр <code>twoSided</code> указывает методу создать обе поверхности.</p>
*
* @param width ширина. Размерность по оси X. Не может быть меньше нуля.
* @param length длина. Размерность по оси Y. Не может быть меньше нуля.
* @param widthSegments количество сегментов по ширине
* @param lengthSegments количество сегментов по длине
* @param twoSided если значение параметра равно <code>true</code>, то создаётся двусторонняя поверхность
* @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);
}
}
}

View File

@@ -0,0 +1,321 @@
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;
import alternativa.types.Point3D;
use namespace alternativa3d;
/**
* Геосфера.
*/
public class GeoSphere extends Mesh {
/**
* Создает геосферу.
* <p>Геосфера после создания содержит в себе одну поверхность с идентификатором по умолчанию.</p>
* <p>Текстурные координаты у геосферы не находятся в промежутке <code>[0, 1]</code>,
* поэтому для материала с текстурой необходимо устанавливать флаг repeat.
*
* @param radius радиус геосферы. Не может быть меньше нуля.
* @param segments количество сегментов геосферы
* @param reverse флаг направления нормалей. При значении <code>true</code> нормали направлены внуть геосферы.
*/
public function GeoSphere(radius:Number = 100, segments:uint = 2, reverse:Boolean = false) {
if (segments == 0) {
return;
}
radius = (radius < 0)? 0 : radius;
const sections:uint = 20;
//var nfaces:uint = sections*segments*segments;
//var nverts:Number = nfaces/2 + 2;
var points:Array = new Array();
var i:uint;
var f:uint;
var theta:Number;
var sin:Number;
var cos:Number;
// z расстояние до нижней и верхней крышки полюса
var subz:Number = 4.472136E-001*radius;
// радиус на расстоянии subz
var subrad:Number = 2*subz;
points.push(createVertex(0, 0, radius, "poleUp"));
// Создание вершин верхней крышки
for (i = 0; i < 5; i++) {
theta = MathUtils.DEG360*i/5;
sin = Math.sin(theta);
cos = Math.cos(theta);
points.push(createVertex(subrad*cos, subrad*sin, subz));
}
// Создание вершин нижней крышки
for (i = 0; i < 5; i++) {
theta = MathUtils.DEG180*((i << 1) + 1)/5;
sin = Math.sin(theta);
cos = Math.cos(theta);
points.push(createVertex(subrad*cos, subrad*sin, -subz));
}
points.push(createVertex(0, 0, -radius, "poleDown"));
for (i = 1; i < 6; i++) {
interpolate(0, i, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i, i % 5 + 1, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i, i + 5, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i, (i + 3) % 5 + 6, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i + 5, i % 5 + 6, segments, points);
}
for (i = 6; i < 11; i++) {
interpolate(11, i, segments, points);
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + f*(segments - 1) + i, 12 + (f + 1) % 5*(segments - 1) + i, i + 1, points);
}
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + (f + 15)*(segments - 1) + i, 12 + (f + 10)*(segments - 1) + i, i + 1, points);
}
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + ((f + 1) % 5 + 15)*(segments - 1) + segments - 2 - i, 12 + (f + 10)*(segments - 1) + segments - 2 - i, i + 1, points);
}
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + ((f + 1) % 5 + 25)*(segments - 1) + i, 12 + (f + 25)*(segments - 1) + i, i + 1, points);
}
}
// Создание граней
var face:Face;
var surface:Surface = createSurface();
for (f = 0; f < sections; f++) {
for (var row:uint = 0; row < segments; row++) {
for (var column:uint = 0; column <= row; column++) {
var a:uint = findVertices(segments, f, row, column);
var b:uint = findVertices(segments, f, row + 1, column);
var c:uint = findVertices(segments, f, row + 1, column + 1);
var va:Vertex = points[a];
var vb:Vertex = points[b];
var vc:Vertex = points[c];
var aUV:Point;
var bUV:Point;
var cUV:Point;
var coordA:Point3D = va._coords;
var coordB:Point3D = vb._coords;
var coordC:Point3D = vc._coords;
if (coordA.y >= 0 && (coordA.x < 0) && (coordB.y < 0 || coordC.y < 0)) {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 - 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
} else {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 + 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordB.y >= 0 && (coordB.x < 0) && (coordA.y < 0 || coordC.y < 0)) {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 - 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
} else {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 + 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordC.y >= 0 && (coordC.x < 0) && (coordA.y < 0 || coordB.y < 0)) {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 - 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
} else {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 + 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
}
// полюс
if (a == 0 || a == 11) {
aUV.x = bUV.x + (cUV.x - bUV.x)*0.5;
}
if (b == 0 || b == 11) {
bUV.x = aUV.x + (cUV.x - aUV.x)*0.5;
}
if (c == 0 || c == 11) {
cUV.x = aUV.x + (bUV.x - aUV.x)*0.5;
}
if (reverse) {
face = createFace([va, vc, vb], (column << 1) + "_" + row + "_" + f);
aUV.x = 1 - aUV.x;
bUV.x = 1 - bUV.x;
cUV.x = 1 - cUV.x;
setUVsToFace(aUV, cUV, bUV, face);
} else {
face = createFace([va, vb, vc], (column << 1) + "_" + row + "_" + f);
setUVsToFace(aUV, bUV, cUV, face);
}
surface.addFace(face);
//trace(a + "_" + b + "_" + c);
if (column < row) {
b = findVertices(segments, f, row, column + 1);
var vd:Vertex = points[b];
coordB = vd._coords;
if (coordA.y >= 0 && (coordA.x < 0) && (coordB.y < 0 || coordC.y < 0)) {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 - 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
} else {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 + 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordB.y >= 0 && (coordB.x < 0) && (coordA.y < 0 || coordC.y < 0)) {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 - 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
} else {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 + 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordC.y >= 0 && (coordC.x < 0) && (coordA.y < 0 || coordB.y < 0)) {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 - 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
} else {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 + 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
}
if (a == 0 || a == 11) {
aUV.x = bUV.x + (cUV.x - bUV.x)*0.5;
}
if (b == 0 || b == 11) {
bUV.x = aUV.x + (cUV.x - aUV.x)*0.5;
}
if (c == 0 || c == 11) {
cUV.x = aUV.x + (bUV.x - aUV.x)*0.5;
}
if (reverse) {
face = createFace([va, vd, vc], ((column << 1) + 1) + "_" + row + "_" + f);
aUV.x = 1 - aUV.x;
bUV.x = 1 - bUV.x;
cUV.x = 1 - cUV.x;
setUVsToFace(aUV, bUV, cUV, face);
} else {
face = createFace([va, vc, vd], ((column << 1) + 1) + "_" + row + "_" + f);
setUVsToFace(aUV, cUV, bUV, face);
}
surface.addFace(face);
}
}
}
}
}
/* private function getUVSpherical(point:Point3D, radius:Number = 0, reverse:Boolean = false):Point {
if (radius == 0) {
radius = point.length;
}
if (reverse) {
var u:Number = 0.5 - Math.atan2(point.y, point.x)/MathUtils.DEG360;
} else {
u = Math.atan2(point.y, point.x)/MathUtils.DEG360 + 0.5;
}
return new Point(u, Math.asin(point.z/radius)/MathUtils.DEG180 + 0.5);
}
*/
private function interpolate(v1:uint, v2:uint, num:uint, points:Array):void {
if (num < 2) {
return;
}
var a:Vertex = Vertex(points[v1]);
var b:Vertex = Vertex(points[v2]);
var cos:Number = (a.x*b.x + a.y*b.y + a.z*b.z)/(a.x*a.x + a.y*a.y + a.z*a.z);
cos = (cos < -1) ? -1 : ((cos > 1) ? 1 : cos);
var theta:Number = Math.acos(cos);
var sin:Number = Math.sin(theta);
for (var e:uint = 1; e < num; e++) {
var theta1:Number = theta*e/num;
var theta2:Number = theta*(num - e)/num;
var st1:Number = Math.sin(theta1);
var st2:Number = Math.sin(theta2);
points.push(createVertex((a.x*st2 + b.x*st1)/sin, (a.y*st2 + b.y*st1)/sin, (a.z*st2 + b.z*st1)/sin));
}
}
private function findVertices(segments:uint, section:uint, row:uint, column:uint):uint {
if (row == 0) {
if (section < 5) {
return (0);
}
if (section > 14) {
return (11);
}
return (section - 4);
}
if (row == segments && column == 0) {
if (section < 5) {
return (section + 1);
}
if (section < 10) {
return ((section + 4) % 5 + 6);
}
if (section < 15) {
return ((section + 1) % 5 + 1);
}
return ((section + 1) % 5 + 6);
}
if (row == segments && column == segments) {
if (section < 5) {
return ((section + 1) % 5 + 1);
}
if (section < 10) {
return (section + 1);
}
if (section < 15) {
return (section - 9);
}
return (section - 9);
}
if (row == segments) {
if (section < 5) {
return (12 + (5 + section)*(segments - 1) + column - 1);
}
if (section < 10) {
return (12 + (20 + (section + 4) % 5)*(segments - 1) + column - 1);
}
if (section < 15) {
return (12 + (section - 5)*(segments - 1) + segments - 1 - column);
}
return (12 + (5 + section)*(segments - 1) + segments - 1 - column);
}
if (column == 0) {
if (section < 5) {
return (12 + section*(segments - 1) + row - 1);
}
if (section < 10) {
return (12 + (section % 5 + 15)*(segments - 1) + row - 1);
}
if (section < 15) {
return (12 + ((section + 1) % 5 + 15)*(segments - 1) + segments - 1 - row);
}
return (12 + ((section + 1) % 5 + 25)*(segments - 1) + row - 1);
}
if (column == row) {
if (section < 5) {
return (12 + (section + 1) % 5*(segments - 1) + row - 1);
}
if (section < 10) {
return (12 + (section % 5 + 10)*(segments - 1) + row - 1);
}
if (section < 15) {
return (12 + (section % 5 + 10)*(segments - 1) + segments - row - 1);
}
return (12 + (section % 5 + 25)*(segments - 1) + row - 1);
}
return (12 + 30*(segments - 1) + section*(segments - 1)*(segments - 2)/2 + (row - 1)*(row - 2)/2 + column - 1);
}
/**
* @inheritDoc
*/
protected override function createEmptyObject():Object3D {
return new GeoSphere(0, 0);
}
}
}

View File

@@ -0,0 +1,117 @@
package alternativa.engine3d.primitives {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Mesh;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Surface;
import flash.geom.Point;
use namespace alternativa3d;
/**
* Плоскость.
*/
public class Plane extends Mesh {
/**
* Создает плоскость.
* <p>Примитив после создания содержит в cебе одну или две поверхности, в зависимости от значения параметров.
* При значении <code>reverse</code> установленном в <code>true</code> примитив будет содержать грань - <code>"back"</code>.
* При значении <code>reverse</code> установленном в <code>false</code> примитив будет содержать грань - <code>"front"</code>.
* Параметр <code>twoSided</code> указывает методу создать обе поверхности.</p>
*
* @param width ширина. Размерность по оси Х. Не может быть меньше нуля.
* @param length длина. Размерность по оси Y. Не может быть меньше нуля.
* @param widthSegments количество сегментов по ширине
* @param lengthSegments количество сегментов по длине
* @param twoSided если значении параметра равно <code>true</code>, то формируется двусторонняя плоскость
* @param reverse инвертирование нормалей
* @param triangulate флаг триангуляции. Если указано значение <code>true</code>, четырехугольники в плоскости будут триангулированы.
*/
public function Plane(width:Number = 100, length:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, twoSided:Boolean = true, reverse:Boolean = false, triangulate: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 lh:Number = length/2;
// Размеры сегмента
var ws:Number = width/widthSegments;
var ls:Number = length/lengthSegments;
// Размеры UV-сегмента
var wd:Number = 1/widthSegments;
var ld:Number = 1/lengthSegments;
// Создание точек и UV
var x:int;
var y:int;
var uv:Array = new Array();
for (y = 0; y <= lengthSegments; y++) {
uv[y] = new Array();
for (x = 0; x <= widthSegments; x++) {
uv[y][x] = new Point(x*wd, y*ld);
createVertex(x*ws - wh, y*ls - lh, 0, x+"_"+y);
}
}
// Создание поверхностей
var front:Surface;
var back:Surface;
if (twoSided || !reverse) {
front = createSurface(null, "front");
}
if (twoSided || reverse) {
back = createSurface(null, "back");
}
// Создание полигонов
for (y = 0; y < lengthSegments; y++) {
for (x = 0; x < widthSegments; x++) {
if (twoSided || !reverse) {
if (triangulate) {
createFace([x + "_" + y, (x + 1) + "_" + y, (x + 1) + "_" + (y + 1)], "front" + x + "_" + y + ":0");
setUVsToFace(uv[y][x], uv[y][x + 1], uv[y + 1][x + 1], "front" + x + "_" + y + ":0");
createFace([(x + 1) + "_" + (y + 1), x + "_" + (y + 1), x + "_" + y], "front" + x + "_" + y + ":1");
setUVsToFace(uv[y + 1][x + 1], uv[y + 1][x], uv[y][x], "front" + x + "_" + y + ":1");
front.addFace("front" + x + "_" + y + ":0");
front.addFace("front" + x + "_" + y + ":1");
} else {
createFace([x + "_" + y, (x + 1) + "_" + y, (x + 1) + "_" + (y + 1), x + "_" + (y + 1)], "front" + x + "_" + y);
setUVsToFace(uv[y][x], uv[y][x + 1], uv[y + 1][x + 1], "front" + x + "_" + y);
front.addFace("front" + x + "_" + y);
}
}
if (twoSided || reverse) {
if (triangulate) {
createFace([x + "_" + y, x + "_" + (y + 1), (x + 1) + "_" + (y + 1)], "back" + x + "_" + y + ":0");
setUVsToFace(uv[lengthSegments - y][x], uv[lengthSegments - y - 1][x], uv[lengthSegments - y - 1][x + 1], "back" + x + "_" + y + ":0");
createFace([(x + 1) + "_" + (y + 1), (x + 1) + "_" + y, x + "_" + y], "back" + x + "_" + y + ":1");
setUVsToFace(uv[lengthSegments - y - 1][x + 1], uv[lengthSegments - y][x + 1], uv[lengthSegments - y][x], "back" + x + "_" + y + ":1");
back.addFace("back" + x + "_" + y + ":0");
back.addFace("back"+x+"_"+y + ":1");
} else {
createFace([x + "_" + y, x + "_" + (y + 1), (x + 1) + "_" + (y + 1), (x + 1) + "_" + y], "back" + x + "_" + y);
setUVsToFace(uv[lengthSegments - y][x], uv[lengthSegments - y - 1][x], uv[lengthSegments - y - 1][x + 1], "back" + x + "_" + y);
back.addFace("back" + x + "_" + y);
}
}
}
}
}
/**
* @inheritDoc
*/
protected override function createEmptyObject():Object3D {
return new Plane(0, 0, 0);
}
}
}

View File

@@ -0,0 +1,144 @@
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);
}
}
}

View File

@@ -0,0 +1,316 @@
package alternativa.engine3d.primitives {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Mesh;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Surface;
import flash.geom.Point;
use namespace alternativa3d;
/**
* Прямоугольный параллелепипед.
*/
public class Box extends Mesh {
/**
* Создание нового параллелепипеда.
* <p>Параллелепипед после создания будет содержать в себе шесть поверхностей.
* <code>"front"</code>, <code>"back"</code>, <code>"left"</code>, <code>"right"</code>, <code>"top"</code>, <code>"bottom"</code>
* на каждую из которых может быть установлен свой материал.</p>
*
* @param width ширина. Размерность по оси X. Не может быть меньше нуля.
* @param length длина. Размерность по оси Y. Не может быть меньше нуля.
* @param height высота. Размерность по оси Z. Не может быть меньше нуля.
* @param widthSegments количество сегментов по ширине
* @param lengthSegments количество сегментов по длине
* @param heightSegments количество сегментов по по высоте
* @param reverse задает направление нормалей граней. Если указано значение <code>true</code>, то нормали будут направлены внутрь фигуры.
* @param triangulate флаг триангуляции. Если указано значение <code>true</code>, четырехугольники в параллелепипеде будут триангулированы.
*/
public function Box(width:Number = 100, length:Number = 100, height:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, heightSegments:uint = 1, reverse:Boolean = false, triangulate:Boolean = false) {
super();
if ((widthSegments == 0) || (lengthSegments == 0) || (heightSegments == 0)) {
return;
}
width = (width < 0)? 0 : width;
length = (length < 0)? 0 : length;
height = (height < 0)? 0 : height;
var wh:Number = width/2;
var lh:Number = length/2;
var hh:Number = height/2;
var ws:Number = width/widthSegments;
var ls:Number = length/lengthSegments;
var hs:Number = height/heightSegments;
var x:int;
var y:int;
var z:int;
// Создание точек
for (x = 0; x <= widthSegments; x++) {
for (y = 0; y <= lengthSegments; y++) {
for (z = 0; z <= heightSegments; z++) {
if (x == 0 || x == widthSegments || y == 0 || y == lengthSegments || z == 0 || z == heightSegments) {
createVertex(x*ws - wh, y*ls - lh, z*hs - hh, x + "_" + y + "_" + z);
}
}
}
}
// Создание поверхностей
var front:Surface = createSurface(null, "front");
var back:Surface = createSurface(null, "back");
var left:Surface = createSurface(null, "left");
var right:Surface = createSurface(null, "right");
var top:Surface = createSurface(null, "top");
var bottom:Surface = createSurface(null, "bottom");
// Создание граней
var wd:Number = 1/widthSegments;
var ld:Number = 1/lengthSegments;
var hd:Number = 1/heightSegments;
var faceId:String;
// Для оптимизаций UV при триангуляции
var aUV:Point;
var cUV:Point;
// Построение верхней грани
for (y = 0; y < lengthSegments; y++) {
for (x = 0; x < widthSegments; x++) {
faceId = "top_"+x+"_"+y;
if (reverse) {
if (triangulate) {
aUV = new Point(x*wd, (lengthSegments - y)*ld);
cUV = new Point((x + 1)*wd, (lengthSegments - y - 1)*ld);
createFace([x + "_" + y + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments], faceId + ":1");
setUVsToFace(aUV, new Point(x*wd, (lengthSegments - y - 1)*ld), cUV, faceId + ":1");
createFace([(x + 1) + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments, x + "_" + y + "_" + heightSegments], faceId + ":0");
setUVsToFace(cUV, new Point((x + 1)*wd, (lengthSegments - y)*ld), aUV, faceId + ":0");
} else {
createFace([x + "_" + y + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments], faceId);
setUVsToFace(new Point(x*wd, (lengthSegments - y)*ld), new Point(x*wd, (lengthSegments - y - 1)*ld), new Point((x + 1)*wd, (lengthSegments - y - 1)*ld), faceId);
}
} else {
if (triangulate) {
aUV = new Point(x*wd, y*ld);
cUV = new Point((x + 1)*wd, (y + 1)*ld);
createFace([x + "_" + y + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments], faceId + ":0");
setUVsToFace(aUV, new Point((x + 1)*wd, y*ld), cUV, faceId + ":0");
createFace([(x + 1) + "_" + (y + 1) + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments, x + "_" + y + "_" + heightSegments], faceId + ":1");
setUVsToFace(cUV, new Point(x*wd, (y + 1)*ld), aUV, faceId + ":1");
} else {
createFace([x + "_" + y + "_" + heightSegments, (x + 1) + "_" + y + "_" + heightSegments, (x + 1) + "_" + (y + 1) + "_" + heightSegments, x + "_" + (y + 1) + "_" + heightSegments], faceId);
setUVsToFace(new Point(x*wd, y*ld), new Point((x + 1)*wd, y*ld), new Point((x + 1)*wd, (y + 1)*ld), faceId);
}
}
if (triangulate) {
top.addFace(faceId + ":0");
top.addFace(faceId + ":1");
} else {
top.addFace(faceId);
}
}
}
// Построение нижней грани
for (y = 0; y < lengthSegments; y++) {
for (x = 0; x < widthSegments; x++) {
faceId = "bottom_" + x + "_" + y;
if (reverse) {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, (lengthSegments - y)*ld);
cUV = new Point((widthSegments - x - 1)*wd, (lengthSegments - y - 1)*ld);
createFace([x + "_" + y + "_" + 0, (x + 1) + "_" + y + "_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0], faceId + ":0");
setUVsToFace(aUV, new Point((widthSegments - x - 1)*wd, (lengthSegments - y)*ld), cUV, faceId + ":0");
createFace([(x + 1) + "_" + (y + 1) + "_" + 0, x + "_" + (y + 1) + "_" + 0, x + "_" + y + "_" + 0], faceId + ":1");
setUVsToFace(cUV, new Point((widthSegments - x)*wd, (lengthSegments - y - 1)*ld), aUV, faceId + ":1");
} else {
createFace([x + "_" + y + "_"+0, (x + 1) + "_" + y + "_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0, x + "_" + (y + 1) + "_" + 0], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, (lengthSegments - y)*ld), new Point((widthSegments - x - 1)*wd, (lengthSegments - y)*ld), new Point((widthSegments - x - 1)*wd, (lengthSegments - y - 1)*ld), faceId);
}
} else {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, y*ld);
cUV = new Point((widthSegments - x - 1)*wd, (y + 1)*ld);
createFace([x + "_" + y + "_" + 0, x + "_" + (y + 1) + "_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0], faceId + ":1");
setUVsToFace(aUV, new Point((widthSegments - x)*wd, (y + 1)*ld), cUV, faceId + ":1");
createFace([(x + 1) + "_" + (y + 1) + "_" + 0, (x + 1) + "_" + y + "_" + 0, x + "_" + y + "_" + 0], faceId + ":0");
setUVsToFace(cUV, new Point((widthSegments - x - 1)*wd, y*ld), aUV, faceId + ":0");
} else {
createFace([x + "_" + y + "_" + 0, x + "_" + (y + 1) +"_" + 0, (x + 1) + "_" + (y + 1) + "_" + 0, (x + 1) + "_" + y + "_" + 0], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, y*ld), new Point((widthSegments - x)*wd, (y + 1)*ld), new Point((widthSegments - x - 1)*wd, (y + 1)*ld), faceId);
}
}
if (triangulate) {
bottom.addFace(faceId + ":0");
bottom.addFace(faceId + ":1");
} else {
bottom.addFace(faceId);
}
}
}
// Построение фронтальной грани
for (z = 0; z < heightSegments; z++) {
for (x = 0; x < widthSegments; x++) {
faceId = "front_"+x+"_"+z;
if (reverse) {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, z*hd);
cUV = new Point((widthSegments - x - 1)*wd, (z + 1)*hd);
createFace([x + "_" + 0 + "_" + z, x + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + (z + 1)], faceId + ":1");
setUVsToFace(aUV, new Point((widthSegments - x)*wd, (z + 1)*hd), cUV, faceId + ":1");
createFace([(x + 1) + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + z, x + "_" + 0 + "_" + z], faceId + ":0");
setUVsToFace(cUV, new Point((widthSegments - x - 1)*wd, z*hd), aUV, faceId + ":0");
} else {
createFace([x + "_" + 0 + "_" + z, x + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + (z + 1), (x + 1) + "_" + 0 + "_" + z], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, z*hd), new Point((widthSegments - x)*wd, (z + 1)*hd), new Point((widthSegments - x - 1)*wd, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point(x*wd, z*hd);
cUV = new Point((x + 1)*wd, (z + 1)*hd);
createFace([x + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + (z + 1)], faceId + ":0");
setUVsToFace(aUV, new Point((x + 1)*wd, z*hd), cUV, faceId + ":0");
createFace([(x + 1) + "_" + 0 + "_" + (z + 1), x + "_" + 0 + "_" + (z + 1), x + "_" + 0 + "_" + z], faceId + ":1");
setUVsToFace(cUV, new Point(x*wd, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([x + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + z, (x + 1) + "_" + 0 + "_" + (z + 1), x + "_" + 0 + "_" + (z + 1)], faceId);
setUVsToFace(new Point(x*wd, z*hd), new Point((x + 1)*wd, z*hd), new Point((x + 1)*wd, (z + 1)*hd), faceId);
}
}
if (triangulate) {
front.addFace(faceId + ":0");
front.addFace(faceId + ":1");
} else {
front.addFace(faceId);
}
}
}
// Построение задней грани
for (z = 0; z < heightSegments; z++) {
for (x = 0; x < widthSegments; x++) {
faceId = "back_"+x+"_"+z;
if (reverse) {
if (triangulate) {
aUV = new Point(x * wd, (z + 1) * hd);
cUV = new Point((x + 1) * wd, z * hd);
createFace([x + "_" + lengthSegments+"_" + (z + 1), x + "_"+lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + z], faceId + ":0");
setUVsToFace(aUV, new Point(x * wd, z * hd), cUV, faceId + ":0");
createFace([(x + 1) + "_" + lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + (z + 1), x + "_" + lengthSegments + "_" + (z + 1)], faceId + ":1");
setUVsToFace(cUV, new Point((x + 1) * wd, (z + 1) * hd), aUV, faceId + ":1");
} else {
createFace([x + "_" + lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + z, (x + 1) + "_" + lengthSegments + "_" + (z + 1), x + "_" + lengthSegments + "_" + (z + 1)], faceId);
setUVsToFace(new Point(x*wd, z*hd), new Point((x + 1)*wd, z*hd), new Point((x + 1)*wd, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point((widthSegments - x)*wd, (z + 1)*hd);
cUV = new Point((widthSegments - x - 1)*wd, z*hd);
createFace([x + "_" + lengthSegments + "_" + z, x + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + z], faceId + ":0");
setUVsToFace(new Point((widthSegments - x)*wd, z*hd), aUV, cUV, faceId + ":0");
createFace([x + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + z], faceId + ":1");
setUVsToFace(aUV, new Point((widthSegments - x - 1)*wd, (z + 1)*hd), cUV, faceId + ":1");
} else {
createFace([x + "_" + lengthSegments + "_" + z, x + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + (z + 1), (x + 1) + "_" + lengthSegments + "_" + z], faceId);
setUVsToFace(new Point((widthSegments - x)*wd, z*hd), new Point((widthSegments - x)*wd, (z + 1)*hd), new Point((widthSegments - x - 1)*wd, (z + 1)*hd), faceId);
}
}
if (triangulate) {
back.addFace(faceId + ":0");
back.addFace(faceId + ":1");
} else {
back.addFace(faceId);
}
}
}
// Построение левой грани
for (y = 0; y < lengthSegments; y++) {
for (z = 0; z < heightSegments; z++) {
faceId = "left_" + y + "_" + z;
if (reverse) {
if (triangulate) {
aUV = new Point(y*ld, (z + 1)*hd);
cUV = new Point((y + 1)*ld, z*hd);
createFace([0 + "_" + y + "_" + (z + 1), 0 + "_" + y + "_" + z, 0 + "_" + (y + 1) + "_" + z], faceId + ":0");
setUVsToFace(aUV, new Point(y*ld, z*hd), cUV, faceId + ":0");
createFace([0 + "_" + (y + 1) + "_" + z, 0 + "_" + (y + 1) + "_" + (z + 1), 0 + "_" + y + "_" + (z + 1)], faceId + ":1");
setUVsToFace(cUV, new Point((y + 1)*ld, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([0 + "_" + y + "_" + z, 0 + "_" + (y + 1) + "_" + z, 0 + "_" + (y + 1) + "_" + (z + 1), 0 + "_" + y + "_" + (z + 1)], faceId);
setUVsToFace(new Point(y*ld, z*hd), new Point((y + 1)*ld, z*hd), new Point((y + 1)*ld, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point((lengthSegments - y - 1)*ld, z*hd);
cUV = new Point((lengthSegments - y)*ld, (z + 1)*hd);
createFace([0 + "_" + (y + 1) + "_" + z, 0 + "_" + y + "_" + z, 0 + "_" + y + "_" + (z + 1)], faceId + ":0");
setUVsToFace(aUV, new Point((lengthSegments - y)*ld, z*hd), cUV, faceId + ":0");
createFace([0 + "_" + y + "_" + (z + 1), 0 + "_" + ((y + 1)) + "_" + (z + 1), 0 + "_" + (y + 1) + "_" + z], faceId + ":1");
setUVsToFace(cUV, new Point((lengthSegments - y - 1)*ld, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([0 + "_" + y + "_" + z, 0 + "_" + y + "_" + (z + 1), 0 + "_" + ((y + 1)) + "_" + (z + 1), 0 + "_" + ((y + 1)) + "_" + z], faceId);
setUVsToFace(new Point((lengthSegments - y)*ld, z*hd), new Point((lengthSegments - y)*ld, (z + 1)*hd), new Point((lengthSegments - y - 1)*ld, (z + 1)*hd), faceId);
}
}
if (triangulate) {
left.addFace(faceId + ":0");
left.addFace(faceId + ":1");
} else {
left.addFace(faceId);
}
}
}
// Построение правой грани
for (y = 0; y < lengthSegments; y++) {
for (z = 0; z < heightSegments; z++) {
faceId = "right_" + y + "_" + z;
if (reverse) {
if (triangulate) {
aUV = new Point((lengthSegments - y)*ld, z*hd);
cUV = new Point((lengthSegments - y - 1)*ld, (z + 1)*hd);
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + y + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + (z + 1)], faceId + ":1");
setUVsToFace(aUV, new Point((lengthSegments - y)*ld, (z + 1)*hd), cUV, faceId + ":1");
createFace([widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + z, widthSegments + "_" + y + "_" + z], faceId + ":0");
setUVsToFace(cUV, new Point((lengthSegments - y - 1)*ld, z*hd), aUV, faceId + ":0");
} else {
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + y + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + (y + 1) + "_" + z], faceId);
setUVsToFace(new Point((lengthSegments - y)*ld, z*hd), new Point((lengthSegments - y)*ld, (z + 1)*hd), new Point((lengthSegments - y - 1)*ld, (z + 1)*hd), faceId);
}
} else {
if (triangulate) {
aUV = new Point(y*ld, z*hd);
cUV = new Point((y + 1)*ld, (z + 1)*hd);
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + (y + 1) + "_" + z, widthSegments + "_" + (y + 1) + "_" + (z + 1)], faceId + ":0");
setUVsToFace(aUV, new Point((y + 1)*ld, z*hd), cUV, faceId + ":0");
createFace([widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + y + "_" + (z + 1), widthSegments + "_" + y + "_" + z], faceId + ":1");
setUVsToFace(cUV, new Point(y*ld, (z + 1)*hd), aUV, faceId + ":1");
} else {
createFace([widthSegments + "_" + y + "_" + z, widthSegments + "_" + (y + 1) + "_" + z, widthSegments + "_" + (y + 1) + "_" + (z + 1), widthSegments + "_" + y + "_" + (z + 1)], faceId);
setUVsToFace(new Point(y*ld, z*hd), new Point((y + 1)*ld, z*hd), new Point((y + 1)*ld, (z + 1)*hd), faceId);
}
}
if (triangulate) {
right.addFace(faceId + ":0");
right.addFace(faceId + ":1");
} else {
right.addFace(faceId);
}
}
}
}
/**
* @inheritDoc
*/
protected override function createEmptyObject():Object3D {
return new Box(0, 0, 0, 0);
}
}
}

View File

@@ -0,0 +1,264 @@
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);
}
}
}

View File

@@ -0,0 +1,197 @@
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 {
/**
* Создает геоплоскость.
* <p>Геоплоскость это плоскость с сетчатой структурой граней.</p>
* <p>Примитив после создания содержит в cебе одну или две поверхности, в зависимости от значения параметров.
* При значении <code>reverse</code> установленном в <code>true</code> примитив будет содержать грань - <code>"back"</code>.
* При значении <code>reverse</code> установленном в <code>false</code> примитив будет содержать грань - <code>"front"</code>.
* Параметр <code>twoSided</code> указывает методу создать обе поверхности.</p>
*
* @param width ширина. Размерность по оси X. Не может быть меньше нуля.
* @param length длина. Размерность по оси Y. Не может быть меньше нуля.
* @param widthSegments количество сегментов по ширине
* @param lengthSegments количество сегментов по длине
* @param twoSided если значение параметра равно <code>true</code>, то создаётся двусторонняя поверхность
* @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);
}
}
}

View File

@@ -0,0 +1,321 @@
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;
import alternativa.types.Point3D;
use namespace alternativa3d;
/**
* Геосфера.
*/
public class GeoSphere extends Mesh {
/**
* Создает геосферу.
* <p>Геосфера после создания содержит в себе одну поверхность с идентификатором по умолчанию.</p>
* <p>Текстурные координаты у геосферы не находятся в промежутке <code>[0, 1]</code>,
* поэтому для материала с текстурой необходимо устанавливать флаг repeat.
*
* @param radius радиус геосферы. Не может быть меньше нуля.
* @param segments количество сегментов геосферы
* @param reverse флаг направления нормалей. При значении <code>true</code> нормали направлены внуть геосферы.
*/
public function GeoSphere(radius:Number = 100, segments:uint = 2, reverse:Boolean = false) {
if (segments == 0) {
return;
}
radius = (radius < 0)? 0 : radius;
const sections:uint = 20;
//var nfaces:uint = sections*segments*segments;
//var nverts:Number = nfaces/2 + 2;
var points:Array = new Array();
var i:uint;
var f:uint;
var theta:Number;
var sin:Number;
var cos:Number;
// z расстояние до нижней и верхней крышки полюса
var subz:Number = 4.472136E-001*radius;
// радиус на расстоянии subz
var subrad:Number = 2*subz;
points.push(createVertex(0, 0, radius, "poleUp"));
// Создание вершин верхней крышки
for (i = 0; i < 5; i++) {
theta = MathUtils.DEG360*i/5;
sin = Math.sin(theta);
cos = Math.cos(theta);
points.push(createVertex(subrad*cos, subrad*sin, subz));
}
// Создание вершин нижней крышки
for (i = 0; i < 5; i++) {
theta = MathUtils.DEG180*((i << 1) + 1)/5;
sin = Math.sin(theta);
cos = Math.cos(theta);
points.push(createVertex(subrad*cos, subrad*sin, -subz));
}
points.push(createVertex(0, 0, -radius, "poleDown"));
for (i = 1; i < 6; i++) {
interpolate(0, i, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i, i % 5 + 1, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i, i + 5, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i, (i + 3) % 5 + 6, segments, points);
}
for (i = 1; i < 6; i++) {
interpolate(i + 5, i % 5 + 6, segments, points);
}
for (i = 6; i < 11; i++) {
interpolate(11, i, segments, points);
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + f*(segments - 1) + i, 12 + (f + 1) % 5*(segments - 1) + i, i + 1, points);
}
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + (f + 15)*(segments - 1) + i, 12 + (f + 10)*(segments - 1) + i, i + 1, points);
}
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + ((f + 1) % 5 + 15)*(segments - 1) + segments - 2 - i, 12 + (f + 10)*(segments - 1) + segments - 2 - i, i + 1, points);
}
}
for (f = 0; f < 5; f++) {
for (i = 1; i <= segments - 2; i++) {
interpolate(12 + ((f + 1) % 5 + 25)*(segments - 1) + i, 12 + (f + 25)*(segments - 1) + i, i + 1, points);
}
}
// Создание граней
var face:Face;
var surface:Surface = createSurface();
for (f = 0; f < sections; f++) {
for (var row:uint = 0; row < segments; row++) {
for (var column:uint = 0; column <= row; column++) {
var a:uint = findVertices(segments, f, row, column);
var b:uint = findVertices(segments, f, row + 1, column);
var c:uint = findVertices(segments, f, row + 1, column + 1);
var va:Vertex = points[a];
var vb:Vertex = points[b];
var vc:Vertex = points[c];
var aUV:Point;
var bUV:Point;
var cUV:Point;
var coordA:Point3D = va._coords;
var coordB:Point3D = vb._coords;
var coordC:Point3D = vc._coords;
if (coordA.y >= 0 && (coordA.x < 0) && (coordB.y < 0 || coordC.y < 0)) {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 - 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
} else {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 + 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordB.y >= 0 && (coordB.x < 0) && (coordA.y < 0 || coordC.y < 0)) {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 - 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
} else {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 + 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordC.y >= 0 && (coordC.x < 0) && (coordA.y < 0 || coordB.y < 0)) {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 - 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
} else {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 + 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
}
// полюс
if (a == 0 || a == 11) {
aUV.x = bUV.x + (cUV.x - bUV.x)*0.5;
}
if (b == 0 || b == 11) {
bUV.x = aUV.x + (cUV.x - aUV.x)*0.5;
}
if (c == 0 || c == 11) {
cUV.x = aUV.x + (bUV.x - aUV.x)*0.5;
}
if (reverse) {
face = createFace([va, vc, vb], (column << 1) + "_" + row + "_" + f);
aUV.x = 1 - aUV.x;
bUV.x = 1 - bUV.x;
cUV.x = 1 - cUV.x;
setUVsToFace(aUV, cUV, bUV, face);
} else {
face = createFace([va, vb, vc], (column << 1) + "_" + row + "_" + f);
setUVsToFace(aUV, bUV, cUV, face);
}
surface.addFace(face);
//trace(a + "_" + b + "_" + c);
if (column < row) {
b = findVertices(segments, f, row, column + 1);
var vd:Vertex = points[b];
coordB = vd._coords;
if (coordA.y >= 0 && (coordA.x < 0) && (coordB.y < 0 || coordC.y < 0)) {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 - 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
} else {
aUV = new Point(Math.atan2(coordA.y, coordA.x)/MathUtils.DEG360 + 0.5, Math.asin(coordA.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordB.y >= 0 && (coordB.x < 0) && (coordA.y < 0 || coordC.y < 0)) {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 - 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
} else {
bUV = new Point(Math.atan2(coordB.y, coordB.x)/MathUtils.DEG360 + 0.5, Math.asin(coordB.z/radius)/MathUtils.DEG180 + 0.5);
}
if (coordC.y >= 0 && (coordC.x < 0) && (coordA.y < 0 || coordB.y < 0)) {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 - 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
} else {
cUV = new Point(Math.atan2(coordC.y, coordC.x)/MathUtils.DEG360 + 0.5, Math.asin(coordC.z/radius)/MathUtils.DEG180 + 0.5);
}
if (a == 0 || a == 11) {
aUV.x = bUV.x + (cUV.x - bUV.x)*0.5;
}
if (b == 0 || b == 11) {
bUV.x = aUV.x + (cUV.x - aUV.x)*0.5;
}
if (c == 0 || c == 11) {
cUV.x = aUV.x + (bUV.x - aUV.x)*0.5;
}
if (reverse) {
face = createFace([va, vd, vc], ((column << 1) + 1) + "_" + row + "_" + f);
aUV.x = 1 - aUV.x;
bUV.x = 1 - bUV.x;
cUV.x = 1 - cUV.x;
setUVsToFace(aUV, bUV, cUV, face);
} else {
face = createFace([va, vc, vd], ((column << 1) + 1) + "_" + row + "_" + f);
setUVsToFace(aUV, cUV, bUV, face);
}
surface.addFace(face);
}
}
}
}
}
/* private function getUVSpherical(point:Point3D, radius:Number = 0, reverse:Boolean = false):Point {
if (radius == 0) {
radius = point.length;
}
if (reverse) {
var u:Number = 0.5 - Math.atan2(point.y, point.x)/MathUtils.DEG360;
} else {
u = Math.atan2(point.y, point.x)/MathUtils.DEG360 + 0.5;
}
return new Point(u, Math.asin(point.z/radius)/MathUtils.DEG180 + 0.5);
}
*/
private function interpolate(v1:uint, v2:uint, num:uint, points:Array):void {
if (num < 2) {
return;
}
var a:Vertex = Vertex(points[v1]);
var b:Vertex = Vertex(points[v2]);
var cos:Number = (a.x*b.x + a.y*b.y + a.z*b.z)/(a.x*a.x + a.y*a.y + a.z*a.z);
cos = (cos < -1) ? -1 : ((cos > 1) ? 1 : cos);
var theta:Number = Math.acos(cos);
var sin:Number = Math.sin(theta);
for (var e:uint = 1; e < num; e++) {
var theta1:Number = theta*e/num;
var theta2:Number = theta*(num - e)/num;
var st1:Number = Math.sin(theta1);
var st2:Number = Math.sin(theta2);
points.push(createVertex((a.x*st2 + b.x*st1)/sin, (a.y*st2 + b.y*st1)/sin, (a.z*st2 + b.z*st1)/sin));
}
}
private function findVertices(segments:uint, section:uint, row:uint, column:uint):uint {
if (row == 0) {
if (section < 5) {
return (0);
}
if (section > 14) {
return (11);
}
return (section - 4);
}
if (row == segments && column == 0) {
if (section < 5) {
return (section + 1);
}
if (section < 10) {
return ((section + 4) % 5 + 6);
}
if (section < 15) {
return ((section + 1) % 5 + 1);
}
return ((section + 1) % 5 + 6);
}
if (row == segments && column == segments) {
if (section < 5) {
return ((section + 1) % 5 + 1);
}
if (section < 10) {
return (section + 1);
}
if (section < 15) {
return (section - 9);
}
return (section - 9);
}
if (row == segments) {
if (section < 5) {
return (12 + (5 + section)*(segments - 1) + column - 1);
}
if (section < 10) {
return (12 + (20 + (section + 4) % 5)*(segments - 1) + column - 1);
}
if (section < 15) {
return (12 + (section - 5)*(segments - 1) + segments - 1 - column);
}
return (12 + (5 + section)*(segments - 1) + segments - 1 - column);
}
if (column == 0) {
if (section < 5) {
return (12 + section*(segments - 1) + row - 1);
}
if (section < 10) {
return (12 + (section % 5 + 15)*(segments - 1) + row - 1);
}
if (section < 15) {
return (12 + ((section + 1) % 5 + 15)*(segments - 1) + segments - 1 - row);
}
return (12 + ((section + 1) % 5 + 25)*(segments - 1) + row - 1);
}
if (column == row) {
if (section < 5) {
return (12 + (section + 1) % 5*(segments - 1) + row - 1);
}
if (section < 10) {
return (12 + (section % 5 + 10)*(segments - 1) + row - 1);
}
if (section < 15) {
return (12 + (section % 5 + 10)*(segments - 1) + segments - row - 1);
}
return (12 + (section % 5 + 25)*(segments - 1) + row - 1);
}
return (12 + 30*(segments - 1) + section*(segments - 1)*(segments - 2)/2 + (row - 1)*(row - 2)/2 + column - 1);
}
/**
* @inheritDoc
*/
protected override function createEmptyObject():Object3D {
return new GeoSphere(0, 0);
}
}
}

View File

@@ -0,0 +1,117 @@
package alternativa.engine3d.primitives {
import alternativa.engine3d.*;
import alternativa.engine3d.core.Mesh;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Surface;
import flash.geom.Point;
use namespace alternativa3d;
/**
* Плоскость.
*/
public class Plane extends Mesh {
/**
* Создает плоскость.
* <p>Примитив после создания содержит в cебе одну или две поверхности, в зависимости от значения параметров.
* При значении <code>reverse</code> установленном в <code>true</code> примитив будет содержать грань - <code>"back"</code>.
* При значении <code>reverse</code> установленном в <code>false</code> примитив будет содержать грань - <code>"front"</code>.
* Параметр <code>twoSided</code> указывает методу создать обе поверхности.</p>
*
* @param width ширина. Размерность по оси Х. Не может быть меньше нуля.
* @param length длина. Размерность по оси Y. Не может быть меньше нуля.
* @param widthSegments количество сегментов по ширине
* @param lengthSegments количество сегментов по длине
* @param twoSided если значении параметра равно <code>true</code>, то формируется двусторонняя плоскость
* @param reverse инвертирование нормалей
* @param triangulate флаг триангуляции. Если указано значение <code>true</code>, четырехугольники в плоскости будут триангулированы.
*/
public function Plane(width:Number = 100, length:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, twoSided:Boolean = true, reverse:Boolean = false, triangulate: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 lh:Number = length/2;
// Размеры сегмента
var ws:Number = width/widthSegments;
var ls:Number = length/lengthSegments;
// Размеры UV-сегмента
var wd:Number = 1/widthSegments;
var ld:Number = 1/lengthSegments;
// Создание точек и UV
var x:int;
var y:int;
var uv:Array = new Array();
for (y = 0; y <= lengthSegments; y++) {
uv[y] = new Array();
for (x = 0; x <= widthSegments; x++) {
uv[y][x] = new Point(x*wd, y*ld);
createVertex(x*ws - wh, y*ls - lh, 0, x+"_"+y);
}
}
// Создание поверхностей
var front:Surface;
var back:Surface;
if (twoSided || !reverse) {
front = createSurface(null, "front");
}
if (twoSided || reverse) {
back = createSurface(null, "back");
}
// Создание полигонов
for (y = 0; y < lengthSegments; y++) {
for (x = 0; x < widthSegments; x++) {
if (twoSided || !reverse) {
if (triangulate) {
createFace([x + "_" + y, (x + 1) + "_" + y, (x + 1) + "_" + (y + 1)], "front" + x + "_" + y + ":0");
setUVsToFace(uv[y][x], uv[y][x + 1], uv[y + 1][x + 1], "front" + x + "_" + y + ":0");
createFace([(x + 1) + "_" + (y + 1), x + "_" + (y + 1), x + "_" + y], "front" + x + "_" + y + ":1");
setUVsToFace(uv[y + 1][x + 1], uv[y + 1][x], uv[y][x], "front" + x + "_" + y + ":1");
front.addFace("front" + x + "_" + y + ":0");
front.addFace("front" + x + "_" + y + ":1");
} else {
createFace([x + "_" + y, (x + 1) + "_" + y, (x + 1) + "_" + (y + 1), x + "_" + (y + 1)], "front" + x + "_" + y);
setUVsToFace(uv[y][x], uv[y][x + 1], uv[y + 1][x + 1], "front" + x + "_" + y);
front.addFace("front" + x + "_" + y);
}
}
if (twoSided || reverse) {
if (triangulate) {
createFace([x + "_" + y, x + "_" + (y + 1), (x + 1) + "_" + (y + 1)], "back" + x + "_" + y + ":0");
setUVsToFace(uv[lengthSegments - y][x], uv[lengthSegments - y - 1][x], uv[lengthSegments - y - 1][x + 1], "back" + x + "_" + y + ":0");
createFace([(x + 1) + "_" + (y + 1), (x + 1) + "_" + y, x + "_" + y], "back" + x + "_" + y + ":1");
setUVsToFace(uv[lengthSegments - y - 1][x + 1], uv[lengthSegments - y][x + 1], uv[lengthSegments - y][x], "back" + x + "_" + y + ":1");
back.addFace("back" + x + "_" + y + ":0");
back.addFace("back"+x+"_"+y + ":1");
} else {
createFace([x + "_" + y, x + "_" + (y + 1), (x + 1) + "_" + (y + 1), (x + 1) + "_" + y], "back" + x + "_" + y);
setUVsToFace(uv[lengthSegments - y][x], uv[lengthSegments - y - 1][x], uv[lengthSegments - y - 1][x + 1], "back" + x + "_" + y);
back.addFace("back" + x + "_" + y);
}
}
}
}
}
/**
* @inheritDoc
*/
protected override function createEmptyObject():Object3D {
return new Plane(0, 0, 0);
}
}
}

View File

@@ -0,0 +1,144 @@
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);
}
}
}