Рассмотрев в «Мире ПК» №5/03 основы, возможности и некоторые программистские аспекты технологии шейдеров, перейдем к практике.

На данный момент существует как минимум четыре способа создания шейдеров. Это написание их в API DirectX 9 или OpenGL версий 1.x с использованием различных расширений, применение OpenGL 2, где поддержка шейдеров встроена изначально. Весьма мощный и удобный инструментарий Cg Toolkit компании nVidia позволяет не только писать шейдеры, но и просматривать их в режиме реального времени, выполнять различные подготовительные операции. Впрочем, и в DirectX 9 имеются средства редактирования шейдеров в реальном времени, обработки текстур и анимации.

Мы же рассмотрим наиболее простой и наглядный способ программирования на языке шейдеров: с помощью подключаемых модулей для пакета Maya, которые можно бесплатно загрузить с сайта компании nVidia. Там же доступны аналоги для 3dStudioMax и Softimage. Сразу отмечу, что в этом случае не требуется знать ни пакет Maya, ни программирование. Еще одним преимуществом такого подхода является более наглядное представление результатов работы и механизмов взаимодействия шейдеров с внешней средой. Результатами же вы сможете воспользоваться не только в редакторе Maya для создания 3D-сцен, но и в собственных интерактивных программах, так как полученные шейдеры, по заявлению разработчиков, будут совместимы с DirectX 9 и OpenGL.

Модуль расширения Maya Cg и его установка

Для загрузки данного модуля расширения необходимо зайти на сайт компании nVidia по ссылке http://developer.nvidia.com. После этого останется только запустить полученный exe-файл и указать папку для установки инструмента, подключение же к Maya будет выполнено автоматически.

Но для того, чтобы подключаемый модуль установился, на вашем компьютере должна быть инсталлирована среда CgFX Runtime, которую можно переписать на том же сайте. Правда, мне пришлось ее еще и откомпилировать в Visual Studio. Впрочем, эта процедура также не потребовала больших знаний: достаточно было найти проект в многочисленных папках Cg Toolkit, открыть его и запустить процесс сборки.

Первое знакомство

Итак, если на вашей машине уже установлены программа Maya, подключаемый модуль для нее Maya Cg и среда CgFX Runtime, то пора приступить к тестированию имеющихся в библиотеках программ-шейдеров, которые хранятся в файлах с расширением .fx. Сразу замечу, что существует два основных формата шейдеров: собственно шейдеры, находящиеся в файлах с расширением .cg, и файлы эффектов с расширением .fx. Вторые отличаются тем, что содержат всю необходимую информацию для применения нужного эффекта в сцене. Это вложенные вершинные и пиксельные шейдеры, а также специальные конструкции языка, реализующие возможность писать один шейдер для нескольких аппаратных платформ.

Теперь запустите пакет Maya. Новичкам не стоит его бояться, так как для работы с шейдерами потребуется только малая толика функциональных возможностей этого продукта. В созданный пустой документ вставьте какой-либо объект, который обязательно должен быть полигональным. Поэтому нажмите и удержите <Пробел>, после чего в окне появится необычное всплывающее меню (рис. 1).

Рис. 1. Всплывающее меню Maya

При нажатом <Пробеле> выполните левый щелчок мышью на пункте Create, не отпуская кнопки переведите указатель на пункт Polygon Primitives и далее выберите любой объект для испытания на нем своего первого шейдера (я выбрал Sphere). В центре сцены появится указанный объект, выделив который с помощью команды Lighting/Shading?Assign New Material?CgFXShader того же всплывающего меню назначьте ему материал CgFXShader. Справа появится окно редактирования материала CgFXShader (рис. 2).

Рис. 2. Панель настройки материала CgFXShader

Теперь осталось выбрать в поле CgFX File нужный файл шейдера. Бывает, что не все шейдеры подключаются безупречно, так как ваша графическая плата может их просто не поддерживать. Возможно также наличие ошибок в самом шейдере. Однако на моей GeForce2 MX удалось с успехом поработать c довольно многими шейдерами из пакета расширения для Maya. Определить успешность загрузки можно по полю CgFX Parameters. Если в нем не появился список параметров указанного шейдера, то лучше выбрать другой файл. Кроме того, при успешной загрузке объект на сцене конечно же поменяет текстуру соответственно шейдеру (рис. 3).

Рис. 3. Загруженный шейдер
Рис. 4. Кнопки навигации Maya

Единственное, что еще вам может потребоваться от пакета Maya, это навигация по сцене путем перемещения камеры, которая позволит рассмотреть объект поближе и под разными углами. Для этого достаточно выбрать мышью одну из кнопок (рис. 4) для выполнения различного рода перемещений виртуальной камеры, а кроме того, перевести отображение объектов сцены в режим Smooth Shade All и отметить флажок напротив пункта Hardware Texturing. Все это можно сделать точно так же, как и в предыдущих случаях, используя меню Shading. Ну и напоследок останется указать программе, что подключаемый модуль CgFXShader должен загружаться автоматически после каждого запуска Maya, воспользовавшись меню Windows?Settings/Preferences?Plug-in Manager.

Теперь только о шейдерах

При написании шейдеров применяются два вида входных данных: переменные из внешней среды (uniform) и данные из входного потока (varying). Первые используются для передачи в шейдер некоторых данных, например координат источника света или камеры. Этот параметр одинаков для всех пикселов и треугольников. В Maya часть этих переменных можно передавать в шейдер из панели параметров. Переменные varying могут быть индивидуальны для каждого пиксела или треугольника, так как содержат их описание и данные. Поэтому для изменения varying-параметров можно использовать uniform-параметры, которые доступны только для чтения.

Еще одно важное отличие между двумя видами переменных заключается в том, что uniform являются пользовательскими переменными, которые разработчик задает по своему усмотрению, а varying — предопределенными (встроенными), и зависят они только от обрабатываемой 3D-модели. В листинге 1 приведен пример создания внутренних переменных из предопределенных.

Здесь создается структура входных параметров, которые будут обслуживать шейдер. То есть он сможет получать данные о координате текущей точки и ее нормали. Остальные параметры будут игнорироваться.

Эта структура не зря названа MyVertexInputs, дело в том, что в исходном тексте описывается сразу оба вида шейдеров: вершинный и пиксельный. А это значит, что для них существуют разные входные потоки данных. Для вершинного это параметры вершины, для пиксельного — параметры точки и некоторые выходные параметры вершинного шейдера.

Для входных параметров вершинных шейдеров существуют следующие предопределенные переменные:

  • POSITION;
  • BLENDWEIGHT;
  • TANGENT;
  • BINORMAL;
  • PSIZE;
  • LENDINDICES;
  • TEXCOORD0-TEXCOORD7.

Для выходных параметров вершинного шейдера и соответственно входных для пиксельного существуют переменные:

  • POSITION;
  • PSIZE;
  • FOG;
  • COLOR0-COLOR1;
  • TEXCOORD0-TEXCOORD7.

Последним потоком является вывод данных из пиксельного шейдера, в котором пока возможны только две предопределенные переменные: COLOR и DEPTH (рис. 5).

Рис. 5. Взаимодействие переменных в шейдерах

Часть описанных переменных мы рассмотрим в приведенных ниже примерах, остальные найдутся в документации по языку шейдеров.

Итак, мы разобрались, что должен обрабатывать шейдер и что выводить на экран. Теперь рассмотрим, как все это организовать в законченную программу.

Прежде всего следует учесть необходимость вершинного шейдера для работы пиксельного. На первый взгляд, для наложения, к примеру, процедурной текстуры на объект достаточно пиксельного шейдера. Но на самом деле для такой операции вполне пригодится и вершинный, так как, используя параметры вершин, можно выполнять множество подготовительных вычислений для нужного пиксела.

Если рассматривать формат эффектов, то для них существует только одна характерная синтаксическая конструкция — technique, в теле которой выполняются шейдеры. С ее помощью можно реализовать множество вариантов решения одной и той же задачи на разных аппаратных платформах. После лексемы technique указывается слово, определяющее целевую платформу рендеринга (листинг 2).

При запуске шейдера выполняется проверка его «техник» на соответствие аппаратному обеспечению; если однозначный вывод сделать нельзя, то пользователю выводится запрос с требованием определить, какую именно «технику» применять.

Внутри каждой «техники» должна существовать еще одна конструкция — pass, в которой и выполняется весь исходный текст. Таких конструкций может быть несколько, для каждого слоя шейдера, что позволяет создавать весьма интересные поверхности, совмещая различные виды алгоритмов покрытия поверхностей (листинг 3).

Однако в файлах эффектов внутри «техник», помимо исходного текста, можно приводить описания типов данных и функций, как это делается в Си и Паскале. Так, в нашем примере функция и структуры будут объявлены до ключевого слова technique.

Сами функции при этом могут определяться как обычные функции Си: [возвращаемое значение] [имя функции] [(список входных параметров)] [{...тело функции...}].

В листинге 4 приведены некоторые примеры.

Перед блоками функций, как и в Си, следует определить типы данных. Определение структур описано выше, а вот определение некоторых переменных мы рассмотрим подробнее, так как в них задаются не только стартовые значения, но и некоторые атрибуты.

В нашей программе мы используем две внешние переменные — LightPos и liteColor, которым зададим параметры в интерактивном режиме из Maya в поле параметров. Для этого необходимо сделать объявления специального вида с указанием полей описания и начальных значений (листинг 5).

В обоих объявлениях после двоеточия указывается тип импортируемого значения, в зависимости от которого в поле параметров шейдера Maya будут отображаться различные виды полей ввода (слайдер, поле выбора цвета или несколько полей ввода для векторов).

В параметрах lightPos выполняется привязка к объекту типа PointLight и Space. К сожалению, ни в документации по шейдерам, ни в описании Maya CgFXShader не говорится об этих объектах. Видимо, у разработчиков еще не дошли до них руки. Подобная ситуация возникает и со множеством других внешних переменных, реализованных в CgFX Runtime. Поэтому все необходимые данные можно получить только из исходных текстов шейдеров и CgFX Runtime.

Что касается атрибутов DiffColor, то там все гораздо проще: внутри блока содержится только строка описания, а после него, как и в предыдущем случае, инициализированы стартовые значения.

Простейший шейдер

В листинге 6 рассмотрен исходный текст самой простой программы-шейдера.

Теперь у вас есть все необходимое, чтобы начать собственные эксперименты.

Конечно, при написании шейдеров в Блокноте невозможно получать сообщения об ошибках компиляции, нет и средств отладки. Поэтому сначала целесообразнее использовать готовые шейдеры, но не следует вводить сразу много изменений между перезагрузками шейдера в Maya, иначе вы рискуете не найти возникшую ошибку.

В будущем мы надеемся продолжить знакомить читателей с тайнами шейдеров и средствами их использования.

С автором можно связаться по e-mail: vit@osp.ru.