Unity 6.3
0 онлайн 118 гостей 3 в системе
Вход
Материалы и шейдеры Шаг 237 из 442

Напишите HLSL для различных графиков APIs

Существуют различия в том, как графика рендеринга ведет себя между разными графиками APIs. Большую часть времени Unity Editor скрывает различия, но есть некоторые ситуации, когда Unity не может сделать это для вас.

Проверка обработки исключений с плавающей запятой

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

Используйте последовательную семантику

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

  • SV_POSITION вместо POSITION для позиции на выходе вершинного шейдера.
  • SV_Target вместо COLOR или COLOR0 для выхода фрагментного шейдера.
  • PSIZE, если вы отображаете меши как точки. Например, установите PSIZE на 1. Это предотвращает некоторые платформы, такие как Metal от чтения размера точки как неопределенного.

Дополнительные сведения о семантике см. в Справочник по семантике High-Level Shader Language (HLSL).

Используйте const для констант

Не используйте const для значений, которые поступают из-за пределов шейдера или которые вы рассчитываете во время выполнения, так как это работает только в HLSL, а не в OpenGL Shading Language (GLSL). Используйте const только для констант времени компиляции.

Избегайте несоответствующих расположений буферов

Если вы используете стандартный тип HLSL cbuffer или макросы Unity CBUFFERSTART и CBUFFEREND, то float3 может стать float4, или float может стать float2.

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

  • Используйте float4 и float4x4 вместо float3 и float3x3, потому что переменные float4 имеют одинаковые размеры на всех графиках APIs, в то время как переменные float3 могут иметь разные размеры на некоторых графиках APIs.
  • Заявляйте переменные в порядке уменьшения размера, например, float4, затем float2, затем float, так что все графики APIs структурируют данные одинаково.

Например:

cbuffer myConstantBuffer {
    float4x4 matWorld;
    float4 vObjectPosition; // Uses a float4 instead of a float3
    float arrayIndex;
}

Примечание: Вы не можете добавлять структуры в постоянные буферы.

Обработка обратных координатных пространств

DirectX, Metal и Vulkan используют разные координатные системы, чем другие графики APIs. Чтобы убедиться, что шейдеры работают правильно на всех платформах, настройте свой код для обработки обратных текстур.

Чтобы проверить обратные текстуры, используйте предпроцессорные условия, такие как #if и #ifdef со встроенными макросами или методами Unity.

Проверка текстур перевернутого рендеринга

Если вы взяли образец текстуры рендеринга на (0,0), DirectX, Metal и Vulkan, то возвращается текстура в левом верхнем углу. Другие графики APIs возвращают текстуру в левом нижнем углу. Unity обрабатывает это внутренне для большинства текстур рендеринга, переворачивая текстуры рендеринга внутри, где это необходимо, так что используемые координаты возвращают одни и те же текстуры на всех платформах.

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

  • Проверьте, определяет ли Unity UNITY_UV_STARTS_AT_TOP, что означает, что графика API использует (0,0) для левого верхнего угла текстуры.

    Например, чтобы проверить на наличие обратных текстур рендеринга и затем перевернуть вертикальные ультрафиолетовые координаты:

    #if UNITY_UV_STARTS_AT_TOP
        if (_MainTex_TexelSize.y < 0)
            uv.y = 1-uv.y;
    #endif
    
  • Проверьте встроенную переменную ProjectionParams.x. Если значение -1, то Unity перевернул текстуру рендеринга, так что вы должны также перевернуть вертикальные координаты UV.

Примечание: Если вы используете GrabPass во Встроенном Render Pipeline, Unity может не инвертировать текстуру. Для вычисления координат, используемых для выборки текстуры, используйте метод ComputeGrabScreenPos. Для получения дополнительной информации, см. Использование встроенных функций шейдера во Встроенном Render Pipeline.

Проверка на наличие обратного направления глубины

Направление глубины в пространстве клипа, буфер глубины и текстуры глубины различаются в зависимости от графики API, на которую вы направляетесь.

Координатное пространство координата Z в DirectX, Metal и Vulkan координата Z в OpenGL ES и WebGL
Буфер глубины и текстуры глубины 1.0 вблизи до 0.0 далеко 0.0 вблизи до 1.0 далеко
Пространство клипа 1.0 вблизи до 0.0 далеко -1.0 вблизи до 1.0 далеко

Используйте следующее в пользовательском коде HLSL для обработки этих различий:

  • Используйте SystemInfo.usesReversedZBuffer, чтобы проверить, использует ли графика API 1.0 до 0.0 для глубины.

  • Проверьте, определяет ли Unity UNITY_REVERSED_Z, что означает, что графика API использует от 1.0 до 0.0 для глубины, затем переверните значение z.

    Например, во Встроенном Render Pipeline:

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

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

Больше макросов, которые помогают с глубиной, см. в Shader методах во Встроенном Render Pipeline или Shader методах в Universal Render Pipeline (URP).

Компиляция на платформах DirectX

Если вы нацелены на DirectX графику API, компилятор более строгий, чем другие компиляторы. Проверьте следующее:

  • Установите все компоненты вектора. Например, если вы объявляете float4, убедитесь, что вы установили все четыре компонента.
  • Не используйте метод tex2D в вертикальном шейдере. Вместо этого используйте метод tex2Dlod для выборки конкретного уровня mip и используйте #pragma target 3.0 для обеспечения совместимости.
  • Если вы используете вершинный шейдер с параметром out в шейдере поверхности, инициализируйте выход с помощью макроса UNITY_INITIALIZE_OUTPUT.

Дополнительные ресурсы