В некоторых случаях существуют различия в способах рендерингаграфики на экране (или в рендеринге). текстура). По умолчанию основная камера в 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
означает, что переменная фактически является константой времени компиляции, и поэтому она должна быть инициализирована с ограничениями времени компиляции (либо литеральными значениями, либо вычислениями на другихconst
s).
Лучше следовать семантике 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 строже, чем другие компиляторы, относится к различным незаметным ошибкам шейдеров. Например, он не принимает выходные значения функции, которые не инициализированы должным образом.
Самые распространенные ситуации, в которых вы можете столкнуться с этим, следующие:
- Шейдер поверхностиУпрощенный способ написания шейдеров для встроенного -в конвейере рендеринга. Подробнее
См. в Словарь спараметр out
. Инициализируйте вывод следующим образом:
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).