Враховуючи обидва кроки, пояснення об'єднання яких ви ходить за межі даного посібника, загальне перетворення систе ми координат xyz у систему x'y'z' задається таким записом:
coscp |
- sin ф sin у |
sincpcosy |
А= sincp |
coscpsin\(i |
-coscpcosy |
0 |
cosy |
siny |
Це означає, що точка (х; у; z) із заданої поверхні переходить у точку (х'; у') на картинній площині, де
х' = х coscp + у snup, у' = -х sincp sin\|/ + у coscp simp + z cosy. Можна визначити і зворотне перетворення, яке описується
такими співвідношеннями:
х = х' coscp - у' sincp sinij/ + z' cos\|/ sincp; у = x' sincp + y' sinv|/ coscp - z' cosy coscp; z = y' cosi|/ + z' siny.
Останнє представлення значень x, у, z через x'y'z' дає змо гу виконати заміну змінних і отримати рівняння поверхні F(x', у', z') = 0 у новій системі координат x'y'z', в якій уже на прям проектування паралельний осі Oz' і проектування ведеть ся на площину х'Оу'. Надалі координати х', у', z' будемо позна чати через х, у, z. Отримане перетворене рівняння поверхні можна представити у вигляді z = f(x, у).
Тепер переходимо до другої, основної частини побудови про екції заданої поверхні на площину. Для кращого подальшого розуміння алгоритму уявимо собі, як можна цю поверхню на малювати на аркуші паперу. Нехай глибина малюнка спрямо вана уздовж осі Oz. Якщо уявити собі, що ми малюємо поверх ню, просуваючись з певним кроком по осі Oz від найближчої частини малюнка до найдальшої, то це будуть зображення його перерізів, для яких значення z буде сталим. Малювання логічно почати із найближчого перерізу: фрагмент поверхні, що належить йому, буде зображено повністю. Далі у решти пе рерізів малюватимемо лише ті частини фрагментів поверхні, що «виглядатимуть» із-за тих, що вже намальовані.
Тепер перейдемо на мову математики. Розглянемо побудову графіків функцій, що відповідають сталим значенням z. Це оз начає, що для кожного z, що змінюється у циклі від zx до z2 (zt < z2), перебираються значення х із деякого діапазону і таким чином підраховуються точки (х; у; z), що лежать на поверхні.
Описана послідовність дій дає змогу побудувати графік функції двох змінних без усунення невидимих ліній, однак таке зображення поверхні буде не зовсім зрозумілим. У зв'язку з цим постає задача про таку побудову поверхні, при якій би усувались невидимі лінії.
Зведемо тривимірну задачу до двовимірної: вся задана по верхня може бути представлена у вигляді послідовності ліній
312
у = f(x, z), які лежать у паралель |
У |
|
|
|
|
|||
|
|
|
|
|||||
них площинах 2 = 2; і не перетина |
|
|
|
|
||||
ються (мал. 176). |
|
|
|
|
— - |
|
||
Отже, маємо такий алгоритм по |
|
|
|
|
||||
|
|
|
|
|
||||
|
|
|
|
|
|
r |
|
|
будови графіка функції у = f(x, z): |
|
|
У S |
|||||
|
|
|
||||||
для кожної площини z =ziy поряд |
|
|
|
|||||
ку зростання г, |
починаючи |
з най |
|
|
|
|
||
|
|
|
|
|
|
|
|
[y=f(X,2) |
ближчої |
точки |
спостереження, |
|
zt |
/ |
^—>¥ |
||
|
|
|
|
|||||
|
|
|
|
|
||||
виводяться лінії і при зображенні |
|
|
|
|
|
|||
поточної |
лінії |
виводиться |
лише |
|
|
|
|
|
о |
|
|
X |
|||||
та її частина, яка не закриваєть |
|
Мал. 176 |
||||||
ся раніше |
виведеними лініями. |
|
|
|
||||
Якщо у деякій площині z = const |
|
|
|
|
|
|||
при деякому х одержується точка у, більша за всі попередні у, то дана точка видима, у протилежному випадку - невидима. Для визначення тих частин лінії у = f(x, z), які не закривають ся попередньо намальованими лініями, вводяться до розгляду дві лінії горизонту - верхня та нижня.
Визначимо поетапне виконання алгоритму плаваючого го ризонту.
На першому кроці виконання алгоритму лінії горизонту не розглядаються, оскільки перший розріз поверхні для z1 розміщений ближче до спостерігача, ніж інші, нічим не закри вається і тому він виводиться повністю. На цьому самому кроці визначаються перші значення ліній горизонту, які будуть ви користані на наступному кроці: для кожного значення х визна чається максимальне та мінімальне значення у.
Друга лінія теж повністю виводиться, а лінії горизонту ко регуються так: нижня лінія горизонту в усіх своїх точках х дорівнює мінімуму серед значень у для двох уже виведених ліній, а верхня лінія - максимуму.
Розглянемо область екрана між верхньою та нижньою лінією горизонту - вона є проекцією частини графіка функції
у = f(x, z) у смузі z1<z < z2. Для інших ліній у = f(x, z) при і > 2
ті частини ліній, які при проектуванні потрапляють в область між двома лініями горизонту, стають невидимими. Кожна нас тупна лінія буде виводитися лише для тих значень х, для яких її проекція лежить поза межами області, що задається двома лініями горизонту.
Роботу цього алгоритму на конкретному прикладі можна на очно пояснити так. Нехай необхідно зобразити панораму па горбів, що розміщені один за одним. Якщо на передньому плані знаходитиметься найвищий пагорб, то визначене на цьому кроці максимальне і мінімальне значення ліній горизонту буде залишатися і на наступних кроках найбільшим, а тому на ек рані монітора за першим пагорбом сховаються всі решта. Якщо
313
ж пагорби будуть упорядковані за зростанням їх висоти, тобто на першому плані знаходитиметься найнижчий з них, потім наступний за висотою і т. д., а останнім - найвищий, то на кож ному кроці виконання алгоритму значення максимальної та мінімальної ліній горизонту будуть корегуватися - максималь на збільшуватиметься, а мінімальна зменшуватиметься. Та ким чином, у результаті на екрані монітора можна буде побачи ти, як за кожним із пагорбів виглядає наступний.
Таким чином, тепер алгоритм виглядає так: якщо при деяко му значенні х значення у на поточній кривій більше за відповідне значення з верхнього горизонту або менше за зна чення нижнього горизонту, то точка у видима, у протилежно му випадку - невидима.
Пояснимо математично основні моменти, на яких базується описаний алгоритм. Нехай проекцією лінії у = f(x, zt) на кар тинну площину є лінія у = yt(x), де (х; у) - координати точки на картинній площині. Тоді контурні лінії у™"* (х) і у™п (х) визнача ються такими співвідношеннями:
уГх(х)=тахуі(х), у™п(х)= тіп Уі(х).
На екран виводяться тільки ті частини лінії у = yh{x), які знаходяться вище від лінії у™ах(х) або нижче від лінії у™т(х).
Є різні способи представлення ліній горизонту, але однією з найпростіших і найефективніших реалізацій цього методу є ре алізація, при якій кожна лінія горизонту задається набором значень з кроком 1 піксель, тобто для кожного цілого значення змінної х (хтіп < х < хтах) обчислюються відповідні значення
уГ(х)іуГ(х).
Перейдемо до представлення алгоритму, що реалізує метод плаваючого горизонту, мовою програмування.
Для зручнішого оперування значеннями ліній горизонту введемо масиви h_max[x] та h_min[x], елементами яких будуть відповідно поточні максимальне та мінімальне значення для кожного х.
За основу тієї частини алгоритму, яка визначає екранні ко ординати видимої точки поверхні, візьмемо розглянутий вище алгоритм Брезенхема для відображення відрізка прямої. Однак при цьому врахуємо, що координати кінців цих відрізків
(Xj; |
г/х) та (х2; у2) по осі абсцис відрізняються на 1 (х2 |
- х1 = 1), а |
|
відповідні значення |
ух та у2 обчислюються за формулами: |
||
у1 = |
f(zt, хг), у2 = f(zt, |
х2). |
|
Окрім цього, слід звернути увагу на те, що суттєвим фактором для визначення видимих точок поверхні є значення кутового
коефіцієнта k = — -. Якщо воно менше від 1, то із збільшенням
2 _ * 1
314
значення х збільшуватиметься і |
|
|
|
|
|
|
|
|
|
|
значення у, а це означає, що |
|
~щ~щ |
|
|
|
|
•__• |
|||
максимальне значення лінії го |
• |
• • |
_• |
|
|
• |
||||
ризонту для кожного х буде ви |
|
|
|
|
|
|
|
|
||
• |
• |
• |
|
• • |
||||||
значене коректно (мал. 177, а). |
|
|
|
|
|
|
|
|
|
|
А от у разі вертикального розта- |
,. |
|
|
0, |
|
|
|
|
||
шування точок (мал. 177, б), се- |
|
|
|
Мал. 177 |
|
|
|
|
|
|
ред яких усі є видимими, може |
|
|
|
|
|
|
|
|
|
|
статися так, що першою буде розглянута точка з більшим зна ченням у і саме воно стане поточним значенням верхньої лінії горизонту для точки Ї. А це означатиме для алгоритму, що решта точок цієї вертикалі є невидимими, що суперечить ре альності.
Тому у реалізації алгоритму присутні дві окремі процедури, які передбачають розгляд двох варіантів значень кутового ко ефіцієнта k.
Можна запропонувати такий варіант основної частини про грами:
for Z := z1 to z2 do |
{Цикл побудови перерізів заданої поверхні по осі Oz.) |
||
for X := x m i n to x m a x - 1 do |
{Перегляд усіх значень x з кроком 1.} |
||
begin |
|
|
|
х1 := х; х2 := х + 1; |
{Початкові значення кінців відрізка у поточному перерізі.} |
||
у1 : = f ( z , x 1 ) ; y 2 : = f ( z , x 2 ) ; |
|
|
|
n := abs(x2 - х1); m := abs(y2 - у1); |
{Ініціалізація початкових значень} |
||
sx := sign(x2 - х1); sy := sign(y2 - у1); |
{для побудови відрізка} |
||
х_р := х 1 ; у_р := у 1 ; s := 0; є := 0; |
{за алгоритмом Брезенхема.} |
||
{Визначення процедури залежно від значення кутового коефіцієнта.} |
|||
if m < n then k_less_1 else k_more_1 |
|
|
|
end; |
|
|
|
Тепер розглянемо процедуру, що реалізує випадок к < |
1: |
||
procedure k_less_1; |
|
|
|
begin |
|
|
|
n2 := 2 * n; m2 := 2 * m; |
{Ініціалізація початкових значень.} |
||
while S < n - 1 do |
{Цикл для побудови всіх точок поточної лінії.} |
||
begin |
{Лічильник точок, крок по осі Ох, обчислення відхилення.} |
||
s := s + 1; х := х + sx; є := є + т 2 ; |
|
|
|
{Якщо відхилення більше ніж 1, то зміщення по осі Оу і перерахунок} |
|||
if є > n then begin у := у + sy; є := є - n2 end; |
{відхилення.} |
||
if у < h_min[x] |
{Якщо значення ординати поточної точки менше} |
||
|
{від лінії нижнього горизонту, то виведення точки} |
||
|
{і перевизначення значення лінії нижнього горизонту,} |
||
then begin PutPixel(x, у, d ) ; h_min[x] := у end
{якщо значення ординати поточної точки більше від лінії} else if у > h_max[x] {верхнього горизонту, ТО}
{виведення точки і перевизначення значення лінії верхнього горизонту.}
then begin PutPixel(x, у, с2); h max[x] := у end;
end;
end;
315
Для вертикального розташування точок процедура може бу ти такою:
procedure k_more_1; begin
С := m; m := n; n := c; |
|
{Ініціалізація початкових значень.} |
|
n2 := 2 * n; m2 := 2 * m; |
|
|
|
u := x; v := y; xO := x; yO := y; |
|
|
|
while s < n - 1 do |
{Цикл для побудови всіх точок поточної лінії.} |
||
begin |
|
{Лічильник точок, крок по осі Оу,} |
|
s : = s + 1;v:=v + sy; є := є + m2; |
{обчислення відхилення.} |
||
{Якщо відхилення більше ніж 1, то зміщення по осі Оу і перерахунок} |
|||
if є > n then begin u := u + sx; є := є - n2 end; |
{відхилення.} |
||
|
{Якщо значення ординати поточної точки менше лінії} |
||
if у < h_min[x] |
|
{нижнього горизонту, то} |
|
then begin |
|
|
|
PutPixel(x, у, с1); |
|
{виведення точки.} |
|
if U <> х |
{Перевизначення значення лінії нижнього горизонту.} |
||
then |
|
|
|
begin |
|
|
|
if sy > 0 then h_min[xO] := yO else h_min[x] := y; |
|||
xO := u; yO := v |
|
|
|
end |
|
|
|
end |
|
|
|
|
{Якщо значення ординати поточної точки більше лінії} |
||
else if у > h_max[x] |
{верхнього горизонту, то} |
||
then |
|
|
|
begin |
|
|
|
PutPixel(x, у, с1); |
|
{виведення точки.} |
|
if U О х {Перевизначення значення лінії верхнього горизонту.} then
begin
if sy > 0 then h_max[xO] := yO else h_max[x] := y; xO:=u;yO:=v
end; end
else if u <> x then begin xO u; yO := vend x := u; у := v
end;
end;
Варто звернути увагу на деякі недоліки описаного методу плаваючого горизонту.
1.Може статися так, що при деякому значенні х значення у(х) невідоме. У такому разі можна запропонувати взяти у якості цього значення середнє між двома сусідніми значеннями.
2.Якщо функція задана малою кількістю точок і має досить гострі піки, то наведений алгоритм може дати некоректні ре зультати.
316