Об ошибках статьи "3D графика"
в ZX-Power#3
(С) 1999, Пелепейченко Александр
__________________________________________
От редакции:
В прошлом номере журнала была опублико-
вана статья о работе с трехмерными объек-
тами, подготовленная нашими друзьями из
Avalon - (C) Ruff&Viator. И вот через не-
которое время один из читателей сообщил
нам о своих замечаниях к вышеупомянутой
статье. Публикуем их здесь, рассчитывая на
комментарии со стороны Ruff'а...
* * *
Загрузил я как-то ZX-Power#3 и стал его
читать. Собственно, ничего удивительного в
этом нет. Так вот, читаю я его, читаю и
вдруг натыкаюсь на эту статью. Поскольку я
являюсь поклонником 3D графики и разных
там эффектов, решаю разобраться в этом
способе. К тому же многообещающее предис-
ловие разжигает интерес к нижеуказанному
способу.
Впоследствии я, конечно, понял всю ру-
лезность этого способа, но надо сказать,
что поначалу я не только не мог врубиться
в прилагаемый код, но и ставил под большое
сомнение теоретическую часть (в нее я тоже
не сразу врубился). Сразу скажу, что спо-
соб очень похож на предложенный в SPECTRUM
EXPERT#2 "метод средней точки".
Внимательно прочитав с десяток раз эту
статью, и так и не поняв многого, я решил
набить это и проверить его работоспособ-
ность. И тут началось самое интересное.
Во-первых, в конце процедуры К64 я увидел
непонятно откуда взявшийся кусок кода (а
точнее даже 2 куска: первый - метка LOOP4
и до конца, второй - то что над этой мет-
кой до команды RET). Изучив эти куски я
понял, что это подсчет тех же осей, но с
учетом ненулевого значения 3D-центра. Во-
обще, он (этот кусок) ТАМ не очень нужен
(разве что для наглядности). Но... (читай
вторую часть статьи).
Немного присмотревшись к тексту, я ре-
шил, что, вероятнее всего, какая-то часть
текста была утеряна. На эту мысль меня на-
толкнуло то, что упоминаются рисунки с но-
мером 2 и 3, а их там в помине нету.
Прим. Ред.: Напечатали все, что было...
Оказалось, что координаты точек попута-
ны бог знает каким образом, и их печать
идет вообще неправильно.
Тогда мне стало ясно - ошибки в статье.
ALASM был загружен, делать было нечего,
и я принялся за отладку программы. Теоре-
тическую часть я принял на веру, не прове-
ряя ее, а вот код, как оказалось, немного
не соответствовал теории.
Ошибки щедро одарили подпрограмму AX.
Непонятно зачем в самом начале этой проце-
дуры было нечто вроде:
LD A,E
SUB 32
LD E,A
... ; и так далее с регистрами
; L, C , L'
Прим. Ред.: Мы их туда не добавляли. :))
Далее, причиной отфонарной печати точек
и непонятно какой последовательности хра-
нения информации про эти точки было попу-
танное местами засылание на стек коорди-
нат. Я, конечно, понимаю, что несколько
ошибок могут компенсировать друг друга и
не считаться ошибками (что могло иметь
место в исходниках автора), но в приведен-
ном листинге такого не происходило. Веро-
ятно, эти ошибки возникли потому, что код
в статью писался по памяти. Весь код, ко-
торый вы видите здесь, вытянут из уже ра-
ботающих исходников, поэтому ошибки подоб-
ного рода маловероятны. Я приведу сдесь
ВСЮ процедуру AX, так как 80% ее части в
POWER#3 являются неверной. На входе в AX в
регистрах задаются координаты ключевых то-
чек, уже спроектированных в экран. Причем
в старшей половине регистра сидит X-коор-
дината.
TABAX EQU 250 ;вход:
;DE = центр 3D
AX LD HX,D ;BC = конец оси z
LD LX,E ;HL = конец оси x
EXX ;HL'= конец оси y
LD A,L ; в POWER#3
PUSH AF ; именно эти PUSH'ы
EXX ; оказались
LD A,C ; немного
PUSH AF ; попутаны
LD A,L ;
PUSH AF ;
LD A,H ;
PUSH AF ;
EXX ;
LD A,H ;
PUSH AF ;
EXX ;
LD A,TABAX
LD (VAR),A
LD A,B ; в POWER#3 стоит 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
VAR DEFB 0
Пояснение (*) см. во второй части.
Не миновали опечатки и процедуру К64. В
том месте, где стоят такие команды (ищите
их после метки LOOP3) :
LOOP3
......
DUP 64
SBC HL,DE
LD A,H
EXX
......
Необходима замена на:
DUP 64
LD A,H
SBC HL,DE
EXX
......
То есть команда LD A,H должна стоять
ПЕРЕД SBC HL,DE, иначе таблица оказывается
сдвинутой на 1 байт вниз.
Больше ошибок и неточностей я не нашел.
И несмотря на все вышесказанное, я хочу
заметить, что, вероятно, если бы не эти
ошибки, я бы так и не разобрался бы с
принципом работы этого метода. Конечно,
главное - идея, а ошибаться склонен каж-
дый.
Ну, с ошибками покончено, теперь мои
изыскания.
часть 2
Метод очень производительный, хотя мож-
но сделать его еще быстрее, что несколько
раздует К64. Этого можно добиться, если к
одной из x-координат при расчете осей при-
бавить HX, и то же самое проделать с одной
из y-координат, после чего убрать эти при-
бавления из процедуры рисования точек. Вы-
игрыш будет точно 12 тактов на точке. В
этом случае можно приспособить тот кусок
кода в К64, о котором я говорил выше.(Мо-
жет он и был приспособлен для этого, но
коментарий к нему затерялся в редакции).
Прим. Ред.: Ну, это уже "наезд"! :)) У
нас, в редакции, "затеряться" может только
вся статья целиком, но тогда мы ее не на-
печатаем... ;))
Для этого нужно именовать его какой-ли-
бо меткой, например К64_1.
Теперь необходимо CALL K64, помеченные
(*) (смотри выше), заменить на CALL K64_1
и убрать команды ADD A,HX и ADD A,LX из
процедуры вывода точек.
Была идея сделать 4D (5D,6D...) ренде-
ринг, однако не было времени, да и без хо-
рошей вращалки/леталки делать это нет
смысла.
А вообще я подумал: "Зачем пользоваться
альтернативным регистром hl' в К64, если
есть еще неиспользующийся BC??? Тогда (за
счет аннулирования EXX'ов) на просчете од-
ной оси по обеим координатам удастся сэко-
номить еще 8*64*2=1024 тактов + около 256
байт, где 8-сумма EXX'ов в тактах, 64 - у
нас там DUP 64, 2 - у одной оси две коор-
динаты (x и y). А таких осей 3 штуки..."
Подумал я так и накодил более быструю про-
цедуру, которая экономит около 3072 тактов
на каждом просчете осей.
K64
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
LD A,(VAR)
LD B,A
INC A
LD (VAR),A
LD C,0
DUP 64
LD A,H
ADD HL,DE
LD (BC),A
INC C
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
LD A,(VAR)
LD B,A
INC A
LD (VAR),A
LD C,0
DUP 64
LD A,H
SBC HL,DE
LD (BC),A
INC C
EDUP
RET
K64_1
CP B
JR 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
И еще одно. Если мы уж и стираем с эк-
рана избражение для вывода нового, то де-
лать это желательно как можно быстрее, что
я и предлагаю сделать заменив
POP HL:LD (HL),0:POP HL.....
таким вариантом:
XOR A
POP HL:LD (HL),A:POP HL:LD (HL),A...
А вообще я так и не смог нарисовать
нормальный 3D обьект, состоящий полностью
из точек и решил (но еще не сделал) подме-
шать draw'ы. Естественно, предложенная
стиралка оказалась неприемлимой.
Правда, на точках проще отсекать неви-
димые и заходящие за экран части, но нари-
совать обьект....(у меня после попытки на-
рисовать появилась идея сделать мини 3D
STUDIO).
Проблему перспективы проще всего решить
перспективно спроектиравав 3D систему ко-
ординат.
На этом все.
__________________________________________