Дисципліна: Засоби програмування комп'ютерної графіки

Тема: Використання тривимірних зображень у Flash

План

1. Вступ.

2. Використання аналітичної геометрії.

3. Створення 3D об’єктів.

4. Керування 3D об’єктами за допомогою клавіш.

1. Вступ.

Програма Flash спочатку була призначена для двомірної графіки (малюнки на площині), і в ній немає спеціальних засобів для створення тривимірних ефектів. Тому досить складно зробити якісну тривимірну анімацію ¬– накладати текстури (малюнки) на поверхні об'єктів, створювати детальні природні сцени.

Але дещо все-таки зробити можна. Існує два підходи: використання серії попередньо побудованих зображень, побудованих в програмах тривимірного моделювання (3ds max, True Space, Swift 3D); побудова зображень за допомогою програми на ActionScript.

Перший спосіб призводить, як правило, до серйозного збільшення обсягу Flash-фільму, оскільки всі малюнки повинні зберігатися всередині нього. При цьому втрачається головна перевага застосування Flash-анімацій в Інтернеті. Крім того, анімація обмежена заздалегідь заданими набором зображень. Другий спосіб вимагає досить серйозного програмування і розуміння математики тривимірного світу. Крім того, складні обчислення сильно навантажують процесор, і тому в анімації рекомендується використовувати не більше 30 кліпів, керованих з програми.

2. Використання аналітичної геометрії.

У просторі точка описується трьома координатами. Існує багато способів визначити координати, але найчастіше використовується прямокутна система координат, показана на рисунку 7.1.

Осі X і Y спрямовані так, як у звичайній декартовій системі на площині. Вісь Z йде перпендикулярно осям X і Y, вона йде від глядача так, що точки з позитивними значеннями z-координати знаходяться «за» екраном (площиною перегляду), а точки з негативними z-координатами – перед екраном.

Z-координата потрібна для того, щоб визначати, які об'єкти розташовані ближче, а які далі. Зображення починається з далеких об'єктів, причому об'єкти, які опинилися повністю закритими іншими об'єктами, не потрібно перемальовувати взагалі. Враховуючи перспективу необхідно враховувати, що розмір віддалених об'єктів менший, ніж ближніх. Для побудови 3D об’єтів потрібно створити новий документ типу ActionScript File і зберегти його, задавши ім'я 3D.fla та додати у цей файл код функції:

function pt3D (x, y, z) {

var p = {x: x, y: y, z: z};

return p;

}.

Ця проста функція служить для створення об'єкта-точки з заданими координатами. Цей об'єкт має властивості x, y і z. Об'єкти такого типу ми будемо використовувати для опису фігур в просторі. Всі точки тривимірного простору ми бачимо на плоскому екрані, в проекції на цей екран. Для спрощення можна не враховувати перспективу. Це означає, що видимі розміри віддалених предметів не будуть змінюватися. В цьому випадку z-координата потрібна тільки для того, щоб визначити порядок малювання об'єктів (спочатку далекі, потім ближні). Всі точки, які мають однакові координати x і y, проектуються в одну і ту ж точку на екрані. Для перетворення просторових координат точки в екранні координати потрібно врахувати два моменти:

Щоб «забути» про все це, можна відразу ставити координати об'єктів в пікселях, а для осі Y використовувати координати з протилежним знаком. Розглянемо три основні типи перетворення координат.

Масштабування (зміна розмірів), коли всі координати множаться на постійну величину k (масштаб):

X = k • x; Y = k • y; Z = k • z.

Тут і далі (x, y, z) позначають вихідні координати точки, а (X, Y, Z) – нові координати, після перетворення. При переміщенні (паралельний перенос) передбачається, що початок координат переміщається в точку (a, b, c), причому координати всіх точок змінюються однаково:

X = x + a;

Y = y + b;

Z = z + c;

Ще один спосіб перетворення координат є обертання, яке можна розкласти на три обертання щодо кожної з осей координат. Можна показати, що при обертанні навколо осі Z на певний кут зміна координат задається формулами:

Якщо не брати до уваги вісь Z, фактично – це поворот відносно початку координат на площині XOY (рис. 7.2). Для того, щоб повернути точку навколо іншого центру, скажімо, точки з координатами (a, b, c) необхідно спочатку перенести початок координат в точку (a, b, c), потім виконати обертання і, нарешті, зробити зворотний перенос. Формули виглядають наступним чином:

Аналогічні формули можна записати для обертання щодо осі X:

і щодо осі Y:

Додайте в файл 3D.as код функції, яка виконує поворот масиву точок на задані кути щодо трьох координатних осей:

function rotate3D (points, angles, center)

{

var g2R = Math.PI / 180;

var sx = Math.sin (angles.x * g2R);

var cx = Math.cos (angles.x * g2R);

var sy = Math.sin (angles.y * g2R);

var cy = Math.cos (angles.y * g2R);

var sz = Math.sin (angles.z * g2R);

var cz = Math.cos (angles.z * g2R);

var x, y, z, xy, xz, yx, yz, zx, zy, scale;

var a = 0, b = 0, c = 0;

if

a = center.x;

b = center.y;

c = center.z;

}

for (i = 0; i

x = points [i] .x - a;

y = points [i] .y - b;

z = points [i] .z - c;

// обертання навколо осі x

xy = cx * y - sx * z;

xz = sx * y + cx * z;

// обертання навколо осі y

yz = cy * xz - sy * x;

yx = sy * xz + cy * x;

// обертання навколо осі z

zx = cz * yx - sz * xy;

zy = sz * yx + cz * xy;

// збереження нових координат

points [i] .x = zx + a;

points [i] .y = zy + b;

points [i] .z = yz + c;

}

}

Ця функція приймає три параметри:

Функція виконує три послідовних повороту: спочатку поворот щодо осі X, потім – щодо осі Y і наостанок – щодо осі Z. Параметр center можна не вказувати, тоді обертання виконується щодо початку координат. На початку функції вводяться допоміжні локальні змінні. Тут g2R – коефіцієнт для перекладу кута з градусів в радіани, ще 6 змінних використовуються для попереднього обчислення синусів і косинусів цих кутів (не потрібно буде повторювати розрахунки для кожної точки!). В змінні a, b і c записуються координати центру обертання. За замовчуванням всі вони дорівнюють нулю.Оператор спрацьовує тоді, коли кількість аргументів, передане функції, більше двох.

До аргументів функції можна звернутися за допомогою масиву arguments, довжина якого дорівнює їх кількості. В даному випадку arguments [0] – це параметр points, arguments [1] – це angles тощо. Основна частина функції – цикл по всіх точках масиву points. Спочатку виконується перенесення початку координат в точку (a, b, c). Потім послідовно робимо повороти на задані кути і записуємо в той же масив points змінені координати. Відразу додаємо до отриманими значеннями x, y і z відповідно a, b і c – це зворотний перенос початку координат в початкове положення.

У перспективі всі об'єкти вдалині здаються менші за розміром (рис. 7.3). Аналогічний ефект потрібно забезпечити і при проектуванні тривимірного світу на плоский екран.

Нехай об'єкт має висоту h і координати (x, y, z). Як випливає з подібності трикутників на малюнку, зображення на екрані буде мати висоту:

H = h • F / (F + z), (5)

де F – відстань від ока до екрана, зване фокусом.

Таким чином, всі розміри множаться на коефіцієнт p = F / (F + z);. Крім того, на цей же коефіцієнт потрібно помножити x-координату та y-координату всіх точок, які знаходяться на даній глибині (мають однакову z-координату). Таким чином, при обліку перспективи змінюється не тільки розмір, але і видиме розташування об'єктів на екрані.

Зауважимо, що при зменшенні фокуса ефект перспективи посилюватиметься, при збільшенні – послаблюватися.

Додайте в кінець файлу 3D.as функцію, яка будує масив видимих точок з урахуванням перспективи:

function perspective (points, focalLength) {

var pt2D = [];

var i, x, y, z, scale;

for (i = 0; i

x = points [i] .x * scale;

y = points [i] .y * scale;

z = points [i] .z;

pt2D [i] = {x: x, y: y, z: z, scale: scale, id: i};

}

return pt2D;

};

Збережіть файл.

Функція приймає два параметри:

points – масив координат точок, кожен елемент якого містить поля x, y і z;

vy - = 2 * vn * n1y;

focalLength – фокус.

Тут, на відміну від функції обертання, будується новий масив точок, а не змінюється старий. Елемент нового масиву має не тільки поля x, y і z (видимі координати), але і ще два додаткових поля:

scale – масштаб, коефіцієнт перспективи;

id (код, ідентифікатор) – номер точки у вихідному масиві.

Таким чином, ми створили файл, який містить всі необхідні нам функції для створення і перетворення координат точок в просторі.

3. Створення 3D об’єктів.

Наприклад, створимо напівпрозору пірамідку (рис. 7.4), що обертається за допомогою клавіш-стрілок. Дамо новому документу ім'я pyramid.fla. Додамо в кадр 1 код:

#include "3d.as"

this.createEmptyMovieClip ( "scene", 1);

scene._x = 275;

Координати всіх вершин піраміди запишемо у масив vert. На рисунку 7.5 показана піраміда і дві її проекції (вид зверху і вид збоку), вершини позначені номерами (нумерація з нуля!).

В основі піраміди лежить рівносторонній трикутник, всі сторони якого рівні a, а всі кути – 60 °. За допомогою простих розрахунків можна показати, що його висота визначається формулою:

h = a • sqrt (2/3),

де sqrt () позначає квадратний корінь. Ми розташуємо початок координат так, щоб основа піраміди була паралельною площині XOZ;

вісь Y проходила через вершину;

точка (0,0,0) ділить висоту, опущену з вершини на основу, у відношенні 1: 2.

Зауважте, що ми вже врахували, що вісь Y направлена вниз, і y-координата вершини негативна, тоді як y-координати кутів основи позитивні. Таким чином, отримуємо наступні координати вершин:

вершина 0: x = a / 2, y = h / 3, z = a • sqrt (3) / 6;

вершина 1: x = 0, y = h / 3, z = -a • sqrt (3) / 3;

вершина 2: x = a / 2, y = h / 3, z = a • sqrt (3) / 6;

вершина 3: x = a / 2, y = -2 • h / 3, z = 0.

Вони записуються в масив vert за допомогою функції pt3D.

Додамо до кадру 1 код:

a = 200;

sq3 = Math.sqrt (3);

h = a * Math.sqrt (2/3);

b = h / 3;

t = 2 * h / 3;

vert = [pt3D (a / 2, b, a * sq3 / 6),

pt3D (0, b, -a * sq3 / 3),

pt3D (-a / 2, b, a * sq3 / 6),

pt3D (0, -t, 0)];

Мінлива sq3 тут введена для того, щоб не обчислювати кілька разів квадратний корінь з трьох. У цьому завданні потрібно не просто міняти координати точок, а й малювати межі – трикутники, що формують боку піраміди. Щоб визначити межу, ми просто перелічимо номера вершин, через які вона проходить.

Додайте до кадру 1 код:

faucet = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]];

color = [0xFFFFFF, 0xFF0000, 0xFF00, 0xFF];

showFigure ();

Масив faucet складається з чотирьох масивів (4 грані). У кожному з цих внутрішніх масивів перераховані номери вершини, наприклад, грань 0 проходить через вершини 0, 1 і 2.

У масив color записується колір кожної з граней. Тут грань 0 – білого кольору, грань 1 – червоного, грань 2 – зеленого і грань 3 – синього.

Функція showFigure, яка викликається в останній сходинці нового блоку, малює фігуру. При цьому важливо спочатку намалювати віддалені межі, а потім вже ближні, тобто потрібна Z-сортування. Ми вже використовували Z-сортування для точок, тепер потрібно застосувати її для граней, з першого погляду ця задача нетривіальна. Однак можна звести рішення до вже відомого результату – застосувати Z-сортування для центральних точок граней, координати яких знаходяться як середнє арифметичне координат її вершин. Добавмо до кадру 1 код функції:

function showFigure () {

var i, midScreen;

ptScreen = perspective (vert, focalLength);

midScreen = midPointsZ ();

midScreen.sortOn ( "z", Array.DESCENDING + Array.NUMERIC);

scene.clear ();

for (i = 0; i

drawFaucet (midScreen [i] .id);

}

Спочатку координати вершин з масиву vert перетворюються в екранні «видимі» координати з урахуванням перспективи. Це робить функція perspective, яку ми записали в файл 3D.as.

Далі в рядку midScreen = midPointsZ () будується масив, кожен елемент якого містить два поля: z – z-координата центральної точки (інші її координати взагалі не потрібні), і id – номер межі у вихідному масиві (для того, щоб знайти її після Z-сортування).

За допомогою методу sortOn центральні точки упорядковано відповідно до зменшення z-координати (від далеких до ближніх) і в циклі будуються всі межі. Функцію drawFaucet, яка виконує рисування межі з заданим номером, ми напишемо далі.

Додайте код функції:

function midPointsZ () {

var i, z;

var mid = new Array ();

for (i = 0; i

z = (ptScreen [faucet [i] [0]]. z +

ptScreen [faucet [i] [1]]. z +

ptScreen [faucet [i] [2]]. z) / 3;

mid [i] = {id: i, z: z};

}

return mid;

}

Ця функція дуже проста, вона вважає для кожної грані z-координату центральної точки як середнє арифметичне z-координат її вершин і повертає новий масив.

Додамо код функції для побудови межі:

function drawFaucet (id) {

var i1 = faucet [id] [0];

var i2 = faucet [id] [1];

var i3 = faucet [id] [2];

with (scene) {

beginFill (color [id], 60);

moveTo (ptScreen [i1] .x, ptScreen [i1] .y);

lineTo (ptScreen [i2] .x, ptScreen [i2] .y);

lineTo (ptScreen [i3] .x, ptScreen [i3] .y);

lineTo (ptScreen [i1] .x, ptScreen [i1] .y);

endFill ();

}

}

Параметр функції id – це номер потрібної межі. Спочатку номера точок «витягуються» з масиву faucet і записуються в змінні i1, i2 і i3. Потім на кліпі scene програмним методом малюється грань (заливка). Зверніть увагу, що обхід контуру виконується в тому ж порядку, в якому перераховані точки в масиві faucet. Для трикутних граней це неважливо, але для більш складних (наприклад, чотирикутників) неправильний порядок точок призводить до неправильного зображенню.

Стиль заливки визначається рядком beginFill (color [id], 60).

Це означає, що з масиву color беремо колір потрібної межі, і встановлюємо прозорість 60%.

4. Керування 3D об’єктами за допомогою клавіш.

Тепер залишається додати обробник натискання клавіші, що дозволяє обертати фігуру навколо осей X і Y. Він точно такий же, як і в попередньому прикладі. Додайте до кадру 1 код:

Key.addListener (scene);

scene.onKeyDown = function () {

ax = ay = az = 0;

switch (Key.getCode ()) {

case Key.LEFT: ay = -5; break;

case Key.RIGHT: ay = 5; break;

case Key.UP: ax = -5; break;

case Key.DOWN: ax = 5; break;

}

rotate3D (vert, pt3D (ax, ay, az));

showFigure ();

}

Дисципліна: Засоби програмування комп'ютерної графіки

Тема: Використання тривимірних зображень у Flash