2016-09-07 22 views
6

Tôi đang cố gắng để nhân rộng các thuật toán lọc Bilinear tự động Unity3D sử dụng mã tiếp theo:Kỹ thuật này là gì, nếu không lọc bilinear?

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; 
} 

tôi nghĩ rằng tôi đã sử dụng các thuật toán đúng vì là người duy nhất tôi đã thấy trên mạng cho Bilinear. Nhưng tôi đã thử nó bằng cách sử dụng tính thống nhất với cùng một kết cấu trùng lặp:

  • 1º kết cấu: đang ở chế độ lọc Điểm và sử dụng tùy chỉnh tôt bóng mờ (maded từ trình tạo bóng ma mặc định).
  • 2º kết cấu: là Bilinear bộ lọc với ma mặc định shader

Và đây là kết quả:

enter image description here

Bạn có thể thấy rằng họ là khác nhau và cũng có một số chuyển trong shader tùy chỉnh của tôi mà làm cho sprite là off-center khi xoay trong trục Z.

Bất kỳ ý tưởng nào về những gì tôi đang làm sai? Bất kỳ ý tưởng về những gì đang làm Unity3D khác nhau? Có thuật toán nào khác phù hợp với tính năng lọc mặc định Unity3D không?

Giải pháp

cập nhật với các giải pháp mã hoàn chỉnh với mã Nico cho người khác, những người tìm kiếm nó ở đây:

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; 
} 

Và thử nghiệm hình ảnh với kết quả:

enter image description here

Tại sao không trừ 0,5 chính xác?

Nếu bạn kiểm tra nó, bạn sẽ thấy một số trường hợp cạnh mà nó nhảy tới (pixel - 1).

Trả lời

6

Hãy xem xét kỹ hơn những gì bạn đang thực sự làm. Tôi sẽ dính vào trường hợp 1D vì nó dễ hình dung hơn.

Bạn có một mảng pixel và vị trí kết cấu. Tôi giả sử, _MainTex_TexelSize.z được đặt theo cách, sao cho nó cung cấp tọa độ pixel. Đây là những gì bạn nhận được (các ô đại diện cho pixel, số trong hộp số pixel và số dưới đây tọa độ không gian pixel):

Pixels

Với lấy mẫu của bạn (giả sử lấy mẫu điểm gần nhất), bạn sẽ nhận được điểm ảnh 2 và 3. Tuy nhiên, bạn thấy rằng tọa độ nội suy cho lerp thực sự là sai. Bạn sẽ vượt qua phần phân đoạn của vị trí kết cấu (ví dụ: 0.8) nhưng phải là 0.3 (= 0.8 - 0.5). Lý do đằng sau điều này khá đơn giản: Nếu bạn hạ cánh ở giữa pixel, bạn muốn sử dụng giá trị pixel. Nếu bạn hạ cánh ở giữa hai pixel, bạn muốn sử dụng giá trị trung bình của cả hai giá trị pixel (nghĩa là giá trị nội suy là 0.5). Ngay bây giờ, bạn về cơ bản đã được bù đắp bằng một nửa pixel ở bên trái.

Khi bạn giải quyết vấn đề đầu tiên, có một thứ hai:

Pixels

Trong trường hợp này, bạn thực sự muốn pha trộn giữa điểm ảnh 1 và 2. Tuy nhiên, bởi vì bạn luôn đi bên phải trong lấy mẫu của bạn, bạn sẽ pha trộn giữa 2 và 3. Một lần nữa, với một giá trị nội suy sai.

Các giải pháp nên được khá đơn giản: một nửa Subtract của pixel chiều rộng từ kết cấu phối hợp trước khi làm bất cứ điều gì với nó, mà có lẽ chỉ sau (giả định rằng các biến của bạn giữ những điều tôi nghĩ):

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

Một lý do khác khiến kết quả khác nhau có thể là Unity thực sự sử dụng một bộ lọc khác, ví dụ: bicubic (nhưng tôi không biết). Ngoài ra, việc sử dụng mipmaps có thể ảnh hưởng đến kết quả.

Các vấn đề liên quan