2016-09-07 6 views
6

Я пытаюсь повторить автоматический билинейной алгоритм фильтрации в Unity3D используя следующий код:Что это за техника, если не билинейная фильтрация?

fixed4 GetBilinearFilteredColor(float2 texcoord) 
{ 
    fixed4 s1 = SampleSpriteTexture(texcoord + float2(0.0, _MainTex_TexelSize.y)); 
    fixed4 s2 = SampleSpriteTexture(texcoord + float2(_MainTex_TexelSize.x, 0.0)); 
    fixed4 s3 = SampleSpriteTexture(texcoord + float2(_MainTex_TexelSize.x, _MainTex_TexelSize.y)); 
    fixed4 s4 = SampleSpriteTexture(texcoord); 

    float2 TexturePosition = float2(texcoord)* _MainTex_TexelSize.z; 

    float fu = frac(TexturePosition.x); 
    float fv = frac(TexturePosition.y); 

    float4 tmp1 = lerp(s4, s2, fu); 
    float4 tmp2 = lerp(s1, s3, fu); 

    return lerp(tmp1, tmp2, fv); 
} 

fixed4 frag(v2f IN) : SV_Target 
{ 
    fixed4 c = GetBilinearFilteredColor(IN.texcoord) * IN.color; 
    c.rgb *= c.a; 
    return c; 
} 

Я думал, что с помощью правильного АЛГОРИТМ, потому что это только один я видел там для билинейной. Но я попробовал его, используя единство с той же текстурой дублируется:

  • 1º текстуры: находится в фильтрации точек, и с использованием пользовательских билинейной шейдер (maded из спрайтов шейдера по умолчанию).
  • 2º текстуры: в билинейной фильтр с спрайтов по умолчанию шейдер на

И это результат:

enter image description here

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

Любая идея о том, что я делаю неправильно? Любая идея о том, что делает Unity3D другим? Есть ли еще один алгоритм, который подходит для фильтрации Unity3D по умолчанию?

Решение

Обновленные с полным решением коды с кодом Нико для других людей, которые ищут для него здесь:

fixed4 GetBilinearFilteredColor(float2 texcoord) 
{ 
    fixed4 s1 = SampleSpriteTexture(texcoord + float2(0.0, _MainTex_TexelSize.y)); 
    fixed4 s2 = SampleSpriteTexture(texcoord + float2(_MainTex_TexelSize.x, 0.0)); 
    fixed4 s3 = SampleSpriteTexture(texcoord + float2(_MainTex_TexelSize.x, _MainTex_TexelSize.y)); 
    fixed4 s4 = SampleSpriteTexture(texcoord); 

    float2 TexturePosition = float2(texcoord)* _MainTex_TexelSize.z; 

    float fu = frac(TexturePosition.x); 
    float fv = frac(TexturePosition.y); 

    float4 tmp1 = lerp(s4, s2, fu); 
    float4 tmp2 = lerp(s1, s3, fu); 

    return lerp(tmp1, tmp2, fv); 
} 

fixed4 frag(v2f IN) : SV_Target 
{ 
    fixed4 c = GetBilinearFilteredColor(IN.texcoord - 0.498 * _MainTex_TexelSize.xy) * IN.color; 
    c.rgb *= c.a; 
    return c; 
} 

И тест изображения с результатом:

enter image description here

Почему бы не вычесть 0,5 точно?

Если вы протестируете его, вы увидите некоторые кромки, где он скачет (пиксель - 1).

ответ

6

Давайте подробнее рассмотрим, что вы на самом деле делаете. Я буду придерживаться 1D-случая, потому что его легче визуализировать.

У вас есть массив пикселей и положение текстуры. Я предполагаю, что _MainTex_TexelSize.z настроен таким образом, что он дает пиксельные координаты. Это то, что вы получаете (коробки представляют собой пиксели, число в коробках число пикселей и число ниже на пиксель пространственных координат):

Pixels

С вашей выборкой (предполагается, что ближайшие выборки точек), вы получите Разрешение- и 3. Однако вы видите, что интерполяционная координата для lerp фактически неверна. Вы пройдете дробную часть положения текстуры (то есть 0.8), но она должна быть 0.3 (= 0.8 - 0.5). Обоснование этого довольно просто: если вы приземлитесь в центре пикселя, вы хотите использовать значение пикселя. Если вы приземлитесь посередине между двумя пикселями, вы хотите использовать среднее значение обоих значений пикселей (то есть значение интерполяции 0.5). Прямо сейчас у вас в основном смещение на половину пикселя влево.

При решении первой проблемы, есть второй один:

Pixels

В этом случае, вы на самом деле хотите, чтобы смешаться между пикселем 1 и 2. Но так как вы всегда идти вправо в ваша выборка, вы будете смешивать между 2 и 3. Опять же, с неправильным значением интерполяции.

Решение должно быть довольно просто: Вычесть половину ширины пикселя от координаты текстуры, прежде чем делать что-либо с ним, что, вероятно, только следующее (при условии, что ваши переменные содержат вещи, которые я думаю):

fixed4 c = GetBilinearFilteredColor(IN.texcoord - 0.5 * _MainTex_TexelSize.xy) * IN.color; 

Другая причина, по которой результаты могут быть разными, может заключаться в том, что Unity фактически использует другой фильтр, например бикубический (но я не знаю). Кроме того, использование mipmaps может повлиять на результат.

 Смежные вопросы

  • Нет связанных вопросов^_^