Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Семестр2_lr.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.27 Mб
Скачать

Лабораторная работа 10 Программное рисование трёхмерных объектов

Цель работы:

1). Изучить: общие принципы программного построения простейших трёхмерных моделей; использование аффинных преобразований для получения проекций вращения трёхмерных моделей; использование фокусного расстояния при расчёте перспективного проецирования.

2). Создать приложение для управления вращением трёхмерного графического объекта вдоль осей X, Y и Z на плоском фоне.

Порядок выполнения работы:

1. Создайте новый проект с названием "lab10".

2. Используйте классы Main и Graphics2D из предыдущей работы.

3. По аналогии класса Graphics2D создайте новый класс Graphics3D для рисования трёхмерных графических объектов с помощью полигонов.

4. В конструкторе класса Graphics3D определите следующие прототипы:

MovieClip.prototype.vertex3D = new Array();

MovieClip.prototype.polygons = new Array();

MovieClip.prototype.setVertex = setVertex;

MovieClip.prototype.setPolygon = setPolygon;

MovieClip.prototype.render = render;

MovieClip.prototype.rotate = rotate;

5. Так же используются следующие глобальные переменные:

var vertex3D, polygons:Array;

var rgb, alpha:Number;

var matrix:Object;

6. Методы setVertex() и setPolygon() предназначены соответственно для заполнения массивов координат вершин и порядок построения полигонов по этим вершинам (четыре вершины – a, b, c, d):

public function setVertex(x:Number, y:Number, z:Number) {

vertex3D.push({x:x, y:y, z:z});

}

public function setPolygon(a:Number, b:Number, c:Number, d:Number, rgb, alpha) {

polygons.push({vertices:[a, b, c, d], rgb:rgb, alpha:alpha});

}

7. При рисовании граней трёхмерной модели на одном плоском графическом уровне, необходимо определять, какая из граней будет ближе к наблюдателю, чем все остальные так, чтобы не было перекрытия. Для этого используется массив depths для хранения информации о порядке граней:

public function render(focalLength:Number) {

...

var vertex2D:Array = new Array();

var depths:Array = new Array();

for (var i = 0; i<polygons.length; i++) {

var zDepth:Number = 0;

for (var j = 0; j<polygons[i].vertices.length; j++) {

var zVertex:Array = polygons[i].vertices[j];

if (!vertex2D[zVertex]) {

vertex2D[zVertex] = new Object();

var scale:Number = focalLength/(focalLength-vertex3D[zVertex].z);

vertex2D[zVertex].x = vertex3D[zVertex].x*scale;

vertex2D[zVertex].y = vertex3D[zVertex].y*scale;

}

zDepth += vertex3D[zVertex].z;

}

depths.push([polygons[i], zDepth]);

}

depths.sort(function (a:Number, b:Number) {

return a[1]>b[1];

});

for (var i = 0; i<depths.length; i++) {

var zPolygon:Array = depths[i][0].vertices;

this.moveTo(vertex2D[zPolygon[0]].x, vertex2D[zPolygon[0]].y);

this.beginFill(depths[i][0].rgb, depths[i][0].alpha);

for (var j = 1; j<zPolygon.length; j++) {

this.lineTo(vertex2D[zPolygon[j]].x,vertex2D[zPolygon[j]].y);

}

this.lineTo(vertex2D[zPolygon[0]].x, vertex2D[zPolygon[0]].y);

this.endFill();

}

}

8. Единственным аргументом метода render() является переменная focalLength, которая учитывается при расчёте перспективной проекции.

9. Теперь, например, для того, чтобы задать некоторый четырёхугольный полигон в трёхмерной системе координат, в классе Main необходимо сделать вызов следующих методов:

var cube:MovieClip = bounds.createEmptyMovieClip("cube", 1);

cube.setVertex(-75, -75, 75);

cube.setVertex(75, -75, 75);

cube.setVertex(75, -75, -75);

cube.setVertex(-75, -75, -75);

cube.setPolygon(0, 1, 2, 3, 0xff0000, 50);

10. Прорисовку графического объекта с помощью метода render() необходимо делать в каждом кадре, очищая перед выводом экран с помощью метода clear(), а также указывать тип линии рисования lineStyle().

11. Задайте рисование правильного куба в пространстве. Все грани закрасьте шестью основными цветами. Измените степень прозрачности (рис. 13).

Рис. 13. Куб с разной степенью прозрачности граней: 0% (слева), 100%(в центре) и 50% (справа)

12. Для того, чтобы вращать или перемещать трёхмерный объект в пространстве, необходимо использовать аффинные преобразования. Для этого необходимо создать новый класс Matrix, конструктор которого будет пустым, а основным методом будет transformMatrix() следующей структуры:

private function transformMatrix(matrix:Object) {

if (complete) {

var move:Object = new Object();

move.a = matrix.a*a+matrix.b*d+matrix.c*g;

...

a = move.a;

...

} else {

a = matrix.a;

...

}

complete = true;

}

13. Переменная matrix представляет собой объект с девятью свойствами: a, b, c, d, e, f, g, h, i для хранения текущей матрицы аффинных преобразований.

14. Три других метода rotateX(), rotateY() и rotateZ() соответственно будут представлять собой аффинные преобразования при вращении вдоль соответствующих осей. Из каждого такого метода должно быть задано обращение к методу transformMatrix() с соответствующей матрицей аффинных преобразований, например, для метода rotateX(angle):

sin = Math.sin(angle*Math.PI/180);

cos = Math.cos(angle*Math.PI/180);

transformMatrix({a:1, b:0, c:0, d:0, e:cos, f:sin, g:0, h:-sin, i:cos});

15. Для вызова этих методов из класса Main одновременно в классе Graphics3D создайте один метод rotate() с тремя аргументами – углами.

16. В самое начало метода render() необходимо добавить следующий фрагмент умножения матрицы трансформации на координаты вершин, взятых из массива vertex3D. При условии наличия заполненного объекта matrix должен выполняться цикл и последующее удаление объекта:

for (var i = 0; i<vertex3D.length; i++) {

var move:Object = vertex3D[i];

var x:Number = matrix.a*move.x+matrix.b*move.y+matrix.c*move.z;

...

move.x = x;

...

}

delete matrix;

17. Для того, чтобы более гибко управлять вращением куба, можно использовать обработку нажатий кнопки мыши и замедление вращения.

Также можно включить управление значением focalLength для метода render() с помощью колёсика прокрутки мыши на площади фонового объекта bounds, к которому должен быть прикреплён объект cube.

Контрольные вопросы:

1). Для чего используется переменная zDepth в методе render()?

2). Каким образом происходит сортировка элементов массива depths?

3). В чём смысл использования логической переменной complete?

4). Для чего используется переменная move’ в методе render()?

5). Что происходит при уменьшении значения focalLength?