Giới thiệu về Bộ lọc tuỳ chỉnh (còn gọi là Chương trình đổ bóng CSS)

Bộ lọc tuỳ chỉnh (trước đây gọi là chương trình đổ bóng CSS) cho phép bạn sử dụng sức mạnh của chương trình đổ bóng WebGL với nội dung DOM. Vì trong quá trình triển khai hiện tại, các chương trình đổ bóng được sử dụng gần như giống với các chương trình đổ bóng trong WebGL, nên bạn cần lùi lại một bước và tìm hiểu một số thuật ngữ 3D cũng như một chút về quy trình đồ hoạ.

Tôi đã thêm một phiên bản ghi lại của bản trình bày mà tôi đã cung cấp gần đây cho LondonJS. Trong video này, tôi sẽ trình bày tổng quan về các thuật ngữ 3D mà bạn cần hiểu, các loại biến khác nhau mà bạn sẽ gặp và cách bắt đầu sử dụng Bộ lọc tuỳ chỉnh ngay hôm nay. Bạn cũng nên tải các trang trình bày để có thể tự chơi với các bản minh hoạ.

Giới thiệu về chương trình đổ bóng

Trước đây, tôi đã viết một bài giới thiệu về chương trình đổ bóng. Bài viết này sẽ cung cấp cho bạn thông tin chi tiết về chương trình đổ bóng và cách sử dụng chương trình đổ bóng từ quan điểm WebGL. Nếu bạn chưa từng xử lý chương trình đổ bóng, thì đây là một phần cần đọc trước khi bạn đi sâu hơn, vì nhiều khái niệm và ngôn ngữ của Bộ lọc tuỳ chỉnh phụ thuộc vào thuật ngữ chương trình đổ bóng WebGL hiện có.

Vậy nên, hãy bật Bộ lọc tuỳ chỉnh và tiếp tục!

Bật bộ lọc tuỳ chỉnh

Bộ lọc tuỳ chỉnh có trong cả Chrome và Canary cũng như Chrome dành cho Android. Bạn chỉ cần chuyển đến about:flags rồi tìm "CSS Shaders" (Bóng đổ CSS), bật các tính năng này rồi khởi động lại trình duyệt. Giờ thì bạn đã sẵn sàng!

Cú pháp

Bộ lọc tuỳ chỉnh mở rộng tập hợp bộ lọc mà bạn có thể áp dụng, chẳng hạn như blur hoặc sepia, cho các phần tử DOM. Eric Bidelman đã viết một công cụ sân chơi tuyệt vời cho những người đó, bạn nên xem qua.

Để áp dụng Bộ lọc tuỳ chỉnh cho một phần tử DOM, bạn sử dụng cú pháp sau:

.customShader {
    -webkit-filter:

    custom(
        url(vertexshader.vert)
        mix(url(fragment.frag) normal source-atop),

    /* Row, columns - the vertices are made automatically */
    4 5,

    /* We set uniforms; we can't set attributes */
    time 0)
}

Bạn sẽ thấy từ đây chúng ta khai báo chương trình đổ bóng đỉnh và mảnh, số hàng và cột mà chúng ta muốn phần tử DOM được chia thành, sau đó là mọi chương trình đổ bóng đồng nhất mà chúng ta muốn truyền qua.

Điều cuối cùng cần lưu ý ở đây là chúng ta sử dụng hàm mix() xung quanh chương trình đổ bóng mảnh với chế độ kết hợp (normal) và chế độ kết hợp (source-atop). Hãy xem xét chính chương trình đổ bóng mảnh để biết lý do chúng ta cần hàm mix().

Đẩy pixel

Nếu đã quen thuộc với chương trình đổ bóng của WebGL, bạn sẽ nhận thấy rằng trong Bộ lọc tuỳ chỉnh, mọi thứ sẽ hơi khác một chút. Một lý do là chúng ta không tạo(các) hoạ tiết mà chương trình đổ bóng mảnh sử dụng để lấp đầy các pixel. Thay vào đó, nội dung DOM đã áp dụng bộ lọc sẽ tự động được liên kết với một hoạ tiết, điều này có nghĩa là hai điều:

  1. Vì lý do bảo mật, chúng tôi không thể truy vấn các giá trị màu pixel riêng lẻ của kết cấu DOM
  2. Chúng ta không tự đặt màu pixel cuối cùng (ít nhất là trong cách triển khai hiện tại), tức là gl_FragColor bị giới hạn. Thay vào đó, giả định rằng bạn sẽ muốn hiển thị nội dung DOM và việc bạn cần làm là thao tác gián tiếp các pixel của nội dung đó thông qua css_ColorMatrixcss_MixColor.

Điều đó có nghĩa là chương trình Hello World của chương trình đổ bóng phân mảnh sẽ có dạng như sau:

void main() {
    css_ColorMatrix = mat4(1.0, 0.0, 0.0, 0.0,
                            0.0, 1.0, 0.0, 0.0,
                            0.0, 0.0, 1.0, 0.0,
                            0.0, 0.0, 0.0, 1.0);

    css_MixColor = vec4(0.0, 0.0, 0.0, 0.0);

    // umm, where did gl_FragColor go?
}

Mỗi pixel của nội dung DOM được nhân với css_ColorMatrix. Trong trường hợp trên, css_ColorMatrix không làm gì cả vì đó là matrice nhận dạng và không thay đổi giá trị RGBA nào. Nếu muốn chỉ giữ lại các giá trị màu đỏ, chúng ta sẽ sử dụng css_ColorMatrix như sau:

// keep only red and alpha
css_ColorMatrix = mat4(1.0, 0.0, 0.0, 0.0,
                        0.0, 0.0, 0.0, 0.0,
                        0.0, 0.0, 0.0, 0.0,
                        0.0, 0.0, 0.0, 1.0);

Bạn có thể thấy rằng khi nhân các giá trị pixel 4D (RGBA) với ma trận, bạn sẽ nhận được một giá trị pixel đã được xử lý ở phía bên kia, và trong trường hợp này, giá trị này sẽ đặt các thành phần màu xanh lục và xanh lam về 0.

css_MixColor chủ yếu được dùng làm màu cơ sở mà bạn muốn kết hợp với nội dung DOM. Quá trình kết hợp được thực hiện thông qua các chế độ kết hợp mà bạn sẽ quen thuộc với các gói nghệ thuật: lớp phủ, màn hình, tránh màu, ánh sáng cứng, v.v.

Có nhiều cách để hai biến này có thể thao tác các pixel. Bạn nên xem thông số kỹ thuật về Hiệu ứng bộ lọc để hiểu rõ hơn về cách chế độ kết hợp và chế độ kết hợp tương tác với nhau.

Tạo đỉnh

Trong WebGL, chúng ta chịu toàn bộ trách nhiệm tạo các điểm 3D của lưới, nhưng trong Bộ lọc tuỳ chỉnh, tất cả những gì bạn cần làm là chỉ định số hàng và cột mà bạn muốn, sau đó trình duyệt sẽ tự động chia nội dung DOM thành một nhóm các tam giác:

Tạo đỉnh
Hình ảnh được chia thành các hàng và cột

Sau đó, mỗi đỉnh trong số đó sẽ được truyền đến chương trình đổ bóng đỉnh để thao tác. Điều đó có nghĩa là chúng ta có thể bắt đầu di chuyển các đỉnh đó trong không gian 3D khi cần. Chẳng bao lâu nữa, bạn có thể tạo ra một số hiệu ứng tuyệt đẹp!

Hiệu ứng đàn xếp
Hình ảnh bị biến dạng do hiệu ứng đàn accordion

Tạo ảnh động bằng chương trình đổ bóng

Việc đưa ảnh động vào chương trình đổ bóng sẽ giúp chương trình này trở nên thú vị và hấp dẫn. Để làm việc đó, bạn chỉ cần sử dụng hiệu ứng chuyển đổi (hoặc ảnh động) trong CSS để cập nhật các giá trị đồng nhất:

.shader {
    /* transition on the filter property */
    -webkit-transition: -webkit-filter 2500ms ease-out;

    -webkit-filter: custom(
    url(vshader.vert)
    mix(url(fshader.frag) normal source-atop),
    1 1,
    time 0);
}

    .shader:hover {
    -webkit-filter: custom(
    url(vshader.vert)
    mix(url(fshader.frag) normal source-atop),
    1 1,
    time 1);
}

Vì vậy, điều cần lưu ý trong mã trên là thời gian sẽ giảm từ 0 xuống 1 trong quá trình chuyển đổi. Bên trong chương trình đổ bóng, chúng ta có thể khai báo time đồng nhất và sử dụng bất kỳ giá trị hiện tại nào của chương trình đó:

    uniform float time;

uniform mat4 u_projectionMatrix;
attribute vec4 a_position;

void main() {
    // copy a_position to position - attributes are read only!
    vec4 position = a_position;

    // use our time uniform from the CSS declaration
    position.x += time;

    gl_Position = u_projectionMatrix * position;
}

Chơi ngay!

Bộ lọc tuỳ chỉnh rất thú vị để sử dụng và bạn sẽ khó (và trong một số trường hợp là không thể) tạo ra những hiệu ứng tuyệt vời nếu không có bộ lọc này. Chúng tôi vẫn đang trong giai đoạn đầu phát triển và mọi thứ đang thay đổi khá nhiều. Tuy nhiên, việc thêm các tính năng này sẽ giúp dự án của bạn thêm phần thú vị. Vậy tại sao bạn không thử?

Tài nguyên khác