2012-07-17 31 views
5

Tôi đang vẽ các màu và họa tiết phẳng vào vải WebGL. Màu sắc và kết cấu của tôi có các giá trị alpha khác nhau và tôi muốn chúng được trộn chính xác. Tôi muốn có nền trong suốt (chúng phải được pha trộn với nội dung HTML, dưới canvas).Trộn với nền HTML trong WebGL

Trong WebGL, tôi sử dụng

gl.clearColor(0, 0, 0, 0); 
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 
gl.enable(gl.BLEND); 

Nó hoạt động một cách chính xác, khi nền HTML là màu đen. Nhưng khi tôi đặt mẫu JPG làm nền, tôi vẽ hình tam giác màu đen (alpha = 1) và tam giác màu trắng (alpha = 0,5), tôi có thể thấy mẫu nền ở vị trí hình tam giác giao nhau. Hành vi này có đúng không?

Trả lời

11

Câu trả lời trước của tôi thực sự không chính xác. Điều đó kết quả mong đợi của những gì bạn mô tả.

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) nghĩa là alpha kết quả là

A_final = A_s * A_s + (1 - A_s) * A_d 

Trong ví dụ của bạn, sau khi hình tam giác màu đen (với alpha = 1) được rút ra, một điểm ảnh được vẽ trong framebuffer sẽ có một alpha của

1 * 1 + (1 - 1) * 0 == 1 + 0 == 1 

Vì vậy, nó sẽ hoàn toàn mờ đục. Tiếp theo, sau khi hình tam giác trắng (với alpha = 0,5) được rút ra, một điểm ảnh trong giao nhau của hai tam giác sẽ có một alpha của

.5 * .5 + (1 - .5) * 1 == .25 + .5 == .75 

đó có nghĩa là màu cuối cùng sẽ được coi như một phần trong suốt, và , khi nó được tổng hợp với trang, nền trang sẽ hiển thị qua.

Đây là vấn đề không phổ biến trong OpenGL thông thường, vì nội dung thường được tổng hợp dựa trên nền trống. Nó xuất hiện khi bạn vẽ một FBO và phải kết hợp các kết quả với các nội dung khác trong ngữ cảnh của bạn. Có một số cách để giải quyết vấn đề này.

Một cách là phải có sự pha trộn alpha của bạn với gl.ONE, gl.ONE_MINUS_SRC_ALPHA để bạn có được

A_final = A_s + (1 - A_s) * A_d 

đó là những gì bạn thường muốn với alpha pha trộn. Tuy nhiên, bạn muốn màu sắc của mình vẫn pha trộn với gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA. Bạn có thể sử dụng gl.blendFuncSeparate thay vì gl.blendFunc để đặt riêng chức năng trộn màu và pha trộn alpha của bạn. Trong trường hợp này, bạn sẽ gọi

gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 

Một lựa chọn khác là để tận dụng lợi thế của màu sắc với alpha premultiplied (mà WebGL actually already assumes you are using, ví dụ, khi lấy mẫu một màu từ một kết cấu). Nếu bạn vẽ hình tam giác thứ hai với alpha đã nhân bản bằng màu sắc (do đó, một nửa tam giác màu trắng trong suốt sẽ có gl_FragColor thiết lập để vec4(.5, .5, .5, .5)), sau đó bạn có thể sử dụng chế độ hòa trộn

gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) 

và nó sẽ hoạt động như bạn muốn cho cả màu và alpha.

Tùy chọn thứ hai là những gì bạn thường thấy trong các ví dụ về WebGL, vì (như đã đề cập), WebGL đã thừa nhận màu của bạn đã được xử lý trước (vì vậy, vec4(1., 1., 1., .5) không nằm ngoài âm lượng, đầu ra hiển thị không xác định và trình điều khiển/GPU có thể xuất ra bất kỳ màu nào nó muốn). Việc xem gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) trong các ví dụ OpenGL thông thường trở nên phổ biến hơn, điều này dẫn đến một số nhầm lẫn.

+0

Cảm ơn bạn rất nhiều, bạn thật tuyệt vời! :) Tôi quyết định sử dụng gl.blendFuncSeparate(). Tôi đã cố gắng sử dụng alpha được nhân trước, nhưng có vẻ kỳ lạ, bởi vì kết cấu của tôi không được cấp phép trước. Tôi sử dụng gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bd.image); ? Làm thế nào tôi có thể thay đổi nó thành premultiplied? –

+0

Theo mặc định, kết cấu không được cấp cho bạn khi được tải. Để trình duyệt tự động nhân các màu theo alpha khi nhập kết cấu, bạn cần đặt thông số kết cấu trước khi gọi texImage2D. Vì vậy, bạn sẽ gọi 'gl.pixelStorei (gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);' trước khi gọi hàm texImage2D mà bạn liệt kê ở trên. Xem thông số lưu trữ pixel lưu ý trong thông số WebGL: http://www.khronos.org/registry/webgl/specs/latest/#PIXEL_STORAGE_PARAMETERS –