1. Текстури.
2. Математика перетворень з текстурами.
1. Текстури.
Текстури – це растрові малюнки, які накладаються на грань об'ємної фігури (рис.9.1). У цьому розділі ми будемо використовувати паралельну проекцію (без урахування перспективних спотворень, які суттєво ускладнюють справу). У цьому прикладі текстури використовуються на кожній грані куба, його можна обертати в різні боки мишкою і клавішами-стрілками. Натиснувши на кнопці із зображенням маленького кубика можна встановити його в початкове положення, яке відповідає ізометричній проекції, яка не спотворює пропорції. Довжини всіх ребер куба тут однакові, кут між ребрами дорівнює 120 °. Для побудови ізометрії кубик потрібно спочатку повернути на 45 ° щодо осі Y, а потім – на 30 ° щодо осі X:
rotate3D (vert, pt3D (0, 45, 0));
rotate3D (vert, pt3D (30, 0, 0));
2. Математика перетворень з текстурами.
Тепер настав час спробувати розібратися в математиці такого перетворення. Зліва на схемі показаний бажаний паралелограм, а праворуч – вихідний прямокутник, повернений на 45 ° (рис.9.2). Тут через p0 позначена точка реєстрації кліпів, а через pH і pW – кутові точки, що визначають висоту і ширину паралелограма. Тангенси кутів α1 і α2 можуть бути знайдені з формул, а самі кути – за допомогою функції Math.atan2. Тут через Δx позначена різниця x-координат точок, а через Δy – різниця їх y-координат. Тоді внутрішній кут паралелограма, позначений як 2α, обчислюється як різниця 2 • α = 180 ° - α1 - α2. Цей кут потрібно отримати масштабуванням вихідного прямокутника (на малюнку праворуч) тільки по осі Y. Позначимо коефіцієнт масштабу через k, він дорівнює масштабному коефіцієнту, який потрібно застосувати для головного кліпу. При y-масштабуванні всі вертикальні розміри множаться на k, а горизонтальні – зберігаються. Тепер знайдемо масштабні коефіцієнти kx і ky для вкладеного кліпу. Позначимо через w – довжину ребра, що з'єднує точки p0 і pW, а через w0 – потрібну ширину внутрішнього кліпу-прямокутника. З огляду на масштабування головного кліпу, аналогічні вирази можна записати і для висоти. Створіть новий файл типу ActionScript File, запишіть в нього код функції зсуву:
function skewClip (clip, p0, pW, pH, w, h) {
function dX (p1, p2) {return p1.x - p2.x;
}
function dY (p1, p2) {return p1.y - p2.y;
}
function dist (p1, p2) {
var dx = dX (p1, p2), dy = dY (p1, p2);
return Math.sqrt (dx * dx + dy * dy);
}
var a, a1, a2, da, s, scale;
clip._x = p0.x; clip._y = p0.y;
clip._xscale = 100;
clip._rotation = 0;
a1 = Math.atan2 (dX (pW, p0), dY (p0, pW));
a2 = Math.atan2 (dX (pH, p0), dY (pH, p0));
a = (Math.PI - a1 - a2) / 2;
scale = Math.tan (a);
clip._yscale = 100 * scale;
da = Math.PI / 2 - a - a1;
clip._rotation - = da * 180 / Math.PI;
s = dist (p0, pW);
q = Math.sin (a) /scale*Math.sqrt (2);
clip.inner._xscale = 100 * s * q / w;
s = dist (p0, pH);
clip.inner._yscale = 100 * s * q / h;
}
Збережемо файл під ім'ям skew.as. Ця функція в точності реалізує описаний вище алгоритм. У ній введені внутрішні функції dX, dY і dist, які дозволяють визначити різницю x-координат, різницю y-координат і відстань між двома точками. Розглянемо приклад, в якому обертається одна грань з накладеною текстурою. Відкрємо файл texture.fla:
#include "3d.as" #include "skew.as" this.createEmptyMovieClip ( "scene", 1);
scene._x = 275; scene._y = 200;
Цей код стандартний і не вимагає пояснень. Додайте до кадру 1 код:
fig = new Object ();
fig.vert = [pt3D (-50,50,0),
pt3D (-50, -50,0),
pt3D (50, -50,0),
pt3D (50,50,0)];
fig.faucet = [[0, 1, 2, 3]];
fig.bitmap = [1];
Тут створюється об'єкт, який має поля vert (вершини), faucet (межі) і bitmap (малюнки). Важливо, що в масиві faucet перший номер вершини відповідає точці pH, другий – точці p0, а третій – точці pW (рис.9.2). Цей порядок буде використовуватися при накладенні текстури. Всі малюнки записані в бібліотеку у вигляді кліпів pic1, pic2, ..., pic6. Додайте до кадру 1 код:
scene.createEmptyMovieClip ( "faucet0", 1);
scene.faucet0.attachMovie ( "pic" + fig.bitmap [0], "inner", 1);
scene.faucet0.inner._rotation = -45;
Усередині кліпу scene створюється кліп faucet0, що представляє грань. Символ з текстурою приєднується до нього як внутрішній кліп inner. Ім'я кліпу в бібліотеці будується з рядка "pic" і номера рисунка для даної грані, який зберігається в масиві bitmap. Внутрішній кліп відразу повертається на 45 ° проти годинникової стрілки. Додайте до кадру 1 код:
w0 = 100;
h0 = 100;
rotate3D (fig.vert, pt3D (0,45,45));
showFigureBmp (fig);
function showFigureBmp (fig) {
var v = fig.faucet [0];
var pH = fig.vert [v [0]];
var p0 = fig.vert [v [1]];
var pW = fig.vert [v [2]];
skewClip (scene.faucet0, p0, pW, pH, w0, h0);
}
Змінні w0 і h0 задають ширину і висоту малюнків. Грань відразу повертається на 45 ° по осях Y і Z і виводиться за допомогою функції showFigureBmp. Ця функція зводиться до визначення потрібних вершин і викликом функції skewClip. Додайте до кадру 1 код обробника:
scene.onEnterFrame = function () {
rotate3D (fig.vert, pt3D (2,0,2));
showFigureBmp (fig);
}
Збережіть файл і перевірте роботу кліпу При зміні кадру фігура повертається на 2 ° по осях X і Z. Виникає питання: «Як накласти текстуру на фігуру іншої форми (трикутник, трапецію тощо). Найпростіший спосіб – використовувати маску, тобто накладати текстуру на прямокутник, але непотрібну частину відсікати за допомогою маски. Збережемо файл під ім'ям cube_texture.fla і доопрацюємо його так, щоб на екрані вийшов куб, що обертається, всі 6 граней якого залиті текстурами. При виконанні цієї роботи потрібно враховувати, що видимість граней тепер визначається не порядком малювання, а глибиною кожної грані-кліпу. Тому після Z-сортування потрібно використовувати метод swapDepths, який переводить кліп на потрібний рівень.