2011-11-07 30 views
5

Image of shader resultGLSL Gif Dither Tác dụng: Tối ưu hóa

Tôi đã có một Shader đoạn mà chủ yếu đọc alpha màu sắc và chuyển nó thành một hiệu ứng phối màu trên các pixel.

Tuy nhiên, đó là bộ xử lý khá chuyên sâu với tất cả các mod và nếu câu lệnh. Có ai có bất kỳ đề xuất nào về tối ưu hóa mã bên dưới không?

varying vec2 the_uv; 
varying vec4 color; 

void main() 
{ 
    // The pixel color will correspond 
    // to the uv coords of the texture 
    // for the given vertice, retrieved 
    // by the Vertex shader through varying vec2 the_uv 

    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); 
    vec4 tex = texture2D(_MainTex, the_uv); 
    tex = tex * color ; 
    float r = tex.a; 

    if (r > 0.1) { 
     if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.5) { 
     if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.7) { 
     if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.9) { 
     if ((mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.3) { 
     if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 
} 

Dưới đây là giải pháp dựa trên những phản hồi:

 varying vec2 the_uv; 
     varying vec4 color; 

     void main() 
     { 
      color = gl_Color; 
      gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
      the_uv = gl_MultiTexCoord0.st; 
     } 
     #endif 

     #ifdef FRAGMENT 
     uniform sampler2D _MainTex; 
     uniform sampler2D _GridTex; 
     varying vec2 the_uv; 
     varying vec4 color; 

     void main() 
     { 
      if (texture2D(_MainTex, the_uv).a * color.a > texture2D(_GridTex, vec2(gl_FragCoord.x, gl_FragCoord.y)*.25).a) gl_FragColor = color; 
      else gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); 

     } 
+0

Bạn có tên rất chung chung cho các biến của mình. Nó sẽ là một _lot_ dễ dàng hơn để tìm ra thuật toán của bạn là gì nếu bạn sử dụng nhiều tên biểu cảm hơn. –

Trả lời

6

Điều bạn đang cố gắng làm là chọn xem mỗi pixel có được chiếu sáng trên lưới 4x4 dựa trên nguồn alpha hay không. Cách đơn giản nhất để làm điều đó là làm điều đó.

Đầu tiên khởi tạo một kết cấu 4x4 với các bản alpha tương ứng được yêu cầu để có đèo pixel (tôi chọn 1.0 là alpha cho không bao giờ thể hiện ở đây)

1.0 0.5 1.0 0.1 
1.0 1.0 0.9 1.0 
1.0 0.3 1.0 0.7 
1.0 1.0 1.0 1.0 

Cài đặt kết cấu này với lặp lại để tránh các mod hoàn toàn và bộ lọc gần nhất để tránh lọc tuyến tính.

Sau đó, sử dụng mẫu lấy kết cấu đó để quyết định có sáng pixel hay không.

vec4 dither = texture2D(_my4x4, gl_FragCoord/4.); // 4 is the size of the texture 
if (r > dither) { gl_FragColor = color; } 

Điều này giả định rằng r không bao giờ 1. Có những cách đơn giản để giải quyết vấn đề đó, ví dụ: chia các giá trị trong kết cấu 4x4 cho 2, ngoại trừ 1.0, và sau đó nhân dither bằng 2 trước khi kiểm tra nếu, nhưng sau khi tìm nạp.

Một số tối ưu hóa tiềm năng hơn nữa:

  • bạn có thể tránh được nếu thử nghiệm hoàn toàn bằng cách sử dụng một kết cấu với so sánh (texture shadow).
  • bạn có thể tránh/4 bằng cách sử dụng các hướng dẫn textureFetch
+0

cảm ơn bạn! các trình đổ bóng cuối cùng của tôi trông giống như: – miketucker

-1

Trước hết, màu sắc mảnh của bạn sẽ giống nhau không phụ thuộc vào kết quả của câu lệnh if từ màu được đặt ở bắt đầu.

Thứ hai, chỉ sử dụng các câu lệnh nếu không có cách nào khác nếu mã của bạn chạy qua từng phép tính bất kể là gì.

Một cách tốt hơn để làm điều này sẽ có:

if (r > 0.9) { 
    if ((mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.7) { 
    if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.5) { 
    if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.3) { 
    if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.1) { 
    if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else{ 
    gl_FragColor = color; 
} 

Tất nhiên điều này sẽ không giúp bạn thay đổi sản lượng từ màu sắc là không bao giờ thay đổi (như tôi đã đề cập trước đó). Nhưng điều này sẽ làm cho mọi thứ chạy nhanh hơn một chút.

Một điều khác cần lưu ý là những trường hợp nào được thực hiện thường xuyên nhất. Tôi giả định rằng các trường hợp với r lớn là phổ biến hơn, do đó thứ tự của các câu lệnh if. Nếu r nhỏ là phổ biến hơn, sau đó đảo ngược thứ tự và có r < 0,1, r < 0,3, r < 0,5, r < 0,7, r < 0,9 sẽ có ý nghĩa hơn.

Toàn bộ vấn đề ở đây là làm cho việc thoát mã càng nhanh càng tốt (nghĩa là có một trong những sự trở lại đúng). Khi một trong các if trả về true, phần còn lại sẽ bị bỏ qua, giúp bạn tránh được việc tính toán tất cả các hoạt động còn lại của mod.

+3

"Đầu tiên, màu sắc của bạn sẽ giống nhau bất kể kết quả của câu lệnh if vì màu được đặt ở đầu." Đo không phải sự thật. Bạn có thể thiết lập kết quả đầu ra giai đoạn đổ bóng nhiều lần; chỉ cái cuối cùng được lấy. Bạn thậm chí có thể thực hiện các thay đổi tại chỗ cho họ. –

+0

Xin lỗi nếu tôi không rõ ràng. Những gì tôi có nghĩa là kể từ khi màu sắc được giao bên ngoài nếu vòng, kết quả của mỗi cá nhân nếu vòng lặp sẽ được như nhau bất kể đó là đúng (r> 0,9 cho cùng một màu frag như r> 0,1). (Trừ khi có một cái gì đó hoàn toàn sai với sự hiểu biết của tôi về cách làm việc shaders). – NickLH

+0

Nhưng chúng chỉ thiết lập màu đó nếu chúng có điều kiện 'mod' bổ sung. Nếu không, họ chỉ sử dụng màu mặc định là 0. Không chỉ là 'r> X'. –