Мои Уведомления
Привет, !
Мой Аккаунт Мои Финансы Мои Подписки Мои Настройки Выход
Руководство API скрипты

Написание шейдеров для разных графических API

В некоторых случаях существуют различия в способах рендерингаграфики на экране (или в рендеринге). текстура). По умолчанию основная камера в Unity отображает изображение на экране. Подробнее
См. в разделе Словарь
между различными графическими API. В большинстве случаев Редактор Unity скрывает различия, но бывают ситуации, когда Редактор не может сделать это за вас. Эти ситуации и действия, которые необходимо предпринять в случае их возникновения, перечислены ниже.

Координаты текстуры рендеринга

Соглашения о координатах вертикальной текстуры различаются для двух типов платформ: Direct3D-подобных и OpenGL-подобных.

  • Как в Direct3D: координата равна 0 вверху и увеличивается вниз. Это относится к Direct3D, Metal и консолям.
  • Подобно OpenGL: координата равна 0 внизу и увеличивается вверх. Это относится к OpenGL и OpenGL ES.

Эта разница, как правило, не оказывает никакого влияния на ваш проект, кроме как при рендеринге в Render Texture Особый тип текстуры, который создается и обновляется во время выполнения. Чтобы использовать их, сначала создайте новую текстуру рендеринга и назначьте одну из ваших камер для рендеринга в нее. Затем вы можете использовать Render Texture в материале, как обычную текстуру. Подробнее
См. в Словарь
. При рендеринге в текстуру на платформе, подобной Direct3D, Unity внутренне переворачивает рендеринг с ног на голову. Это позволяет согласовать соглашения между платформами, при этом соглашение о платформе, подобное OpenGL, является стандартом.

Эффекты изображения и рендеринг в UV-пространстве — два распространенных случая в шейдерахпрограмме, работающей на графическом процессоре. Подробнее
См. в Словарь
, где необходимо принять меры, чтобы убедиться, что различные соглашения о координатах не создавайте проблем в своем проекте.

Эффекты изображения

При использовании эффектов изображения и сглаживания результат Исходная текстура для эффекта изображения не переворачивается, чтобы соответствовать соглашению платформы, подобной OpenGL. В этом случае Unity выполняет рендеринг на экране для сглаживания, а затем преобразует рендеринг в текстуру рендеринга для дальнейшей обработки с помощью эффекта изображения.

Если у вас простой эффект изображения, который одновременно обрабатывает одну текстуру рендеринга, Graphics.Blit обрабатывает несовместимые координаты. Однако, если вы обрабатываете более одной текстуры рендеринга вместе в своих Эффект изображения, текстуры рендеринга, скорее всего, будут иметь разную вертикальную ориентацию на платформах, подобных Direct3D, и при использовании сглаживания. Чтобы стандартизировать координаты, вам нужно вручную «перевернуть» Текстуру экрана вверх дном в вашей Вершинном шейдереПрограмме, которая запускается на каждом вершина 3D-модели во время рендеринга модели. Подробнее
См. в Словарь
, чтобы он соответствовал стандарту координат OpenGL.

В следующем примере кода показано, как это сделать:

// Flip sampling of the Texture: // The main Texture // texel size will have negative Y). #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) uv.y = 1-uv.y; #endif

Обратитесь к Сцене обнаружения границСцена содержит окружение и меню вашей игры. Думайте о каждом уникальном файле сцены как об уникальном уровне. В каждой сцене вы размещаете свое окружение, препятствия и декорации, по сути проектируя и создавая свою игру по частям. Подробнее
См. в Словарь
в примере проекта замены шейдеров Unity (см. ресурсы Unity Learn) для более подробного примера. Обнаружение краев в этом проекте использует как Текстуру экрана, так и КамеруКомпонент, который создает изображение определенной точки обзора в вашей сцене. Вывод либо рисуется на экране, либо фиксируется в виде текстуры. Подробнее
См. в Словарь
Глубина +Текстура нормалей.

Аналогичная ситуация возникает с GrabPass. Результирующая Текстура рендеринга может фактически не быть перевернутой вверх дном на Direct3D-подобных (не OpenGL-подобных) платформах. Если в коде шейдера используются образцы текстур GrabPass, используйте функцию ComputeGrabScreenPos из включаемого файла UnityCG.

Визуализация в UV-пространстве

При рендеринге в пространстве текстурных координат (UV) для специальных эффектов или инструментов вам может потребоваться настроить шейдеры, чтобы рендеринг был согласован между системами, подобными Direct3D, и системами, подобными OpenGL. Вам также может понадобиться настроить рендеринг между рендерингом на экране и рендерингом в текстуру. Отрегулируйте их, перевернув проекцию, подобную Direct3D, вверх ногами, чтобы ее координаты совпадали с координатами проекции, подобной OpenGL.

В встроенная переменная ProjectionParams.x содержит +1 или значение –1. -1 указывает, что проекция была перевернута вверх дном, чтобы соответствовать координатам проекции, подобным OpenGL, а +1 указывает, что это не так. был перевернут. Вы можете проверить это значение в своих шейдерах, а затем выполнять различные действия. В приведенном ниже примере проверяется, была ли перевернута проекция, и если да, то она переворачивается, а затем возвращает соответствующие координаты UV.

float4 vert(float2 uv : TEXCOORD0) : SV_POSITION { float4 pos; pos.xy = uv; // This example is rendering with upside-down flipped projection, // so flip the vertical UV coordinate too if (_ProjectionParams.x < 0) pos.y = 1 - pos.y; pos.z = 0; pos.w = 1; return pos; }

Обрезать пространственные координаты

Подобно координатам текстуры, координаты пространства отсечения (также известные как координаты пространства после проекции) различаются между платформами, подобными Direct3D, и платформами, подобными OpenGL:

  • Похоже на Direct3D: глубина пространства отсечения увеличивается с +1,0 в ближней плоскости до 0,0 в дальней плоскости. Это относится к Direct3D, Metal и консолям.

  • Похоже на OpenGL: глубина пространства отсечения изменяется от –1,0 в ближней плоскости до +1,0 в дальней плоскости. Это относится к OpenGL и OpenGL ES.

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

Внутри кода скрипта используйте GL.GetGPUProjectionMatrix для преобразования системы координат Unity (которая соответствует соглашениям OpenGL) в координаты Direct3D, если это то, что ожидает платформа.

Точность вычислений шейдера

Чтобы избежать проблем с точностью, убедитесь, что вы тестируете свои шейдеры на целевых платформах. Графические процессоры в мобильных устройствах и ПК различаются тем, как они обрабатывают типы с плавающей запятой. Графические процессоры ПК обрабатывают все типы с плавающей запятой (с плавающей запятой, половинной и фиксированной) как одинаковые — они выполняют все вычисления с полной 32-битной точностью, в то время как графические процессоры многих мобильных устройств этого не делают.

Подробности см. в документации по типам данных и точности.

Объявления констант в шейдерах

Использование const отличается в Microsoft HSL (см. msdn.microsoft.com). ) и язык шейдеров OpenGL GLSL (см. Википедию).

  • Майкрософт HLSL const имеет почти то же значение, что и в C# и C++, в том смысле, что объявленная переменная доступна только для чтения в своей области, но может быть инициализирована в в любом случае.

  • Константа GLSL OpenGL const означает, что переменная фактически является константой времени компиляции, и поэтому она должна быть инициализирована с ограничениями времени компиляции (либо литеральными значениями, либо вычислениями на других consts).

Лучше следовать семантике GLSL OpenGL и объявлять переменную как const только тогда, когда она действительно неизменна. Избегайте инициализации переменной const какой-либо другой mutableВы можете изменить содержимое изменяемый пакет. Это противоположность неизменному. Изменяемыми являются только локальные пакеты и встроенные пакеты.
Просмотреть в значениях Словарь
(например, в качестве локальной переменной в функции) . Это также работает в Microsoft HLSL, поэтому использование const позволяет избежать ошибок на некоторых платформах.

Семантика, используемая шейдерами

Чтобы шейдеры работали на всех платформах, некоторые значения шейдеров должны использовать следующую семантику:

  • Позиция вывода вершинного шейдера (вырезка пространства): SV_POSITION. Иногда шейдеры используют семантику POSITION, чтобы заставить шейдеры работать на всех платформах. Обратите внимание, что это не работает на Sony PS4 или с тесселяцией.

  • Цвет вывода фрагментного шейдера: SV_Target. Иногда шейдеры используют COLOR или COLOR0, чтобы шейдеры работали на всех платформах. Обратите внимание, что это не работает на Sony PS4.

При рендеринге сеток в виде точек выводите семантику PSIZE из вершинного шейдера (например, установите для нее значение 1). Некоторые платформы, такие как OpenGL ES или Metal, рассматривают размер в точках как «неопределенный», если он не записывается из шейдера.

Дополнительные сведения см. в документации по семантике шейдеров.

Синтаксис компилятора Direct3D Shader

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

Самые распространенные ситуации, в которых вы можете столкнуться с этим, следующие:

void vert (inout appdata_full v, out Input o) { **UNITY_INITIALIZE_OUTPUT(Input,o);** // ... }
  • Частично инициализированные значения. Например, функция возвращает float4, но код устанавливает только его значения .xyz. Задайте все значения или измените значение на float3, если вам нужны только три значения.

  • Использование tex2D в вершинном шейдере. Это неверно, потому что в вершинном шейдере не существует производных UV. Вместо этого вам нужно сэмплировать явный мип-уровень; например, используйте tex2Dlod (tex, float4(uv,0,0)). Вам также необходимо добавить #pragma target 3.0, так как tex2Dlod — это функция Shader model 3.0.

Синтаксис DirectX 11 (DX11) HLSL в шейдерах

Некоторые части конвейера компиляции Surface Shader не понимают синтаксис HLSL (язык шейдеров Microsoft) для DirectX 11.

Если вы используете функции HLSL, такие как StructuredBuffers, RWTextures и другой синтаксис, отличный от DirectX 9, оберните их в Макрос препроцессора только для DirectX X11, как показано в примере ниже.

#ifdef SHADER_API_D3D11 // DirectX11-specific code, for example StructuredBuffer myColors; RWTexture2D myRandomWriteTexture; #endif

Использование выборки кадрового буфера шейдера

Некоторые графические процессоры (в первую очередь на основе PowerVR на iOS) позволяют вам выполнять форму программируемого смешивания, предоставляя текущий цвет фрагмента в качестве входных данных для шейдера фрагментов (см. EXT_shader_framebuffer_fetch на khronos.org).

В Unity можно писать шейдеры, использующие функцию выборки кадрового буфера. Для этого используйте аргумент цвета inout при написании фрагментного шейдера на любом HLSL (язык шейдеров Microsoft — см. msdn.microsoft.com) или Cg (язык затенения от Nvidia - см. nvidia.co.uk).

Пример ниже представлен в Cg.

CGPROGRAM // only compile Shader for platforms that can potentially // do it (currently gles,gles3,metal) #pragma only_renderers framebufferfetch void frag (v2f i, inout half4 ocol : SV_Target) { // ocol can be read (current framebuffer color) // and written into (will change color to that one) // ... } ENDCG

Направление глубины (Z) в шейдерах

Направление глубины (Z) различается на разных платформах шейдеров.

DirectX 11, DirectX 12, PS4, Xbox One, металл: обратное направление

  • Буфер глубины (Z) равен 1,0 в ближней плоскости и уменьшается до 0,0 в дальней плоскости.

  • Диапазон пространства отсечения: [near,0] (означает расстояние ближней плоскости в ближней плоскости, уменьшающееся до 0,0 в дальней плоскости).

Другие платформы: традиционное направление

  • Значение буфера глубины (Z) равно 0,0 в ближней плоскости и 1,0 в дальней плоскости.

  • Пространство клипа зависит от конкретной платформы:
    • На платформах, подобных Direct3D, диапазон составляет [0,far] (означает 0,0 в ближней плоскости, увеличивающееся до расстояния в дальней плоскости в дальней плоскости).
    • На платформах, подобных OpenGL, диапазон составляет [-near,far] (что означает минус расстояние ближней плоскости на ближней плоскости, увеличивающееся до расстояния дальней плоскости на дальней плоскости).

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

Итак, когда вы используете шейдеры с платформ с обратной глубиной (Z):

  • Определено значение UNITY_REVERSED_Z.
  • _CameraDepth Диапазон текстуры текстуры: от 1 (ближний) до 0 (дальний).
  • Диапазон интервала клипа находится в диапазоне от «near» (близко) до 0 (далеко).

Однако следующие макросы и функции автоматически обрабатывают любые различия в направлениях глубины (Z):

  • Linear01Depth(float z)
  • LinearEyeDepth(float z)
  • UNITY_CALC_FOG_FACTOR(координата)

Извлечение буфера глубины

Если вы извлекаете значение буфера глубины (Z) вручную, вам может потребоваться проверить направление буфера. Ниже приведен пример этого:

float z = tex2D(_CameraDepthTexture, uv); #if defined(UNITY_REVERSED_Z) z = 1.0f - z; #endif

Использование пространства клипа

Если вы используете глубину отсечения (Z) вручную, вы также можете абстрагироваться от различий между платформами с помощью следующего макроса:

плавающий clipSpaceRange01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(rawClipSpace);

Примечание. Этот макрос не изменяет пространство клипа на платформах OpenGL или OpenGL ES, поэтому на этих платформах он возвращается в диапазоне от «-near»1 (ближний) до далекого (дальний).

Матрицы прогнозов

GL.GetGPUProjectionMatrix() возвращает z-обратную матрицу, если вы работаете на платформе с обратной глубиной (Z). Однако, если вы компонуете из проекционных матриц вручную (например, для пользовательских теней или рендеринга глубины), вам необходимо самостоятельно изменить направление глубины (Z) там, где оно применяется, с помощью скрипта.

Пример этого ниже:

var shadowProjection = Matrix4x4.Ortho(...); //shadow camera projection matrix var shadowViewMat = ... //shadow camera view matrix var shadowSpaceMatrix = ... //from clip to shadowMap texture space //'m_shadowCamera.projectionMatrix' is implicitly reversed //when the engine calculates device projection matrix from the camera projection m_shadowCamera.projectionMatrix = shadowProjection; //'shadowProjection' is manually flipped before being concatenated to 'm_shadowMatrix' //because it is seen as any other matrix to a Shader. if(SystemInfo.usesReversedZBuffer) { shadowProjection[2, 0] = -shadowProjection[2, 0]; shadowProjection[2, 1] = -shadowProjection[2, 1]; shadowProjection[2, 2] = -shadowProjection[2, 2]; shadowProjection[2, 3] = -shadowProjection[2, 3]; } m_shadowMatrix = shadowSpaceMatrix * shadowProjection * shadowViewMat;

Смещение глубины (Z)

Unity автоматически обрабатывает смещение глубины (Z), чтобы убедиться, что оно соответствует направлению глубины (Z) Unity. Однако, если вы используете собственный плагин рендеринга кода, вам необходимо отменить (обратить) смещение глубины (Z) в вашем коде C или C++.

Инструменты для проверки направления глубины (Z)

  • Используйте SystemInfo.usesReversedZBuffer, чтобы узнать, используете ли вы платформу с обратной глубиной (Z).
Вы можете отблагодарить автора, за перевод документации на русский язык. ₽ Спасибо
Руководство Unity 2021.3