О, спасибо за статью! Я на досуге вайбкодом балуюсь (да-да, позор!), астра мне делает игру моей мечты (без корованов). Чисто процедурная бродилка-гляделка по лиминальным помещениям на JS (наверное) прямо в html-странице, но полностью автономная. Оч хочу похвастаться, только не знаю как выложить.
Задумывались ли вы когда-нибудь о том, как разработчики 3D-игр умудрялись выжимать красивую графику из слабого железа в 90-х годах? Вспомните NFS High Stakes, Quake 3, Unreal или Jurassic Park: Tresspaser — все они, несмотря на простоту технологий, выглядят сногсшибательно - в них были и зеркала, и отражения на металлических поверхностях, и продвинутый статический свет с рейтрейсингом, и даже четкие тени...
...но немногие знают, что на видеокартах уровня 3dfx Voodoo 2 это достигалось путём использования хитрых техник, хаков и особенностей видеокарт тех лет. В этой статьи мы с вами из первых уст рассмотрим такие техники на практике — ведь одним из моих хобби является написание 3D-демок и игр под ретро-железо.
О железе
Конечно начать рассказ стоит с железа, на котором работали 3D-игры в те годы. Среднестатистический компьютер в середине девяностых состоял из:
Процессора — Intel 386/486 на частоте 16-50МГц, и его аналогов от AMD/Cyrix в сборках попроще, а Pentium 66 и 133 можно было встретить в моделях побогаче.
Оперативной памяти — 4-8 мегабайт в бюджетных сборках и 16-32 в более богатых
Видеокарты — простой VGA-адаптер без ускорения 2D, или же 2D-ускоритель типа S3 Trio с поддержкой аппаратного блиттинга. 3D ускорять такие видеокарты не умели.
HDD — от ~100 до 500МБ на бюджетных сборках, и до ~1ГБ на некоторых дорогих.
О 3D-ускорении в домашних ПК тогда можно было только мечтать, однако многие разработчики всё равно делали полноценные, пусть и несложные по графике 3D-игры и демки — просто в них отрисовкой мира занимался процессор. Такой подход назывался Software rendering и стал возможен благодаря развитию FPU в x86-процессорах — диковинке, о которой большинству чипов на ARM/MIPS оставалось только мечтать (FPU не было даже в PlayStation 1).
У софтрендеров были как плюсы, так и минусы. Главным плюсом можно отметить то, что в отличии от ранних видеокарт, у них не было фиксированного конвейера и разработчик мог реализовать отрисовку именно так, как он хочет — иными словами, он мог встроить «шейдеры» прямо в функцию растеризации треугольника. Другим важным плюсом я считаю то, что рендер имел «бесплатный» прямой доступ к буферу кадра, что позволяло реализовывать разные пост-эффекты по типу LUT, блюра или капель дождя на стекле.
Пример реализации дождя в Дальнобойщиках. Хотя именно в Д1 могли реализовать не пост-эффектом, а полупрозрачной текстурой-маской, которая формируется процессором, или вообще через стенсильный буфер.
Но были и минусы, и самый важный — огромная нагрузка на процессор, которая росла обратно пропорционально разрешению игры. В 320x200 Pentium 66 ещё мог кое-как справиться с простой сценой без особого овердрава (как в Quake 1), но на 640x480 и 800x600 FPS падал в однозначные числа. Второй минус происходит из первого — отсутствие фильтрации и перспективной коррекции текстур во многих играх, из-за чего текстуры полов и стен под определенным углом начинают искажаться.
Что тако Overdraw?
Overdraw — процент отрисовки поверхностей, которые перекрывают уже отрисованный ранее фрагмент.
Простой пример — мы сидим в доме и смотрим в стену. Если игра нарисует сначала ландшафт за домом, затем забор, затем качели за забором, и только потом стену перед нашим носом — это уже Overdraw. Некоторые игры умудряются рисовать за кадр практически весь уровень и это сильно бьёт по филлрейту.
В Quake-подобных такого не было, поскольку там работал хитрый PVS-куллинг, который отсекал даже те стенки, которые сейчас находятся прямо за стенкой на которую мы смотрим.
Гигагерцовый Vortex86 уже не вывозил Quake 1 в 1280x1024 даже под DOS!
Первой 3D-видеокартой на ПК была STG2000 (также известная как Diamond Edge 3D), выпущенная в 1995 году на чипе NV1 — который по совместительству был первым видеочипом Nvidia. На практике, NV1 был целым мультимедийным комбайном: в одном чипе скрывался 3D-ускоритель, 2D-ускоритель, аудио и MIDI-контроллер, и даже контроллер геймпадов Sega Saturn. И всё бы хорошо, но видеочип от Nvidia оперировал не привычными треугольниками, а квадами с хитрым способом представления текстурных координат — портирование 3D-игр на «треугольных» софтрендерах было слишком сложным, требовало переделывание всей геометрии (а значит и переобучения 3D-моделеров), из-за чего большинство разработчиков решило не заморачиваться и NV1 провалился, чуть не обанкротив молодую Nvidia.
Фото с сайта Vintage3D
Всего через год, в 1996 году, появилась первая 3dfx Voodoo, которая перевернула мир 3D-игр на ПК с ног на голову. Это был первый полноценный 3D-ускоритель, который мог реально разгрузить процессор и рендерить игры в куда большем разрешении с приличным FPS — можно было замахнуться не только на 640x480, но и 800x600 при 16-битном цвете! Главным нюансом было то, что 3dfx Voodoo был именно ускорителем — то есть чисто технически, он умел только растеризовывать треугольники, интерполировать цвета и наносить на них текстуры, и накладывать туман: у него не было ни вершинного конвейера, ни клиппинга, ни освещения — всё это делал процессор. Но под Voodoo было легко программировать, у него был понятный API Glide, а ещё он стоил относительно приемлемых денег — что и сделало 3dfx Voodoo стандартом на рынке конца 90-х.
3dfx Voodoo 1 с одним TMU. Фото с TechPowerUp
Однако во времена первой 3dfx Voodoo, игры были сильно ограничены в плане графики из-за конвейера. Дело в том, что Voodoo 1, как и ViRGE с ATi 3D Rage, умели наносить лишь одну текстуру за проход отрисовки — из-за чего для рендеринга уровней с освещением приходилось рисовать сцену два раза — первый проход с основной текстурой, второй с лайтмапой в режиме альфа-блендинга с смешиванием, а если были ещё и detail-текстуры — то добавлялся и третий проход! Учтите что GL/D3D были ещё глупыми, и на каждый такой проход приходилось снова и снова трансформировать и клипать геометрию что также било по процессору.
Решением стало появление текстурных комбайнеров в ~1997-1998 году, которые были прямым предком пиксельных шейдеров. В зависимости от числа текстурных юнитов, видеокарта могла смешивать сразу несколько текстур за один проход отрисовки, и делать не только умножение — но и сэмплинг по маске (полезно было для реализации ландшафтов, ранняя вариация Splatmapping'а), умножение итогового цвета в два раза (для реализации эффекта псевдоблума), DOT3-бампмаппинг, Environment mapped bump-mapping (помните демки из конца 90-х с красивой отражающейся водичкой? Вот это и есть EMBM) и ещё много разных интересных эффектов.
Помните красивую шейдерную водичку из Morrowind? Она была сделана по сэмплу из D3D8. Ничего сложного в этой водичке нет: отражение наносилось с помощью проекционной матрицы для текстурных координат, а бамп маппинг работал за счет комбайнеров.
В 1999 году появился первый GPU — GeForce 256, который имел поддержку T&L и переносил вершинный конвейер и хранение геометрии на видеокарту, а в 2001'ом — GeForce 3 с поддержкой полноценных вершинных и пиксельных шейдеров. С того момента всё и изменилось: игры стали ещё более крутыми, графонистыми, появились новые техники освещения помимо затенения по Фонгу, и так мы с вами дошли до PBR с GI в реалтайме в любом мейнстримном движке...
Освещение
...но давайте же вспомним, как разработчики реализовывали свет на ограниченном железе в 90-х годах. Причём в некоторых играх освещение было достаточно сложным и реалистичным — взять как пример Quake и Half-Life, которые вероятно одними из первых адаптировали технику Radiosity-лайтмап в играх.
Сцена в Half-Life 1 без освещения
Radiosity — техника просчета глобального освещения с переотражениями и тенями за счет использования программного рейтрейсинга. QRAD бьёт всё сцену на так называемые патчи, считает для них влияние других патчей (в основном видимость и дистанцию) и симулирует аппроксимацию того, как свет проходил бы и отражался через них в реальном мире. То есть это именно физическая симуляция работы света, а не её красивая аппроксимация в виде шедоумап/Blinn-Phong в более современных играх с реалтайм освещением.
Главным нюансом Radiosity было то, что его невозможно было просчитывать в реальном времени до появления RTX-карт, поэтому освещение, рассчитанное этим алгоритмом, запекалось в специальные текстуры и затем наносилось на этапе рендеринга как второй слой.
Освещение в реальном времени реализовывалось схожим с современными играми способом, однако распределение света работало несколько по другому. В основе лежали всё те же алгоритмы затенения по Фонгу и ставший классикой N dot l, однако поскольку видеокарты в те годы не умели считать освещение сами и этим занимался процессор, программа (или OpenGL/D3D) рассчитывала свет для каждой вершины модели, а не пикселя, а полученный цвет от освещения записывался прямо в вершину.
В растеризации треугольников есть такое понятие, как барицентрические координаты — это интерполированные между тремя вершинами точки, которые описывают текущую «позицию» в системе координат треугольника и используются как для нанесения текстур и расчета попиксельного света, так и для интерполяции цвета. Как раз за счет интерполяции цвета между всеми тремя вершинами мы и получаем плавное освещение на каждом треугольнике, что в сумме даёт реалистичное освещение и блики, но только если у модели достаточная детализация. Такой подход называется затенением по Гуро.
Почему освещение в реальном времени использовали так мало?
Само по себе освещение в реальном времени не было прям таким уж тяжелым в те годы, но его использовали очень мало. Почему? Да потому что в графических API было строгое ограничение на число одновременных источников света для модели — всего 8 штук. Это нормально для модели персонажа, но мало для куска уровня, на который может влиять 10 источников света от фонарей/лампочек и т.д.
Решением проблемы стало появление Forward+ и Deferred-рендеринга, где свет считается в скринспейсе только для видимых пикселей. В мобильных играх повершинное освещение активно использовалось примерно до 2015 года.
Слева затенение по Гуро, справа попиксельный Blinn-Phong. Иллюстрация отсюда.
Интересным способом реализовывали и фонарики, а также свет от ночных фонарей и других источников света, которые дают конусообразное освещение. Тут было две техники: либо использование честных Spotlight'ов (поддержка которых была как в D3D, так и в OpenGL), либо использование проективных текстур. Концепция проективных текстур очень простая: если умножить WorldSpace-позицию треугольника на комбинированную ViewProject-матрицу проектора (т.е позиции с которой светит фонарик), то мы получаем ClipSpace-координаты в пространстве проектора (верные и для треугольника) — и таким образом можем нанести на него текстуру так, будто на него текстуру проецирует проектор из реального мира.
Здесь свет от лампы — лайтмапа, а свет от фонарика — как раз проецированная текстура
Таким же способом реализовывали и так называемые проективные тени — ближайший предок шедоумап. Там суть заключалась в том, что в отдельную текстуру рендерится объект с позиции источника света, а затем на дорогу или пол проецируется текстура тени, создавая мягкие, красивые и дорогие по VRAM тени задолго до PCF-шедоумап! Такой подход использовался в Mafia 1, Half-Life 2 и Street Legal Racing: Redline.
Здесь можно увидеть четкие и относительно мягкие тени, пусть и с альясингом. Для 2003 года это отличный результат.
В Portal 2 тоже активно использовались проективные текстуры. Из Вики valvedevelopernetwork.
Ну и конечно проективные текстуры использовались для реализации простых blob-теней во многих аркадах нулевых и 2010-х годов.
Пример блоб тени. Взято из мануала Unity.
Раз уж мы с вами заговорили о тенях, то нужно обязательно вспомнить о так называемых Shadow Volumes или стенсильных тенях. На рубеже 90-х и 2000-х, вопрос теней в реальном времени в играх стоял остро. Shadowmap уже, конечно, придумали, однако видеокарты всё ещё не умели сравнивать Z-координату в шедоумапах до появления специального расширения в OpenGL и D3D9. Более того, шедоумапы без фильтрации страдали от альясинга и очень сомнительного качества, пусть даже у них было полноценное самозатенение.
Пример Shadowmap из статьи на gamedev.ru. Кстати, сделаны только на FFP!
Shadow Volumes работали по другому принципу, нежели image-based техники и предлагали весьма интересный способ решения проблемы:
Сначала программа вытягивает силуэтные грани модели по направлению от источника света. Получившаяся модель называется теневым объёмом.
Затем рисуется теневой объем только с передними видимыми гранями, а в стенсил-буфер записывается значение 1.
Далее рисуется всё тот же теневой объем, но только с задними видимыми гранями, которые перезаписывают в стенсил-буфер значение 0 в местах не связанных с тенью.
После рисования всей сцены, рисуется серый полупрозрачный прямоугольник на весь экран с включенной проверкой по стенсилу. Если в стенсиле значение 0 — значит тени в этом пикселе нет, если 1 — значит есть, и таким образом мы получаем корректные, четкие и красивые тени без проблем, свойственных ShadowMap'ам.
Стенсильный буфер работает по тому же принципу, что и трафарет при рисовании на листе бумаги, только в 3D-графике. Он имеет такое же разрешение, как и сама игра, и каждый пиксель в нем является флагом «можно ли рисовать в этом месте или нет» для основного экрана (рендертаргета) игры.
Силуэт о которм мы говорили. Скриншот из статьи Семёна Козлова на gamedev.ru.
Стенсильные тени использовались во многих играх вплоть до ~2005 года. Самые известные — GTA San Andreas (там тени падали от фонарных столбов, пешеходов и машин) и F.E.A.R, однако поскольку просчет объёмов приходилось делать на процессоре для каждого источника света отдельно — техника устарела к появлению D3D10, и даже геометрические шейдеры, где их можно было считать почти бесплатно, волюмы не спасли.
Еще одна интересная техника тех лет — попытка симуляции атмосферного эффекта Godrays, или так называемые лучи Иакова: когда свет проходит сквозь узкие щели в пыльной и темной комнате, он выглядит как объемные лучи и многие разработчики делали красивый фейк этого эффекта за счет простейших вытянутых коробок с градиентной полупрозрачной текстурой. Эффектом пользуются еще с 90-х годов по сей день:
NFS High Stakes PS1
Прошу прощения за мыло :(
Отражения
Не менее интересно были реализованы и отражения. Сейчас в сети часто можно встретить жалобы игроков на то, что в современных играх отражения слишком примитивные, особенно это касается гонок, где в зеркалах автомобиля можно увидеть только статическую Reflection prob'у, а в зеркалах зданий разве что замыленную копию мира, отрисованную в рендертаргет низкого разрешения. В пример игроки приводят игры из нулевых и даже девяностых, где отражения были честными!
В GTA в зеркало можно было стрелять из снайперки и даже самого себя пристрелить. Многие думают что за зеркалом прячется клон игрока в виде отдельного игрового объекта, однако на практике снайперка — единственное оружие в игре, где пуля реально является объектом, а не рейкастом и она просто попадала по хитбоксу игрока сразу в тот момент, как была выпущена.
Секрет таких отражений в использовании всё того же стенсил-буфера. Игра сначала рисует объект зеркала с записью маски «зеркальных» пикселей в стенсил, затем рисует мир еще раз задом-наперед относительно зеркала и с помощью стенсилбуфера обрезает все пиксели, что попадают за пределы зеркала. Да, да, эта техника буквально строится на концепции «зазеркалья» и использовалась даже в Duke Nukem 3D 1995 года!
Скрин из статьи на Хабре.
Однако у техники есть куча минусов: например с ней зеркало может быть только прямой формы, никаких отражающихся чайников и кузовов автомобилей. Кроме того, она требует реализации адекватного отсечения по перекрытию, иначе в отражении еще раз может отрисоваться половина мира и уронить FPS (самый простой способ — поделить уровень на комнаты и рисовать только ту комнату, в которой находится игрок, в таком случае зеркала превращаются в частный случай порталов). Но многие игры использовали ее для воды до появления нормального рендера в текстуру в качестве альтернативы screenspace-отражений.
Для кузовов автомобилей и других не-плоских объектов применялась иная, довольно хитрая техника. До появления кубических карт текстур (из которых сэмплить можно в «3д» координатах, которые в свою очередь можно посчитать от угла взгляда на объект) активно применялась техника сферических карт отражений. Выглядели они как 360 фотографии:
Поскольку геометрию трансформировал процессор, на этапе перемножения вершин на MVP-матрицу он генерировал новые текстурные координаты, которые брали нормаль вершины в пространстве камеры, делили его на 2 и прибавляли 0.5, дабы перевести из View-space в Normalized-space. Получалось что координата идеально огибала сферу и делала красивые отражения. Бонусом эту же карту можно было использовать в качестве неба (которое анимировалось путем того, что сфера прсто крутилась вокруг своей оси) — и таким образом мы получали статический Reflection-probe.
На скриншоте из NFS Hot Pursuit 1 можно увидеть отражения не только на автомобилях, но и на дороге. Техника была по сути «бесплатной» на видеокартах с мультитекстурированием — как например на 3dfx Voodoo 2.
Анимация
Кроме того, думаю многим читателям будет интересно узнать о том, как в те годы делали анимацию. Ни для кого не секрет, что в подавляющем большинстве современных игр для анимации используется скиннинг — то есть модель разбивается на иерархию (кости), где трансформация каждого элемента зависит от трансформации родительского элемента. Это очень удобно для гуманоидных персонажей, поскольку позволяет легко одевать персонажа в броню или положить ему в руки пушку, а также позволяет использовать одну анимацию на десятках разных персонажей.
Однако до появления скиннинга существовала еще одна очень похожая система, называемая Object Transform. Работает она по тому же принципу, но положение объектов зависит не от костей и их весов, а от позиции/поворота самих объектов. Иными словами, персонажи собирались просто из набора кусочков — руки, локти, торс, ноги, и всё анимировалось отдельно. Помните угловатых персонажей в GTA III и Quake 3? Вот это оно и есть :)
Обратите внимание на сочленения — видно что колени и бедра как бы впиваются в таз персонажа, поскольку это отдельные объекты. Модель Томми выглядит естественно благодаря использованию скиннинга. Скриншот с gtaforums.
Помимо Object Transform, в те годы также активно использовался морфинг. Это самая простая система анимации, которая «запекает» позиции вершин для каждого кадра отдельно, после чего вершины интерполируются движком для создания плавности. Несмотря на возможность реализации интересных эффектов по типу реакции на взрывы и лицевой анимации, она является самой неэффективной, поскольку занимает много памяти и не умеет ретаргетинг (применение одной анимации к нескольким моделям). Кроме того, с этой системой сложно положить пушку в руки персонажу, из-за чего во многих играх оружие было неотъемлемой частью персонажа.
В Quake можно было отключить интерполяцию и анимация монстров становилась дерганной и резкой. В современных играх этот способ тоже используется для объектов вдалеке - для экономии числа вычислений в вершинном шейдере.
Однако у этой системы есть неоспоримый плюс — нулевая нагрузка на процессор, благодаря чему ее использовали в Quake 1 и 2, и иногда используют для некоторых особых случаев в современных играх.
❯ Заключение
Вот такими техниками пользовались разработчики игр в 90-х годах. Многие из них используются и по сей день — например лайтмаппинг, шедоумапы, морфинг и PVS никуда не делись, и все эти техники за последние 20 лет сильно прокачались. А вам интересно было узнать о том, как работали графические фишки в играх прошлых лет? Стоит ли писать подобный материал для 2D-игр (там выйдет поменьше, но тоже есть о чем рассказать)? Пишите свое мнение в комментариях!
К слову можно считать эту статью предисловием к будущему материалу о разработке 3D-игры для ретро-компьютеров с нуля, без каких либо движков! В качестве тестовых машин, мне было бы интересно пощупать что‑то ещё из семейства Nvidia ION/Radeon Xpress Graphics/VIA Chrome9 HC/Trident Blade. Если у кого‑то есть всякие интересные тонкие клиенты или ноутбуки на прикольном железе, или что‑то AMD'шное времен 939/462 — пишите в ЛС, обязательно сделаю контент!
Олды блога могут вспомнить мою демку про самолетики. Возможно скоро будет статья про куда более крутую игру для ретро компьютеров и возможно даже PSP и PS2!
Ну а я надеюсь, что вам было интересно. Подписывайтесь на блог, чтобы не пропускать новые статьи каждую неделю! А если вам интересна тематика ремонта, моддинга и программирования для гаджетов прошлых лет — подписывайтесь на мой Telegram‑канал «Клуб фанатов балдежа„, куда я выкладываю бэкстейджи статей, ссылки на новые статьи и видео, а также иногда выкладываю полезные посты. А ролики (не всегда дублирующие статьи) можно найти на моём YouTube канале.“»
А если вы хотите что‑нибудь подарить из железа и увидеть о нём статью — пишите мне в Telegram, Max или ВК. Меня очень интересуют самые разные гаджеты: начиная от игровых консолей и любых связанных с геймингом устройств, телефонов, смартфонов, КПК, заканчивая ретро‑компьютерами и ноутбуками. Кто знает, может героем следующейподобной статьи окажется ноутбук из 90-х?:‑)
Особенно сильно я люблю ковыряться в ноутбуках из начала 90-х. Источник
После обзоров устройства не продаются, а остаются в моей коллекции. Когда‑нибудь я хочу сделать музей, где к каждому устройству можно будет приложить QR и почитать мою статью. Кто знает, вдруг на следующей неделе я также подробно расскажу про девайс из вашей юности?:)
Кстати, у меня есть GameBoy Advance SP, под который я очень хочу написать игру. Однако мой экземпляр был залит водой и кофе. Может у кого‑то есть донор с дохлой платой, откуда я смог бы взять контроллер питания? У меня AGS-101.
Недавно мне подарили настоящую легенду — STB 3dfx Voodoo 3 с двумя TMU, 16'ю мегабайтами видеопамяти и 2D-ускорителем. Как настоящий гик и любитель покопаться в ретро-железе, я сразу же нашел даташит и начал изучать внутреннюю архитектуру этого игрового монстра. И поверьте, здесь есть на что посмотреть!
В сегодняшней статье мы во всех деталях изучим архитектуру оригинальной 3dfx Voodoo, узнаем почему Nvidia выиграла в гонке видеокарт и почему игры с API Glide выглядели гораздо красивее, чем с D3D/OpenGL! Если любите настоящие технарские статьи без нейрослопа и рерайта — жду вас под катом!
❯ Предыстория
Думаю многие мои читатели знают, что 3dfx стала одним из пионеров 3D-графики на ПК для геймеров. Их видеокарты не отличались поддержкой «шейдеров», как Rendition Verite, долгое время толком не поддерживали OpenGL, а первые модели для работы требовали отдельную 2D-видеокарту. Однако их успех был обусловлен двумя главными факторами: масштабируемость и производительность.
Rendition Verite V2200. Фото моё
Первая 3dfx Voodoo появилась в 1996 году и несмотря на высокую цену в ~300$, почти сразу стала хитом. Во первых, из конкурентов у Voodoo был разве что NVidia NV1, Rendition Verite и PowerVR Midas. NV1 сразу провалился из-за использования растеризатором квадов вместо привычных разработчикам треугольников, PowerVR был достойным конкурентом, но его TBDR-растеризатор сильно терял филлрейт и подтормаживал при отрисовке полупрозрачных поверхностей типа заборов и решеток (чего в играх всегда хватало), и только Verite был реальным конкурентом. Однако Verite не поддерживал ни OpenGL, ни D3D (который тогда был в зачаточном состоянии) и требовал освоения весьма сложного графического API — SSpeedy3D.
3dfx Voodoo 1 с одним TMU. Фото с TechPowerUp
Дело в том, что в те годы каждый производитель видеокарт предлагал своё графическое API для взаимодействия с видеокартой. У S3 это был Metal, у ATi — CIF, а у 3dfx — Glide. И в отличии от других API, Glide был максимально близок к стандартному и простому OpenGL, только с изначальным упором на игры. В те годы, разработчики игр были вынуждены адаптировать свой движок для каждой видеокарты отдельно и благодаря своей простоте и продуманности, Glide стал неким стандартом — любой уважающий себя движок вплоть до 2000-го года обязательно поддерживал видеокарты 3dfx.
Carmageddon — одна из BRender-игр с поддержкой Glide. Скриншот с форума CWABoard
Однако в 1997 году, у 3dfx уже появились серьезные конкуренты в лице ATi и Nvidia. 3dfx Voodoo мало того что сама стоила ~200-250$, так ещё и для работы требовала дополнительную внешнюю 2D-видеокарту, которая стоила еще баксов 50. За ~150$, Nvidia предлагала новенькую Riva 128 с 4МБ видеопамяти, встроенным 2D-ускорителем, а также аппаратным декодером DVD-видео. ATi Rage Pro стоила примерно столько-же, по тестам была чуток медленнее, чем Nvidia, но также предлагала ноутбучные версии с поддержкой LVDS. Так что ноутбуки с чипами ATi с натяжкой можно было назвать игровыми.
ATI Rage LT Pro в Compaq Armada M300. Фото моё
3dfx решила проблему необходимости 2D-видеокарты весьма интересным костылем: компания выпустила Voodoo Rush — связку из 2D-видеочипа от Alliance Semiconductor и обычной Voodoo 1. Ирония была в том, что на видеокарты ставили как 2D-чипы AT25, так и 3D-чипы AT3D — и получалось что в системе было аж два видеочипа с поддержкой 3D-ускорения (и AT3D был не так уж и плох).
3dfx Voodoo Rush с видеочипом AT25. Фото с сайта vintage3d
Ещё через год, в 1998 году, 3dfx выпустила Voodoo 2, которая стала ещё круче за счёт масштабируемости. Во первых, к GPU стало возможным подключить второй текстурный юнит, благодаря чему стало возможным наносить сразу две текстуры за один проход. А во вторых, теперь можно было объединить сразу две видеокарты с помощью технологии SLI, благодаря чему общая производительность теоретически увеличивалась в два раза. Причём SLI был реализован просто и гениально: первая видеокарта рисовала четные сканлайны, вторая — нечетные, и всё это делалось асинхронно, благодаря чему увеличивался общий филлрейт.
3dfx Voodoo 2 в исполнении Diamond Multimedia. Фото из Википедии
Однако Voodoo 2 всё ещё требовала внешнюю 2D-видеокарту и на момент 1998 года это было уже ни в какие ворота. S3 Savage, ATi Rage 128, NVidia Riva TNT, Matrox G200, Trident 3DImage, Rendition Verite V2200, Intel i740, SiS 6326 — абсолютно все эти видеокарты имели в себе приличный 2D-ускоритель. Причем Riva TNT также поддерживала мультитекстурирование, вплотную подбиралась к Voodoo 2 в бенчмарках и, в отличии от видеокарты от 3dfx, поддерживала рендеринг в 24х-битном формате. Это был главный конкурент Voodoo 2, который местами его заметно превосходил.
S3 ViRGE. Фото моё
В 1999 году появилась 3dfx Voodoo 3, в которой наконец-то появилось 2D-ядро, а благодаря переходу на более продвинутый техпроцесс удалось засунуть сам GPU и два текстурных юнита в один чип. Кроме того, инженерам 3dfx удалось повысить частоту работы видеоядра с 90МГц до 130+. Наконец, благодаря интеграции всех компонентов в один кристалл, стало возможным сделать бюджетную видеокарту — Velocity 100, которая представляла из себя Voodoo 3 с уменьшенным объёмом видеопамяти с 16МБ до 8, а также одним отключенным текстурным юнитом (который включается обратно твиком в реестре :)). Эта версия стоила ~80$ и стала первой доступной Voodoo «для всех».
STB Velocity 100. Фото моё
Но... было уже поздно. 3dfx Voodoo 3 была популярной за счёт остаточной славы и поддержки играми Glide, но с точки зрения функционала, видеокарты от Nvidia и ATi их давно уже уделывали вчистую. В 1999 году, у Nvidia в GeForce 256 уже появился T&L, кубмапы (возможность реализации полноценных отражений), бамп-маппинг и некоторые другие продвинутые техники. Voodoo 4, вышедшая в 2000 году перед банкротством компании, не смогла спасти ситуацию — она хоть и поддерживала 24х-битный цвет, но отсутствие T&L сильно било по производительности в играх с заметно возросшей полигональностью. По итогу, 3dfx обанкротилась и была выкуплена мелким зеленым стартапом — Nvidia :)
❯ Аппаратная архитектура
Как я уже говорил ранее, видеокарты 3dfx не имели каких-то архитектурных особенностей типа возможности загрузки микрокода в GPU или тайлового рендеринга. На практике это были простейшие Fixed-Function сканлайн-растеризаторы, где внешний вид каждого треугольника задавался набором регистров, и кроме отрисовки примитивов GPU больше ничего не умел. Почти во всех остальных картах того периода архитектура была точно такой-же и функционально Voodoo не так сильно отличался от условного S3 ViRGE или Intel i740, просто инженерам 3dfx удалось выжать максимальную производительность.
Однако на аппаратном уровне, видеокарты 3dfx заметно отличались от современников за счет того, что состояли как минимум из трех чипов:
TMU — тот самый текстурный юнит, о котором я говорил в вводной части статьи. В его задачи входит сэмплинг текстур, при этом он занимается не просто выборкой пикселей из видеопамяти, но и мип-маппингом, фильтрацией, а также перспективной коррекцией. В Voodoo 2 на одной видеокарте может быть сразу 3 TMU — что позволяет рисовать геометрию аж с 3-мя текстурами одновременно за один проход. Чисто технически, TMU тоже является полноценным растеризатором, так что его можно считать «мини-GPU».
Если игра рисует примитив с мультитекстурированием (например стенку с наложенной текстурой кирпича и пыли) — рендеринг работает параллельно: сначала первый TMU нарисует стенку с кирпичом, затем второй нарисует с пылью — в конце FBI смешает их и получится пыльная кирпичная стена! Без мультитекстурирования, игре пришлось бы сначала нарисовать кирпичную стенку, затем включить дорогой альфа-блендинг в режиме умножения ((SRCCOLOR * DESTCOLOR) + (DESTCOLOR * 0)) и нарисовать эту же стенку с текстурой пыли ещё раз.
Кроме того, TMU умел в проективные текстуры и всякие трюки с UV-координатами, благодаря чему можно было реализовать проективные попиксельные тени в реальном времени, металлические поверхности за счёт сферических карт отражений (помните отражающиеся машинки в NFS HP?) и некоторые другие фишки.
FBI — сам GPU, выполняющий роль растеризатора и управляющий текстурными юнитами, а также линейным доступом к видеопамяти. Даже у FBI образца 1996 года был весьма богатый функционал: и освещение по Гуро, и попиксельный туман, и дизеринг, и Z-буфер/стенсил-буфер, и даже полноэкранное сглаживание! В общем, было всё необходимое для игр, разве что линии с антиальясингом не поддерживались.
Но были и минусы — FBI первых версий не поддерживал float'ы и оперировал исключительно целыми числами и fixed-point арифметикой, а ещё у него не было понятия Clip-Space — всё рисовалось исключительно в абсолютных экранных координатах. Но об этом чуть позже.
RAMDAC — чип, выводивший фреймбуфер из видеопамяти на экран. Работало это весьма забавно: когда пользователь использует 2D-окружение — RAMDAC в 3dfx Voodoo отключается и VGA-сигнал с 2D-видеокарты коммутируется напрямую на VGA-разъём в Voodoo. Когда пользователь запускает 3D-игру (а в первых 3dfx Voodoo 3D-режим был эксклюзивным) — FBI переключал линии на свой RAMDAC. Получается что в ПК работало сразу два RAMDAC'а одновременно :)
Не менее интересной была и организация памяти. Дело в том, что все 4/8/16 мегабайт видеопамяти были отдельно поделены между TMU и FBI. Каждому TMU отдельно отводилось по 2-16 мегабайт VRAM, которые использовались только для хранения текстурных данных. У FBI была своя память объёмом в 2-4МБ, которая использовалась для фреймбуфера, Z-буфера и Stencil-буфера. От объёма VRAM для TMU зависело сколько текстур и какого разрешения можно загрузить на текущем уровне в игре, а от объёма памяти для FBI зависело максимальное разрешение изображения и возможность использования техник типа Stencil-зеркал или теней.
Схема из даташита 3dfx Voodoo 2
Главной проблемой 3dfx Voodoo был примитивный конвейер, который по большей части ложился на процессор. Для отрисовки каждого треугольника, процессору приходилось:
Посчитать степень освещенности каждого треугольника по алгоритму Гуро и Фонгу. То есть как минимум N ⋅ L.
Перемножить каждую вершину модели на матрицу модели-вида-проекции, чтобы получить позицию треугольника в пространстве экрана — так называемом Clip-Space. Каждую координату нужно было вручную поделить на W-компоненту вершины.
Затем ему нужно было произвести так называемый процесс клиппинга — разбиения наполовину-видимых треугольников, которые пересекают ближнюю плоскость отсечения (или «нос» игрока, если говорить простыми словами). Самый простой пример — это оружие в Quake: если клиппинг не делать, то задняя (невидимая нам) часть пушки просто инвертирует свои координаты и будет отображаться «перевернутой» уходя вдаль, хотя она должна просто скрыться из виду. Это самый тяжелый алгоритм, поскольку требует поиска точки пересечения треугольника с границей экрана и разбиения его на два новых.
Далее ему нужно было преобразовать Clip-Space координаты с плавающей точкой в абсолютные координаты ((((x * 0.5) + 0.5) * width) + (width / 2)). 3dfx Voodoo 2 наконец-то научился в floating-point координаты в Clip-Space, но для совместимости всё равно лучше было использовать «старый» подход.
И только затем пинать его в видеокарту, вручную записывая параметры каждого треугольника в регистры FBI по одному. Помните glBegin/glEnd? Вот это как раз оттуда :)
Для сравнения, в GeForce 256 ни один из этих этапов вообще не нужен был. Геометрию можно загрузить в специальную область в видеопамяти и отправить команду на отрисовку, после чего видеокарта сама всё сделает. Именно поэтому 3dfx Voodoo хорошо себя показывал в старых играх, где сцены были 4000-10000 треугольников, но вот когда игры пошли 30-40 тысяч полигонов... тут уже нагрузка на процессор была слишком высокой.
Между слов...
От схожей проблемы страдали и GPU от Intel. Тот же GMA900 был отнюдь не самым слабым видеочипом, но отсутствие аппаратного вершинного конвейера и установка в бюджетные ноутбуки с слабыми процессорами сделало своё дело...
Аппаратный конвейер в Intel'ах появился только начиная с GMA 500 — и то это на самом деле был PowerVR SGX535 :)
Интересно и то, что в 3dfx Voodoo 2 уже были зачатки 2D-движка в виде аппаратного блиттера, причем с возможностью блиттить как из оперативной памяти ПК, так и видеопамяти, но API для него в Glide я не нашел. Судя по всему, 3dfx просто не успела доделать полноценный VGA-совместимый контроллер в 1998 году, оставив в видеочипе только блиттер.
Схема из даташита 3dfx Voodoo 2.
На самом низком уровне, управление 3dfx Voodoo происходило в основном с помощью замаппленых в память регистров. Драйвер искал PCI-устройство, выделял ему Base Address Register и затем конфигурировал FBI относительно текущего видеорежима. Когда игра хотела нарисовать следующий треугольник, драйвер записывал параметры вершин в соответствующие регистры FBI и TMU (да, регистры, связанные с вершинами у них дублировались) и отправлял команду TRIANGLECMD.
Вот он, D3D11_INPUT_ELEMENT_DESC! Скриншот из даташита 3dfx Voodoo 2
Да, всё было настолько просто. Как я уже говорил, так было не только у 3dfx, но и у S3 (о ViRGE я писал отдельную статью), Intel, SiS, ATi и Nvidia до GeForce 256. Отличался только Rendition Verite, но о нём мы с вами поговорим как-нибудь в другой раз.
❯ Программная архитектура
С точки зрения софта, у 3dfx Voodoo тоже всё было не так однозначно. Конечно основным графическим API был Glide, однако в 1997-1998 году стандартизацию и влияние OpenGL и Direct3D отрицать было глупо. Всё больше и больше игр использовали D3D, поддержку которого 3dfx поспешно добавила в 1997 году. Тут важно отметить то, что в те годы каждая версия Direct3D очень сильно друг от друга отличалась. Direct3D 5 оперировал командными буферами на манер современных видеокарт (Microsoft глядели в воду!), Direct3D7 уже был больше похож на OpenGL/D3D9, и обратной совместимости, как в случае с D3D11/D3D10/D3D9 у них не было — 3dfx приходилось писать новый драйвер под новые версии DirectX.
Ещё про командные буферы
Назывались они Execute-буферами и имели тот же функционал, что и списки в OpenGL. Microsoft надеялась что рано или поздно Execute-буферы можно будет выполнять напрямую на GPU - и угадала примерно к 1999-2000 году.
Самое забавное что сама концепция не прижилась и вплоть до D3D11 в видеокартах не было нормальных буферов команд.
Не путайте командные буферы с стейтблоками - это разные вещи.
Лого 3dfx. Взято с ныне почившего сайта компании
С OpenGL тоже было всё не так гладко, поскольку в 1996 году его перспективы в играх всё ещё были туманны из-за ориентира на профессиональные рабочие станции. В конце-концов, кому в играх нужен был рендеринг на сервере? Однако игра поколения, Quake, использовала именно это графическое API и 3dfx пришлось сделать небольшой костыль вместо полноценного драйвера — MiniGL.
MiniGL работал поверх нативного графического API (т.е Glide) и предоставлял игре минимально-необходимый для работы набор функций — то есть рисование треугольников/квадов, работу с текстурами, матрицы и... ну, по сути все. Другие игры также могли использовать MiniGL, но у них не было доступа ни к функциям работы с туманом, ни к освещению в реальном времени, ни к мультитекстурированию, ни к Stencil-буферу. Немного позже другие производители видеокарт тоже начали реализовывать свои драйверы MiniGL и это стало своеобразным MiniAPI внутри Quake.
Полноценный нативный ICD-драйвер (так в те годы называли полноценные драйвера OpenGL) для OpenGL вышел только в 1998 году в виде бета-версии... и по сравнению с MiniGL, он был нереально тормозным и глючным! Часть функционала была забагованной, производительность была не ахти и даже в Quake на ICD видеокарта показывала себя хуже, чем с MiniGL. Но в целом, 3dfx за это винить не стоит — в те годы нормальные драйвера для OpenGL были только у Nvidia, S3 и Intel (иронично). Даже у ATi с OpenGL всё было очень плохо...
Поэтому главным секретом успеха 3dfx стало API Glide. Как я и говорил ранее, оно как две капли воды было похоже на упрощенный OpenGL, но отличалось отсутствием математической библиотеки, клиппера геометрии (да, программист был вынужден писать его сам, в отличии от D3D и GL) и... аллокатора текстур! Да, вы все правильно поняли — предполагалось что именно программист будет вручную управлять видеопамятью каждого текстурного юнита и ручками писать логику выделения/освобождения памяти.
С игровой точки зрения, Glide был функционально богаче D3D и OpenGL, и обгонял их на несколько лет вперед. Уже в 1998 году, в Glide была поддержка мультитекстурирования и комбайнеров, хромакея вместо альфа-теста (который требовал дополнительный цветовой компонент и занимал драгоценную видеопамять) и прямого доступа к фреймбуферу. Зато не поддерживались текстуры с разрешением выше 256x256 и соотношением сторон, отличающимся от 1:1 и 2:1...
В остальном, Glide был практически прямым интерфейсом к видеокарте, благодаря чему работал быстро. Но к 2000 году, Glide окончательно устарел концептуально, вместе с архитектурой оригинального 3dfx Voodoo, из-за чего компания и разорилась. ATi и Nvidia оказались шустрее...
❯ Заключение
Вот такой была 3dfx: сначала компания влетела на рынок игровых видеокарт с двух ног, успела стать стандартом ПК-гейминга, но всего через 3 года её архитектура устарела настолько быстро, что в 2000 году её поглотил какой-то там стартап с зеленым логотипом... Увы и ах, остается только надеяться, что инженеры 3dfx приложили руку к таким легендарным видеокартам, как GeForce 3 и GeForce 4! Хотя кто знает, может кто-то из них сейчас разрабатывает RTX 6xxx? :)
Ну а я надеюсь, что вам было интересно. Подписывайтесь на блог, чтобы не пропускать новые статьи каждую неделю! А если вам интересна тематика ремонта, моддинга и программирования для гаджетов прошлых лет — подписывайтесь на мой Telegram-канал «Клуб фанатов балдежа», куда я выкладываю бэкстейджи статей, ссылки на новые статьи и видео, а также иногда выкладываю полезные посты и щитпостю. А ролики (не всегда дублирующие статьи) можно найти на моём YouTube канале.
А если вы хотите что-нибудь подарить из железа и увидеть о нём статью — пишите мне в Telegram. Меня очень интересуют самые разные гаджеты: начиная от игровых консолей и любых связанных с геймингом устройств, телефонов, смартфонов, КПК, заканчивая ретро-компьютерами и ноутбуками. Кто знает, может героем следующейподобной статьи окажется ноутбук из 90-х? :)
Особенно сильно я люблю ковыряться в ноутбуках из начала 90-х. Источник
После обзоров устройства не продаются, а остаются в моей коллекции. Когда-нибудь я хочу сделать музей, где к каждому устройству можно будет приложить QR и почитать мою статью. Кто знает, вдруг на следующей неделе я также подробно расскажу про девайс из вашей юности? :)
Кстати, у меня есть GameBoy Advance SP, под который я очень хочу написать игру. Однако мой экземпляр был залит водой и кофе. Может у кого-то есть донор с дохлой платой, откуда я смог бы взять контроллер питания? У меня AGS-101.
Наступил четверг и настало время для очередной Игры Недели, чтобы напоминать о крутых играх которые мы уже сделали на Dos.Zone, и чтобы не предавать их забвению. На первых двух частях GTA мы обкатывали нашу новую технологию WebGL3Dfx, которая открыла дорогу еще более крутой эмуляции ПК игр в браузерах.
А еще эти игры точно также как Vice City вежливо попросили удалить юристы Take Two выслав нам второй по счету pre-DMCA.
В недавнем интервью-подкасте я подробно рассказывал про нашу новую технологию WebGL3Dfx и даже объявил релиз 3Dfx версии кармагеддона, вот только мы забыли ее выложить Так что держите!