Что значит компиляция шейдеров
Компиляция шейдеров
В этом разделе описывается FXC.EXE компилятор, используемый для моделей шейдеров 2 – 5,1. Для Shader Model 6 используется DXC.EXE вместо, который описан в статье Использование dxc.exe и dxcompiler.dll.
Microsoft Visual Studio 2012 теперь может компилировать код шейдера из * файлов. hlsl, включаемых в проект C++.
в рамках процесса сборки Visual Studio 2012 использует компилятор кода fxc.exe HLSL для компиляции HLSL файлов в двоичные файловые файлы шейдеров или в байтовые массивы, определенные в файлах заголовков. Как компилятор кода HLSL компилирует каждый файл HLSL в проекте, зависит от того, как указать свойство файлов выходные данные для этого файла. Дополнительные сведения о страницах свойств HLSL см. в разделе страницы свойств HLSL.
Используемый метод компиляции обычно зависит от размера * файла HLSL. Если включить в заголовок большой объем байтового кода, размер и начальное время загрузки приложения будут увеличены. Кроме того, весь байтовый код должен находиться в памяти даже после создания шейдера, что приведет к потере ресурсов. Но при включении в заголовок байтового кода можно уменьшить сложность кода и упростить создание шейдера.
Теперь рассмотрим различные способы компиляции кода шейдера и соглашений для расширений файлов для кода шейдера.
Использование расширений файлов кода шейдера
Чтобы согласовать соглашение с Майкрософт, используйте следующие расширения файлов для кода шейдера:
Компиляция во время сборки в объектные файлы
При компиляции HLSL-файлов в двоичные файловые файлы шейдера приложение должно считывать данные из этих файлов объектов (. cso является расширением по умолчанию для этих объектных файлов), назначать данные байтовые массивы и создавать объекты шейдера из этих массивов байтов. Например, чтобы создать шейдер вершин (ID3D11VertexShader * * ), вызовите метод ID3D11Device:: креатевертексшадер с массивом байтов, который содержит скомпилированный байтовый код шейдера вершин. В примере «учебник по Direct3D » показано, как создавать объекты шейдера из байтовых массивов, полученных из. объектно построителей двоичных файлов шейдера. В этом примере кода из примера учебника по Direct3Dсвойство выходные данные Files для файла симплевертексшадер. HLSL определяет компиляцию в объектный файл симплевертексшадер. cso.
Компиляция во время сборки в файлы заголовков
Компиляция с помощью D3DCompileFromFile
Можно также использовать функцию D3DCompileFromFile во время выполнения для компиляции кода шейдера. Дополнительные сведения о том, как это сделать, см. в разделе инструкции. Компиляция шейдера.
Windows Приложения Магазина поддерживают использование D3DCompileFromFile для разработки, но не для развертывания.
[Решено] Black Ops Cold War застряла на компиляции шейдеров
Black Ops Cold War Stuck Compiling Shaders
Ниже мы собрали последние исправления этой ошибки совместимости шейдеров, попробуйте их и сразу же вернитесь к игре.
В последнее время геймеры сообщают проблема компиляции шейдеров в Black Ops Cold War, что приводит к зависанию или сбою игры. Если вы оказались в одной лодке, не волнуйтесь. Ниже мы собрали последние исправления этой ошибки, попробуйте их и сразу же вернитесь к игре.
Попробуйте эти исправления:
Возможно, вам не придется пробовать их все. Просто спускайтесь вниз, пока не приземлитесь на ту, которая делает трюк.
Исправление 1: отсканируйте и восстановите свою игру
Проблема компиляции шейдеров может быть вызвана повреждением или отсутствием файлов игры. Поэтому, прежде чем пробовать что-то более сложное, сначала вам нужно проверить целостность файлов игры.
Теперь перезапустите Black Ops Cold War и проверьте, можете ли вы пройти компиляцию шейдеров.
Если проблема не исчезнет, попробуйте следующее исправление, указанное ниже.
Исправление 2: перезапустите установку шейдеров.
Вот как перезапустить установку шейдеров:
Если это решение не решает проблему, обратите внимание на следующее ниже.
Исправление 3: обновите графический драйвер
После обновления драйвера графического процессора перезагрузите компьютер, чтобы изменения вступили в силу. Затем запустите игру и проверьте, можете ли вы завершить компиляцию.
Если последняя версия графического драйвера не принесла вам удачи, просто воспользуйтесь следующим методом.
Исправление 4: Удалить папки кеша
Поврежденный кеш может привести к ошибке игры, которая в некоторых случаях останавливает ваш процесс без подсказки. Вы можете попробовать очистить кеш и проверить, решает ли это проблему.
Исправление 5. Свяжите свои учетные записи Activision и Blizzard.
Возможно, у вас застряла компиляция шейдеров, вы не подключили свою учетную запись Blizzard на веб-странице Activision. Вам необходимо убедиться, что ваши учетные записи Activision и Blizzard связаны, чтобы избежать возможных ошибок.
Надеюсь, это руководство поможет вам решить проблему компиляции шейдеров. Если у вас есть какие-либо вопросы или идеи, не стесняйтесь обращаться к нам в комментариях ниже.
Шейдеры. Что и как
Расскажу, как в общем случае они работают, что умеют и как их используют
Сразу оговорюсь, что материал рассчитан на тех, кто никогда не работал с шейдерами или вообще не знаком с разработкой игр, то есть это в некотором смысле научпоп.
Слово «шейдер» в контексте разработки игр очень популярно, слышать его могли и те, кто игры не делает. Само слово изначально появилось от англ. shading (затенение) — первые шейдеры использовались, чтобы передавать глубину с помощью работы со светом, блеском, тенями и прочим. Со временем шейдеры стали использоваться для совершенно разного вида постобработки и вообще отрисовки примерно всего.
Говоря общими словами, шейдер — это просто программа для графической карты. То есть то, что пишется школьниками на паскале (хипстерами на пайтоне) — это программы для вашего центрального процессора (CPU), а шейдеры — для графического (GPU). Особенность же этих программ выходит из особенностей GPU — они работают параллельно на сотнях маленьких ядех вместо нескольких больших, преимущественно осуществляя математические операции.
Теперь разберемся, как это все работает.
В общем случае цель шейдера — отрисовать некоторый объект. Поэтому возьмем куб, распишем процесс его отрисовки и посмотрим, где используются шейдеры и зачем. Сначала опишем сам куб. Для графической карты это 8 точек, между некоторыми из которых есть плоскость. Каждая из точек описывается тремя числами (правильно сказать, что это вершины). Помимо этого у кубика есть цвет и положение внутри мира.
Процесс отрисовки, если его достаточно упростить (что я и сделаю в рамках этой статьи), можно поделить на несколько шагов:
1. Получение входных данных из памяти.
2. Выполнение шейдера вершин.
3. Растеризация.
4. Выполнение шейдера пикселей (фрагментов).
5. Проведение тестов «глубины».
6. Отрисовка на текстуру для экрана.
В первом шаге видеокарта каким-то образом получает данные (вершины, плоскости, текстуры) в свою видеопамять, для нас это сейчас не так важно. Далее происходит конвертация координат относительно объекта в координаты на экране относительно камеры. После происходит растеризация — высчитывается, в каких пикселях уже на экране находится объект. Такие пиксели называют фрагментами. Отличие от пикселей заключается в том, что фрагмент помимо информации о пикселе, содержит еще и некоторую побочную информацию, полученную после растеризации. Для упрощения будем считать, что это все просто пиксели на экране. Далее для каждого пикселя выполняется шейдер фрагмента. А затем проверяется, что расстояние от камеры до фрагмента соответствует высчитанному заранее в нужном направлении в буфере глубины. Проще говоря, проверяется, нет ли перед объектом чего-либо еще, и нужно ли его отрисовывать на итоговое изображение.
Как видите, в процессе отрисовки можно заметить два вида шейдера. На самом деле, сейчас есть чуть больше видов, но они не столь важны для разбора, так как имеют более специфичный характер использования, а мы рассказываем на пальцах. Но вот те два, что нас волнуют:
1. Шейдер вершин.
2. Шейдер фрагментов.
Как сказано было ранее, этот шейдер (или группа шейдеров по очереди) занимается переводом координат относительно объекта, в координаты на текстуре.
На картинке начало координат немного не соответствует реальным, что все так же не влияет на понимание процесса 🙂
Пройдемся по состояниям. В первом у нас, очевидно, входные координаты без излишков. На втором они были перенесены в координаты относительно начала «мира». Потом они переносятся в координаты относительно точки смотрящего (видно на второй картинке), но заметно, что картинка плоская. Их проекция происходит далее и мы получаем наши итоговые координаты. Все эти операции производятся шейдером. Помимо прочего, он позволяет не только отобразить реальные координаты, но и модифицировать их так, чтобы исказить объект для эффекта. Например, я недавно писал шейдер, который переворачивал спрайт, чтобы отрисовать его тень:
После преобразований вершин и растеризации нужно высчитать цвет каждого фрагмента (помним, что для упрощения это пиксели). Для примера возьмём наш куб: мы помним, что он залит одним цветом. Просто сделаем так, чтобы цвет каждого фрагмента стал цвета куба и все:
Выглядит немного странно, да? Проблема в том, что мы не видим ни теней, ни текстур. Будь на кубе какая-либо текстура, мы бы заметили переход между гранями. Вот возьмем текстуру:
Теперь достаточно в каждом пикселе просто брать цвет из текстуры. Но чтобы это сделать, нужно добавить для каждой точки куба еще информацию: UV канал. Это координат вида (u, v). Отсюда и название, так как x и y были заняты. Она присваивается вершине объекта и обозначает точку на текстуре, которая ей соответствует. Чтобы было понятнее, если мы хотим на каждую грань куба нарисовать знакомое нам лицо, то UV координаты для каждой грани будут выглядеть предельно просто:
Модифицировать их никак не надо. Более того, считать координаты для каждой точки — тоже не нужно. Этим занимается GPU, самостоятельно интерполируя точки из вершин. Тогда достаточно просто сказать для каждой точки что-то вроде
Это очень условный пример, но примерно так в простейшем случае оно и работает:
Помимо натягивания текстур в пиксельном шейдере можно, например, получить информацию об освещенности и добавить к цвету черного пропорционально затемнению в этой точке, тогда объект будет менее плоским. Это, конечно, если просчет освещенности где-то написан, потому что сама по себе видеокарта о понятиях освещения и теней мало чего знает. Вообще делать с цветами можно что угодно, например подменять их в зависимости от игрока:
Помимо UV канала в шейдер в зависимости от его вида приходят разные данные. Они зависят от игрового движка и графической библиотеки. Обычно туда входят данные о местоположении точки, нормаль (вектор исходящий от поверхности в точке), UV канал. Но также шейдер вершин может передавать данные в пиксельный шейдер. Если это координата, то она будет проинтеполирована на основе положения фрагмента относительно вершин, между которыми он находится, как, например, UV данные.
Что значит компиляция шейдеров
Чтобы поместить шейдер, который вы только что написали, в ваш графический движок, вы делаете в основном те же самые вещи, которые FX Composer делает, чтобы показать вам шейдер. Благодаря DirectX или XNA легко загрузить файл шейдерного эффекта и установить все требуемые параметры (вы уже делали это в предыдущей главе для шейдера визуализации линий). В следующей главе вы перейдете к использованию более общего класса, который принимает много различных шейдеров и использует более оптимизированный способ установки всех необходимых шейдерам параметров, а в этой главе мы просто заставим файл SimpleShader.fx работать в вашем движке.
Как обычно, начнем с определения тестового модуля. Создайте новый файл с именем simpleShader.cs в пространстве имен Shaders и напишите следующий код:
Тестовый модуль должен компилироваться, за исключением метода renderModel нового класса SimpleShader, который еще не определен. Давайте быстро определим этот метод:
Теперь тестовый модуль компилируется, и вы можете запустить его, чтобы увидеть пустой экран.
Компиляция шейдеров
Загрузить скомпилированный эффект так же просто, как загрузить текстуру. Просто определите переменную эффекта, а затем загрузите ее в конструкторе SimpleShader:
На платформе Windows вы также можете загружать шейдеры динамически (в этом случае они не будут заранее скомпилированы XNA Framework), что может быть полезно для тестирования и изменения шейдеров во время выполнения вашей игры. Обычно во время разработки для большинства шейдеров я использую некомпилированные файлы шейдеров, а затем помещаю их в конвейер содержимого, когда игра завершена и я больше не собираюсь изменять шейдеры. Для самостоятельной загрузки и компиляции шейдеров используется следующий код:
Использование параметров
Как вы узнали в процессе создания шейдера, мировая матрица, матрица вида и матрица проекции действительно важны для преобразования ваших трехмерных данных и получения корректного результата на экране. Для установки всех этих параметров шейдера вы просто используете метод RenderModel, который вызывается из вашего тестового модуля:
Сначала в этом коде устанавливается мировая матрица. Это очень важно, поскольку если не устанавливать мировую матрицу, она может содержать абсолютно сумасшедшие значения от каких-нибудь предыдущих операций, и трехмерная модель будет визуализирована в каком-нибудь случайном месте, а не там, где вам надо. Поскольку модель яблока достаточно большая, вы слегка уменьшаете ее масштаб, чтобы она соответствовала размерам экрана в используемом по умолчанию классе SimpleCamera из предыдущей главы.
Формат вершин
Перед тем, как визуализировать данные из вашей трехмерной модели яблока, вы должны убедиться, что ваше приложение и шейдер знают, какой формат вершин использовать. В DirectX это достигалось путем простой установки одного из предопределенных форматов вершин фиксированного конвейера функций, но эти форматы больше не существуют, и вы не можете установить их. Вместо этого вы должны определить полное объявление вершины, также как делали это в шейдере для структуры VertexInput. Поскольку мы просто используем встроенную структуру VertexPositionNormalTexture, нам не надо ничего определять самостоятельно, но в следующей главе вы узнаете, как сделать это для собственного нестандартного формата TangentVertex.
На самом деле вам не нужно создавать новое объявление вершин каждый раз, когда вы вызываете RenderModel, но чтобы упростить материал я строю новое объявление вершин при каждом вызове. В первом параметре передается графическое устройство, а во втором — массив элементов вершин из структуры XNA VertexPositionNormalTexture. За дополнительной информацией обращайтесь к главе 7.
Визуализация с шейдерами
Чтобы теперь визуализировать яблоко с вашим шейдером необходимо сначала указать, какую технику вы хотите использовать (в любом случае, по умолчанию будет установлена первая техника, но полезно знать, как устанавливать техники). Для визуализации шейдера вы всегда будете использовать свойство CurrentTechnique класса эффекта. Затем вы проходите по технике так же, как это делает FX Composer, — вы рисуете все трехмерные данные для каждого прохода, который есть в технике (как я говорил раньше, обычно у вас будет только один проход). Визуализация самого яблока не то чтобы очень проста, поскольку единственный метод, который XNA предоставдяет вам для этого, это mesh.Draw, который надо вызывать для каждой сетки модели после установки необходимых параметров шейдеров, что вы видели в предыдущей главе, когда писали класс Model.
Другая вещь, отсутствующая в XNA Framework, это вспомогательные методы для создания сеток кубов, сфер или чайников. Вы также заметите, что большинство функциональности пространства имен Direct3DX просто не существует в XNA. Вы только можете получить доступ к некоторым методам, когда пишете собственный обработчик содержимого, но это не поможет вам при написании своего движка, или когда вы захотите проверить модели, сетки или шейдеры. Вы также не можете получить доступ к любым данным вершин или индексов загруженных моделей, потому что все буферы вершин и индексов доступны только для записи, что хорошо с точки зрения производительности, но плохо, если вы захотите что-нибудь модифицировать. В вашем небольшом фрагменте кода вы просто имитируете поведение метода mesh.Draw, только без кода эффектов, поскольку для этой цели у вас здесь используется собственный класс эффектов.
Если подробнее, это означает, что вы перебираете каждый проход (снова у вас только один) и рисуете все сетки (также только одну для вашего яблока), визуализируя все части каждой сетки (представьте себе, и здесь одну), устанавливая буферы вершин и индексов с помощью свойств класса XNA Device. Затем вы вызываете DrawIndexedPrimitives для визуализации всех вершин внутри шейдера. После этого проход и шейдер закрываются и вы наконец видите свое яблоко с текстурой marble.dds на экране (рис. 6.16).
Тестирование шейдераТеперь все работает, но это не означает, что вы не можете немного поэкспериментировать со своим шейдером и проверить другие параметры материалов, текстуры или режимы визуализации. Чтобы достичь эффекта проволочного каркаса, который вы видели раньше на рис. 6.5, просто измените значение FillMode перед запуском шейдера: Или вы можете немного поуправлять материалами шейдера; если хотите, можете загрузить другую текстуру или даже модель. Класс шейдера написан таким образом, что позволяет вам загружать любую модель XNA и текстуру и тестировать их. Простейшим способом модификации результата работы шейдера могло бы быть изменение значений фоновой, рассеиваемой и отражаемой компонент, чтобы получить злое инопланетное яблоко (рис. 6.17).
|