Пример простой 3D визуализации
Прочитав
- Object3D - прототип 3D объекта;
- Sphere - параметрически описанный объект сферы
- View3D - класс, рисующий 3D объект
- Main - основной класс документа
Смотреть
Сегодня я просто выложу исходники, а теорию разберем в другой раз (если это кому-нибудь станет интересно)
Класс Object3D:
package lib3d {
/**
* @author Michael
*/
public class Object3D extends Object {
public var tilesArray : Array = new Array;
public var tilesColors : Array = new Array;
private var _nMesh : Number = 10;
public function set nMesh(n : Number) : void {
_nMesh = n;
setTilesArray();
}
public function get nMesh() : Number {
return _nMesh ;
}
public function Object3D() {
setTilesArray();
}
public function setTilesArray() : void {
}
}
}
Класс Sphere:
package lib3d {
import lib3d.Object3D;
/**
* @author Michael
*/
public class Sphere extends Object3D {
public function Sphere() {
super();
}
override public function setTilesArray() : void {
var i : int;
var j : int;
var istep : Number;
var jstep : Number;
istep = 1.75 * Math.PI / nMesh;
jstep = Math.PI / nMesh;
tilesArray = new Array();
for(i = 0;i <= nMesh; i++) {
tilesArray[i] = new Array();
for(j = 0;j <= nMesh;j++) {
tilesArray[i][j] =
[
90 * Math.cos(istep * i) * Math.sin(jstep * j),
90 * Math.sin(istep * i) * Math.sin(jstep * j),
90 * Math.cos(jstep * j)
];
}
}
}
}
}
Класс View3D:
package lib3d {
import flash.display.Shape;
import flash.display.Sprite;
/**
* @author Michael
*/
public class View3D extends Sprite {
private var shCube : Shape = new Shape();
private var tilesArray : Array = new Array;
private var tilesColors : Array = new Array;
private var nMesh : Number = 0;
private var renderObject:Object3D;
public var fLen : Number = 1000;
public var firstRun : Boolean = true;
public function View3D(obj : Object3D) {
renderObject = obj;
addChild(shCube);
Init();
}
public function Init():void{
tilesArray = renderObject.tilesArray;
tilesColors = renderObject.tilesColors;
nMesh = renderObject.nMesh;
firstRun = true;
}
public function renderView(t : Number,p : Number) : void {
var i : int;
var j : int;
var n : int;
var distArray:Array = new Array();
var dispArray:Array = new Array();
var tilesNewArray:Array = new Array();
var midPoint : Array = new Array();
var dist : Number;
var depLen : Number;
var coloFactor:Number = 1.5;
t = t * Math.PI / 180;
p = p * Math.PI / 180;
shCube.graphics.clear();
for(i = 0;i <= nMesh;i++) {
tilesNewArray[i] = new Array();
for(j = 0;j <= nMesh;j++) {
// Задаем новые координаты с учетом поворота
tilesNewArray[i][j] = pointNewView(tilesArray[i][j], t, p);
}
}
for(i = 0;i < nMesh;i++) {
if(firstRun) {
tilesColors[i] = new Array();
}
// Вычисляем среднюю точку для сортировки
for(j = 0;j < nMesh;j++) {
midPoint[0] =
(
tilesNewArray[i][j][0] +
tilesNewArray[i + 1][j][0] +
tilesNewArray[i][j + 1][0] +
tilesNewArray[i + 1][j + 1][0]
) / 4;
midPoint[1] =
(
tilesNewArray[i][j][1] +
tilesNewArray[i + 1][j][1] +
tilesNewArray[i][j + 1][1] +
tilesNewArray[i + 1][j + 1][1]
) / 4;
midPoint[2] =
(
tilesNewArray[i][j][2] +
tilesNewArray[i + 1][j][2] +
tilesNewArray[i][j + 1][2] +
tilesNewArray[i + 1][j + 1][2]
) / 4;
dist = Math.sqrt(Math.pow(fLen - midPoint[0], 2) +
Math.pow(midPoint[1], 2) +
Math.pow(midPoint[2], 2)
);
distArray.push([dist,i,j]);
if(firstRun) {
tilesColors[i][j] = combineRGB(
(2 * coloFactor * midPoint[2] + 100) * 0.8 + 70,
(2 * coloFactor * midPoint[1] + 100) * 0.8 + 70,
(2 * coloFactor * midPoint[0] + 100) * 0.8 + 70);
}
}
}
// Сортируем по средним точкам для прорисовки
distArray.sort(byDist);
for(i = 0;i <= nMesh;i++) {
dispArray[i] = [];
for(j = 0;j <= nMesh;j++) {
dispArray[i][j] = [fLen / (fLen - tilesNewArray[i][j][0]) * tilesNewArray[i][j][1],
-fLen / (fLen - tilesNewArray[i][j][0]) * tilesNewArray[i][j][2]];
}
}
depLen = distArray.length;
shCube.graphics.lineStyle(0, 0x333333,0.2);
for(n = 0;n < depLen;n++) {
i = distArray[n][1];
j = distArray[n][2];
shCube.graphics.moveTo(dispArray[i][j][0], dispArray[i][j][1]);
shCube.graphics.beginFill(tilesColors[i][j], 1);
shCube.graphics.lineTo(dispArray[i][j + 1][0], dispArray[i][j + 1][1]);
shCube.graphics.lineTo(dispArray[i + 1][j + 1][0], dispArray[i + 1][j + 1][1]);
shCube.graphics.lineTo(dispArray[i + 1][j][0], dispArray[i + 1][j][1]);
shCube.graphics.lineTo(dispArray[i][j][0], dispArray[i][j][1]);
shCube.graphics.endFill();
}
firstRun = false;
}
private function pointNewView(v : Array, theta : Number, phi : Number) : Array {
var newCoords : Array = [];
newCoords[0] = v[0] * Math.cos(theta) * Math.sin(phi) +
v[1] * Math.sin(theta) * Math.sin(phi) +
v[2] * Math.cos(phi);
newCoords[1] = -v[0] * Math.sin(theta) + v[1] * Math.cos(theta);
newCoords[2] = -v[0] * Math.cos(theta) * Math.cos(phi) -
v[1] * Math.sin(theta) * Math.cos(phi) +
v[2] * Math.sin(phi);
return newCoords;
}
private function combineRGB(red : Number,green : Number,blue : Number) : Number {
var RGB : Number;
if(red > 255) {
red = 255;
}
if(green > 255) {
green = 255;
}
if(blue > 255) {
blue = 255;
}
if(red < 0) {
red = 0;
}
if(green < 0) {
green = 0;
}
if(blue < 0) {
blue = 0;
}
RGB = ( red << 16 ) | ( green << 8 ) | blue;
return RGB;
}
private function byDist(v : Array,w : Array) : Number {
if (v[0] > w[0]) {
return -1;
} else if (v[0] < w[0]) {
return 1;
} else {
return 0;
}
}
}
}
Класс Main:
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import fl.controls.Slider;
import fl.events.SliderEvent;
import lib3d.Sphere;
import lib3d.View3D;
/**
* @author Michael
*/
public class Main extends Sprite {
private var sphere : Sphere;
private var sphereView : View3D;
private var doRotate : Boolean = false;
private var prevX : Number;
private var prevY : Number;
private var curTheta : Number = -10;
private var curPhi : Number = 60;
private var shBack : Sprite = new Sprite();
private var mySlider : Slider = new Slider();
private var info:TextField = new TextField();
public function Main() {
// Создаем объект "Сфера"
sphere = new Sphere();
// Создаем "просмотрщик" 3D-объекта
sphereView = new View3D(sphere);
sphereView.x = 300;
sphereView.y = 200;
// Рисуем бакграунд
drawBack();
// Добавляем слайдер для указания количества поверхностей объекта
addChild(mySlider);
mySlider.y=380;
mySlider.x=200;
mySlider.width=200;
mySlider.minimum=10;
mySlider.maximum=30;
mySlider.value=20;
mySlider.name="MySlider";
mySlider.liveDragging = true;
mySlider.addEventListener(SliderEvent.CHANGE, sliderChange);
addChild(info);
info.x=420;
info.y=375;
info.height=20;
info.text = 'Детализация: '+ String(mySlider.value);
shBack.addChild(sphereView);
// Начальная прорисовка 3D-объекта
sphere.nMesh = mySlider.value;
sphereView.Init();
sphereView.renderView(curTheta, curPhi);
// Добавляем обработчики мыши для поворота объекта
shBack.addEventListener(MouseEvent.ROLL_OUT, boardOut);
shBack.addEventListener(MouseEvent.MOUSE_MOVE, boardMove);
shBack.addEventListener(MouseEvent.MOUSE_DOWN, boardDown);
shBack.addEventListener(MouseEvent.MOUSE_UP, boardUp);
}
// Обработчик слайдера
private function sliderChange(event : SliderEvent) : void {
sphere.nMesh = mySlider.value;
sphereView.Init();
sphereView.renderView(curTheta, curPhi);
info.text = 'Детализация: '+ String(mySlider.value);
}
private function drawBack() : void {
shBack.graphics.lineStyle(1, 0x000000);
shBack.graphics.beginFill(0x000000);
shBack.graphics.drawRect(0, 0, 600, 360);
shBack.graphics.endFill();
addChild(shBack);
}
// Обработчики событий мыши
private function boardOut(e : MouseEvent) : void {
doRotate = false;
}
private function boardDown(e : MouseEvent) : void {
prevX = mouseX;
prevY = mouseY;
doRotate = true;
}
private function boardUp(e : MouseEvent) : void {
doRotate = false;
}
private function boardMove(e : MouseEvent) : void {
var locX : Number = prevX;
var locY : Number = prevY;
if(doRotate) {
prevX = mouseX;
prevY = mouseY;
curTheta -= (prevX - locX);
curPhi -= (prevY - locY);
// Прорисовываем с новыми углами поворота
sphereView.renderView(curTheta, curPhi);
e.updateAfterEvent();
}
}
}
}
Ууууу какой замечательный кАмпакт-диск ©Масяня