RUSH
#01
29 мая 1999 |
|
Spectrum программинг - Быстрые 3D-расчеты: продвинутый алгоритм.
Быстрая 3D-графика для SPECCY, реаль- но ли это ? Возможно, нижеследующая статья раскроет для Вас ранее неизвестные возмож- ности SPECCY и окажется полезной при ра- боте с трехмерными объектами. Статья рас- читана на более-менее подготовленных чи- тателей, но может оказаться полезной даже начинающим пользователям... Не смотря на некоторую хаотичность и недосказнность подачи информации, здесь описывается в определенной степени выдаю- щийся способ работы с 3D обьектами в ре- альном времени. Процедура примечательна тем, что ра- ботает очень быстро. Основная суть данного метода состоит в том, что вращается не каждая точка в отдельности, а сразу целая плоскость. Этот метод ножет пригодиться не только для создания крутых векторных эффектов, но и для написания новых игрушек. А как rulez'но будут смотреться старые векторные игры, переделанные с учетом последних кодерских достижений !... Представте, например, ELITE, работающую в 2-3 раза быстрее или плавнее ! Перейдем, собственно, к материалу, предоставленному RUFF'ом, еще до того как он почувствовал вкус написания игрушек на Amiga и стал успешно "кодить" там... Хорошим примером иллюстрирующим описанный ниже алгоритм является эффект из демо "Hallutinations in Opera" - вращающийся 3-D человек, состоящий из одних векторов. Ruff> Когда-то я прочитал статью в "ECHO 1" про вывод 3-D объектов. Там описан тради- ционный метод, который все (кто знаeт) используют. Это, конечно, очень интересно поворачивать точки вокруг осей X,Y и Z по специальным формулам. Для поворота вокруг оси X: Y'=COS(N)*Y-SIN(N)*Z Z'=SIN(N)*Y+COS(N)*Z вокруг оси Y: X'=SIN(N)*Z+COS(N)*X Z'=COS(N)*Z-SIN(N)*X вокруг оси Z: X'=COS(N)*X-SIN(N)*Y Y'=SIN(N)*X+COS(N)*T ( N - Угол поворота) У этого способа есть недостатки. А если точнее, один очень большой недостаток - занимает много времени! На операции умножения (какими б они быстрыми не были) и вычисления COS и SIN ( даже по таблице) уходит немало времени. Если учесть проблему со знаками и то, что обычно объекты вращают сразу вокруг трех осей ( некоторые вообще используют калькулятор BASIC'а ), то тут ничего не остается, кроме как сперва рассчитывать координаты, а потом выводить graphix. Некоторые даже подгружают отдельно рассчитаные на BASIC'е координаты. Это же lamer'ство!(Кроме отдельных случаев). Правда, иногда встречаються программки с REAL-TIME 3D CALCULATING'ом. Но как они тормозят!!! ...Это было вступление. Теперь ближе к делу. Я придумал новый способ вывода 3D объектов. Вот его достоинства: - Он намного (!!!) быстрее вышеописаного способа. чтобы вычислить координаты од- ной точки, нужно приблизительно 200 так- тов (при желании можно сделать еще быстрее). - 3D объект можно не только поворачивать, но и деформировать (растягивать,сжимать и тд.) Я не могу полностью привести здесь листинг этого эффекта,поэтому привожу все по кускам, которые вы сами соберете и дополните кому что надо. Вот первый фрагмент - сама процедура печати 3D объекта: PRINT: LD (SAV+1),SP ; сохраняю SP LD SP,... ; ... - Это начальный адрес координат ; точек 3D объекта. На одну точку 4 байта ; ( 3 байта - координаты X,Y,Z; 1 байт- ; старший байт таблици осей ( про нее ; чуть попозже) он,кстати,дальше ; обозначается меткой TABAX). EXX LD HL,BUFER ; Специальный буфер для ; очистки экрана ; (смотри ниже) LD B,175 ; кол-во точек-векторов LP1 ;Дальше идет процедура печати одной точки: EXX POP BC ; в BC - Y,X POP HL ; в HL - старш. байт таблицы ; осей, Z LD A,(HL) LD E,L LD L,B INC H ADD A,(HL) INC H LD L,C ADD A,(HL) ADD A,HX LD C,A INC H LD A,(HL) LD L,E INC H ADD A,(HL) LD L,B INC H ADD A,(HL) ADD A,LX LD L,A ; Теперь координаты точек (X и Y в экране) ; вычислены и помешрны в регистры C и L. ; Дальше идет процедура печати точки по ; координатам в этих регистрах (69 такт.). ; Для нее нужна специальная таблица, так- ; Кто, кто такой процедуры не знает, ; может использовать свою. PLOT: LD H,TABLE_P LD D,(HL) INC H LD A,(HL) INC H LD L,C ADD A,(HL) INC H LD E,A LD A,(DE) OR (HL) LD (DE),A ; Ну, вот. Точку напечатали, теперь можно ; (если хотите) в специальный буфер ; поместить адрес в экране этой точки ; (для того, чтоб потом быстро очистить ; экран методом POP HL: LD (HL),0: ; POP HL: LD (HL),0: POP HL...). LD A,D EXX DEC HL ; Адрес буфера растет ; вверх-ногами (для удобства). LD (HL),A EXX LD A,E EXX DEC HL LD (HL),A DJNZ LP1 ; Следующая точка. SAV LD SP,0 RET Как-то непривычно смотрятся команды LD SP,0 : RET , зато экономит память. Вы, надеюсь, догадались, что эта про- цедура сама-по-себе ничего не даст. ЕЩЕ нужно написать процедуру очистки экрана и процедуру создания таблиц осей. Здесь я их не привожу по причине большего обьема (длины), который они занимают. Очистку эк- рана я, конечно, мог бы написать, только хасчет этого у каждого свои принципы ( кто б написал installer, кто поместил бы все в DUP'ы, и тд. и тп.). Короче,сами напишите. А насчет создания таблиц с координатами осей, то лучше я сперва расскажу принцип. Y ===== .... ________________ === == . . /!^ ! == . . / !* ! === . . / !>48 ! === . . / !* ! === . . ! !* .А ! == . . ! !* ! === == . . ! !* ! ===== .... ! !* ! ! !* ! рисунок 1 ! !* ! ! !* 32 ! ! _______^________! ! 30/****************>/ X ! ^/* / ! /* / !/<________________/ Z Посмотрите на РИСУНОК 1. Как вы дога- дались - это куб. Представте, что внутри него находится З-D обьект. Каждая точка этого обьекта имеет три координаты по осям Y, X и Z. Здесь оси не бесконечные. Напри- мер, они могут состоять из 64 точек (коор- динат). То-есть, точку можно задать тремя числами от 0 ДО 63. А теперь самое интересное... Возьмем, например, точку а с координатами Y=48,X=32,Z=30. Kак узнать ее координаты в экране, если учесть, что ось Z повернута так, как на рисунке ? На каждой оси помечена точка с соот- ветствующтй координатой. Глаеное - нужно узнать координаты Y и X этих точек и цен- тра (точка пересечения осей) на экране. Допустим, мы их знаем: Kоординаты от левого верхнего угла Y,X: На оси Y-70,46 На оси X-172,140 На оси Z-180,40 Центр -172,46 Чтобы вычислить координаты в экране точки "А" применяем две простые формулы: Oбозначим координаты в экране (то-же, что выше, только вместо цифр буквы): На оси Y-Yy,Xy На оси X-Yx,Xx НА оси Z-Yz,Xz Центр -Yc,Xc Итак, формулы: Y= (Yy-Yc)+(Yx-Yc)+(Yz-Yc)+Yc X= (Xy-Xc)+(Xx-Xc)+(Xz-Xc)+Xc Подставляем значения: Y =(70-172)+(172-172)+(180-172)+172= =78 X =(46-46)+(140-46)+(40-46)+46=134 Kоординаты точки "А" в экране 78,134 Вышеприведенная программка печати 3D обь- екта именно это и делала - подсчитывала сумму (правда, немного по другому), печа- тала точку и запоминала адрес в экране. А что же должна делать программа рас- считывания координат осей? - Конечно рас- считывать координаты осей... Но давайте сперва разберемся с формулами... Вы, наверное, уже давно пораскрывали скобки, посокращали лишние координаты цен- тра и уверены, что я это не заметил ? Так, вообще, можно сделать, только в этом мало смысла. Вот в чем дело: тут от каждой коорди- наты точки оси отнимается координата цен- тра. Вернемся к координатам точек осей. Как вы догадались, придется рассчитывать координаты всех 64 точек осей. А эти коор- динаты мы будем рассчитывать не так, как они есть в экране, а с центром с координа- тами в экране 0,0. А затем останется лишь прибавить координаты центра. Сама процедура рассчета координат осей занимает не много времени. У меня, напри- мер, (если процедуру поставить в начале прерывания) кадровая развертка не успеет дойти даже до первых строк экрана. Но для координат осей нужен буфер. Посчитаем его длину: Одна ось-64 точки, то-есть 128 координат. Всего осей 3, значит, всего координат 128*3=384 координаты. Одна координата-один байт. Но ради ускорения вывода 3D спрайта, лучше координаты одной оси хранить в 512 байтах (координаты Y-256 байт, координаты X-256 байт. Из 256-ти байт используются только 64). Всего буфер выйдет 512*3=1536 байт. Тоже не очень много. Ну, а теперь сама программа. Принцип работы будет обьясняться по ходу дела. Как уже писалось выше, мы будем рассчитывать координаты осей так, если бы центр имел координаты 0;0. А потом уже, при выводе, прибавим координаты центра. Это съэкономит время. Кстати, координаты центра в моей програмке будут храниться в регистровой паре IX, так-что, ее содержание не меняй- те, или сохраняйте, а затем востанавливай- те (моя программа рассчитывания координат осей связана с программой печати 3D спрай- та парой IX и содержимым буфера координат осей). AX ; Процедура рассчитывания координат ; осей. Координаты (в экране) ; крайних точек осей ; задаются в регистрах HL',BC,HL. ; Координаты центра в DE. ; Кстати, для тех, кто не хочет, ; чтоб 3D обьект сжимался и растяги- ; вался, то может для поворота этих ; 4-х точек использовать формулы ; 3-D вращения (look up). TABAX EQU 250 (64000=250*256) ; Старший байт буфера в который ; рассчитываются координаты осей. ; Адрес буфера кратен 256 (!!!) LD A,E SUB 32 LD E,A LD A,L SUB 32 LD L,A LD A,C SUB 32 LD C,A EXX LD A,L SUB 32 LD L,A EXX LD HX,D ; Имеется в виду ст.байт IX, LD LX,E ; младший байт IX. ; (Недокументированные команды ; процессора Z-80. 6 тактов) LD A,L PUSH AF LD A,C PUSH AF EXX LD A,L PUSH AF EXX LD A,H PUSH AF LD A,B PUSH AF EXX LD A,TABAX LD (VAR),A LD A,H LD B,HX CALL K64 POP AF LD B,HX CALL K64 POP AF LD B,HX CALL K64 POP AF LD B,LX CALL K64 POP AF LD B,LX CALL K64 POP AF LD B,LX CALL K64 RET K64 ; К64-самая главная процедура. Вызывается ; программой целых 6 раз. Просчитывает ; промежуточные 64 координаты. Координата- ; цель в регистре А, а источник в В. ; Источник у нас центр, значит в B всегда ; координата центра (Y или X). А вообще ; здеаь она нужна только для получения ; разници (А-В или В-А) и для определения ; направления (положительное или отрица- ; тельное). Так-как координаты центра у ; нас 0;0 - адрес таблици в 64 байта (куда ; поместить все числа) кратный 256. Его ; старший байт задается по адресу VAR. ; Этот байт, кстати, програмка в конце са- ; ма увеличивает на 1. ; Tак я рассчитывал сперва координаты Y, ; вызывая эту процедуру, а потом X-ы, ; вызывая ее еще раз. осей у нас три, ; поэтому процедура К64 вызывается 6 раз. CP B JP C,LOOP1 SUB B LD L,A LD H,0 ADD HL,HL ADD HL,HL EX DE,HL LD HL,0 LOOP2 EXX LD A,(VAR) LD H,A INC A LD (VAR),A LD L,0 EXX DUP 64 ; или какой-нибудь цикл, типа ; LD B,64:...:DJNZ ... LD A,H ADD HL,DE EXX LD (HL),A INC L EXX EDUP RET LOOP1 LD C,A LD A,B SUB C LD L,A LD H,0 ADD HL,HL ADD HL,HL EX DE,HL LD HL,0 LOOP3 EXX LD A,(VAR) LD H,A INC A LD (VAR),A LD L,0 EXX DUP 64 ; или какой-нибудь цикл, типа ; LD B,64:...:DJNZ ... SBC HL,DE LD A,H EXX LD (HL),A INC L EXX EDUP RET CP B JP C,LOOP4 SUB B LD L,A LD H,0 ADD HL,HL ADD HL,HL EX DE,HL LD H,B LD L,0 JP LOOP2 LOOP4 LD C,A LD A,B SUB C LD L,A LD H,0 ADD HL,HL ADD HL,HL EX DE,HL ADD A,C LD H,A LD L,0 JP LOOP3 VAR NOP NOP Ну, вот и все... Для тех, кто не вник во все нюансы, или не хочет дополнительно менять, совершен- ствовать этот метод, а хочет написать все по своему, некоторые рекомендации: 1. Не забудте о формате хранения коорди- нат 3D обьекта. Не забудте про буферы (координат осей, delete буфер). 2. Координаты крайних точек осей (Kz, Kx,Ky и центр) считайте по формулам вращения или по синусоидной табличке. 3. Алгоритм программы вывыда должен быть где-то таким: EI HALT DI CALL PRINT Заносим в HL',BC,HL,DE следующие значе- ния из син.таблици (нужно еще учесть, чтоб они не были слишком большими,иначе спрайт может вылезти за экран и залезть с другой стороны. CALL AX Очистка экрана с использованием DELETE буфер'а. Желательно приспособить все для работы с двумя экранами. JP BEGIN
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября