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

Тема: Робота з 3D об’єктами у Flash

План

1. Переміщення спостерігача за допомогою клавіш.

2. Бібліотека для роботи з фігурами.

1. Переміщення спостерігача за допомогою клавіш.

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

Розглянемо приклад анімації (рис.8.1), керованої клавішами-стрілками. Клавіші «вгору» і «вниз» переміщують спостерігача вперед і назад, клавіші «вліво» і «вправо» повертають його у відповідному напрямку. Якщо утримувати клавішу Shift, клавіші «вгору» і «вниз» змінюють висоту очей спостерігача. Використання бібліотек для роботи з фігурами.

2. Бібліотека для роботи з фігурами.

Для того, щоб побудувати такий фільм, ми спочатку створимо невелику бібліотеку функцій для роботи з тривимірною графікою. Для опису фігури будемо використовувати структуру, показану на рисунку. Вона містить три поля (властивості):

Як бачимо, це ті ж дані, які використовувалися для опису піраміди в попередній лекції, тільки вони об'єднані в одну структуру. Спочатку напишемо функцію moveBy, яка переміщує фігуру на вектор (a, b, c). Це означає, що до x-координатами всіх вершин потрібно додати a, до y-координат додати b і до z-координат додати c. При цьому початок координат переміщається в точку (a, b, c). Для такого переміщення потрібно зробити цикл по масиву вершин vert і для кожної з них виконати код:

vert [i] .x + = a;

vert [i] .y + = b;

vert [i] .z + = c;

Для зручності три координати вектора переміщення записуються в одну структуру, яка може бути побудована за допомогою функції pt3D (її код знаходиться в файлі 3D.as). Створимо новий документ типу ActionScript File та запишемо в нього код функції переміщення:

function moveBy (fig, way) {

var i; for (i = 0; i

with (fig.vert [i]) {

x + = way.x; y + = way.y; z + = way.z;

}

}

}

Збережемо файл під ім'ям figures3D.as. У цій функції два параметри – посилання на фігуру (вірніше, на область, де зберігаються її дані), і вектор переміщення way. Далі створимо функцію, яка будує прямокутний паралелепіпед (блок, «цеглина»). Так можна, наприклад, моделювати будинок. Ця функція повинна приймати в параметрах розміри блоку, масив з 6 елементів, що задає кольори граней, і початкову точку. В якості точки прив'язки виберемо лівий нижній кут ближній до нас межі. Якщо початкове положення не задано, ця точка поміщається в початок координат. Додайте в файл figures3D.fla код функції:

function brick (dx, dy, dz, color, place) {

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

if () {

a = place.x; b = place.y; c = place.z;

}

rect.vert = [pt3D (0, 0, dz), pt3D (0, -dy, dz),

pt3D (dx, -dy, dz), pt3D (dx, 0, dz),

pt3D (0, 0, 0), pt3D (0, -dy, 0),

pt3D (dx, -dy, 0), pt3D (dx, 0, 0)];

rect.faucet = [[0, 1, 2, 3], [2, 3, 7, 6],

[5, 6, 7, 4], [1, 5, 4, 0],

[1, 2, 6, 5], [0, 3, 7, 4]];

rect.color = color; moveBy (rect, pt3D (a, b, c));

return rect;

У функції створюється новий об'єкт rect (рис.8.2), що має поля vert, faucet і color. Параметри dx, dy і dz задають його розміри, масив color – кольору граней, а додатковий параметр place – це координати точки, куди потрібно перемістити точку прив'язки з початку координат.

Масив точок і вершин будується так само, як і раніше, для переміщення використовується тільки що написана функція moveBy. Зверніть увагу, що в наведеному варіанті функції brick масив color не буде копіюватися, а просто в поле rect.color записується посилання на нього (адреса). Це означає наступне: якщо ми створюємо два блоки, використовуючи один і той же масив color, і потім змінимо цей масив, то зміняться кольори обох блоків. Щоб цього не сталося, можна створювати масив заново і копіювати значення, передані через параметр:

rect.color = new Array ();

for (i = 0; i

rect.color [i] = color [i];

У цій програмі ми будемо працювати з декількома об'єктами, які можуть перекривати один одного. Щоб враховувати це, потрібно зібрати всі грані разом, в одному об'єкті, і застосувати єдине Z-сортування. Наступна функція додає до об'єкта-фігури fig нову фігуру newFig того ж типу, яка передається як другий параметр. Фактично при цьому зливаються їх масиви vert, faucet і color, в результаті будується один об'єкт, що описує всі грані обох вихідних фігур. Для злиття масивів використовується метод concat (concatenation – з'єднання, зчіпка). Наприклад, у результаті виконання коду:

a = [1, 2, 3];

b = [4, 5];

c = a.concat (b);

створюється новий масив c з елементами [1,2,3,4,5]. Додайте в файл figures3D.fla код функції:

function addFigure (fig, newFig) {

var nPrev = fig.vert.length;

var i, k, n;

fig.vert = fig.vert.concat (newFig.vert);

for (i = 0; i

n = newFig.faucet [i] .length;

for (k = 0; k

}

fig.faucet = fig.faucet.concat (newFig.faucet);

fig.color = fig.color.concat (newFig.color);

}

При злитті масивів важливо не забути перетворити масив faucet, який описує межі другої фігури, що приєднується. У ньому до злиття вказані номери вершин саме для другої фігури, а після злиття там повинні бути номери тих же вершин, але в загальній нумерації. Наприклад, якщо перша фігура включала 5 вершин, номери вершин другої фігури в загальному списку будуть починатися з 5. Отже, перед злиттям з масиві faucet фігури newFig потрібно збільшити номери всіх вершин на 5. Ось як це зроблено у функції:

var nPrev = fig.vert.length;

for (i = 0; i

n = newFig.faucet [i] .length;

for (k = 0; k

}

Спочатку викликається функція perspective (з файлу 3D.as), яка розраховує ефект перспективи для заданого фокуса. Потім за допомогою функції midPointZ для всіх граней обчислюється z-координата середньої точки, за якою виконується сортування. Нарешті в циклі для кожної грані викликається функція малювання drawFaucet. Додайте в файл figures3D.fla код функції:

function midPointsZ (fig) {

var i, j, k, nPoints, sumZ;

var mid = new Array ();

for (i = 0; i

sumZ = 0; nPoints = fig.faucet [i] .length;

for (j = 0;

k = fig.faucet [i] [j]; (5)

sumZ + = ptScreen [k] .z; );

}

sumZ / = nPoints;

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

}

return mid;

}

Наступна функція, showFigures, призначена для малювання всіх граней в потрібному порядку. Додайте в файл figures3D.fla код функції:

function showFigures (fig) {

var i, midScreen;

ptScreen = perspective (fig.vert, focalLength);

midScreen = midPointsZ (fig);

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

scene.clear ();

for (i = 0; i

}

Спочатку викликається функція perspective (з файлу 3D.as), яка розраховує ефект перспективи для заданого фокуса. Потім за допомогою функції midPointZ для всіх граней обчислюється z-координата середньої точки, за якою виконується сортування. Нарешті в циклі для кожної грані викликається функція малювання drawFaucet. Додайте в файл figures3D.fla код функції:

function midPointsZ (fig) {

var i, j, k, nPoints, sumZ;

var mid = new Array ();

for (i = 0; i

sumZ = 0; nPoints = fig.faucet [i] .length;

for (j = 0; j

k = fig.faucet [i] [j];

sumZ + = ptScreen [k] .

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

}

sumZ / = nPoints;

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

}

return mid;

}

У порівнянні з попереднім варіантом (див. лекція 8) функція midPointsZ працює для будь-якого числа вершин (а не тільки для трьох). Єдине, що потрібно – вершини в масиві faucet повинні бути перераховані в порядку їх обходу при побудові контуру. Нова версія функції drawFaucet також працює для будь-якого числа вершин, вони перебираються в циклі. Добавте у файл figures3D.fla код функції функції:

drawFaucet (рис, midPoint) {

якщо (midPoint.z

var id = midPoint.id; з (сцена) {

beginFill (fig.color [id], 100);

var k0 = fig.faucet [id] [0];

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

для (var i = 1; i

var k = fig.faucet [id] [i];

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

}

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

endFill ();

}

}

Збережемо остаточний варіант бібліотек функцій. На початку цієї функції добавлена стрічка (midPoint.z за допомогою якої здійснюється поворот. Ми вважаємо, що спостерігач знаходиться в точці з координатами (0,0, -focalLength), тому всі грані, що опинилися позаду нього (що мають меншу z-координату, ніж –focalLength) не малюються, оскільки відбувається вихід із функції по оператору return.

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

Тема: Робота з 3D об’єктами у Flash