Перспективное правильное наложение текстур в iOS Metal

Я пробовал различные способы интерполяции и создания изображения с правильной перспективой, но ни один из предложенных способов не работает.

Мой текущий код:

struct VertexStruct
{
  float4 normalizedPosition [[ position ]];
  float4 texCoord;
}

vertex VertexStruct testVertex(device float4 *vertices [[ buffer(0) ]],
                                     uint vid [[ vertex_id ]])
{
  VertexStruct outVertices;

  outVertices.normalizedPosition = ...;

  outVertices.texCoord = float4(vertices[vid].x, vertices[vid].y, 0.0, 127.0);

  return outVertices;
}

fragment half4 testFragment(VertexStruct inFrag [[ stage_in ]],
                            texture2d<half, access::sample> volume [[ texture(0) ]])
{
  float2 texCoord = float2(inFrag.texCoord.xy * (1.0 / inFrag.texCoord.w));
  constexpr sampler s(coord::normalized, filter::linear, address::clamp_to_zero);
  return volume.sample(s, texCoord);
}

Текстура 128x128 и вершины:

  • 0,0
  • 0,127
  • 127,0
  • 127,127

Теоретически 4-й параметр, w, должен помочь с правильной интерполяцией перспективы. Сообщается, что этот трюк работает в OpenGL ES, но в моем случае, есть он у меня или нет, ничего не меняется.

Что я получаю:

введите здесь описание изображения

Синий — это чистый цвет, а все, что находится внутри черной трапеции, — это содержимое текстуры. Красная трапеция должна находиться в центре черной трапеции. Если вы откроете его в Photoshop и проведете диагональ черной трапеции, она точно пройдет диагональ красной трапеции.

введите здесь описание изображения

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

Кто-нибудь может увидеть ошибку?


person aledalgrande    schedule 09.10.2015    source источник


Ответы (1)


Наложение текстуры с корректной перспективой было нормой более десяти лет и используется по умолчанию всеми графическими API, особенно Metal. Вам не нужно ничего делать, чтобы получить правильные результаты с точки зрения перспективы, при условии, что вы не делаете ничего совершенно неправильного в настройках.

На самом деле Metal позволяет указать как интерполяцию, так и выборку прямо в MSL. По умолчанию везде используется квалификатор center_perspective (центр пикселя, правильная интерполяция перспективы, за очевидным исключением положения, которое равно center_no_perspective.

Учитывая, что данные, поступающие от растеризатора в вашу функцию фрагмента, имеют значение stage_in, вы просто добавляете желаемый квалификатор выборки/интерполяции, как и любой другой атрибут, после объявления элементов непосредственно в вашем коде MSL. Пример явной подробной спецификации:

struct Fragment {

    float4 position             [[ center_no_perspective ]];    // Default, can be omitted.
    float4 specialTreatment     [[ centroid_perspective ]];     // Let's say you need centroid + perspective correct.
    float2 textureCoordinates   [[ center_perspective ]];       // Default, can be omitted.

};

Что касается других ваших вариантов, то это в основном комбинации центр/центроид/выборка и перспектива/без_перспективы, а также flat (без интерполяции, очевидно, для целых чисел). В списке это выглядит так:

  • [[ flat ]] Без интерполяции, целые члены.
  • [[ center_perspective ]] По центру, правильная перспектива (по умолчанию)
  • [[ center_no_perspective ]] По центру, линейно (позиция по умолчанию)
  • [[ centroid_perspective ]] Центроид, правильная перспектива
  • [[ centroid_no_perspective ]] Центроид, линейный
  • [[ sample_perspective ]] Образец, правильная перспектива*
  • [[ sample_no_perspective ]] Образец, линейный*

Предупреждение: квалификаторы sample_* заставят функцию фрагмента выполняться для каждого сэмпла, а не для обычного фрагмента. Переход на субпиксели — это потенциальный красный флаг производительности, поэтому используйте его при необходимости.

person Elim Garak    schedule 16.10.2015
comment
Привет @elim garak, я отмечу твой ответ как правильный, потому что, если мы говорим о наложении текстур, это действительно правильно. Я обнаружил, что если я спроецирую свои вершины на плоскость в вершинном шейдере, а затем попытаюсь сэмплировать текстуру во фрагментном шейдере (который называется корректной интерполяцией перспективы), вам понадобится специальная гомография. правильно читать текстуру. Если бы я вместо этого рассчитал координаты NDC для точек и предоставил работу графическому процессору, все прошло бы хорошо. - person aledalgrande; 16.10.2015
comment
Да, в этом случае вам понадобится индивидуальная работа. Но всегда лучше максимально использовать базовый конвейер, если это возможно. Удачи! - person Elim Garak; 16.10.2015