GlslCanvas là một thư viện JavaScript nhẹ, giúp tích hợp nhanh chóng các shader GLSL (đặc biệt là fragment shader) vào trang web thông qua WebGL — mà không cần viết mã WebGL thuần. Với cú pháp khai báo đơn giản qua thuộc tính HTML và API dễ hiểu, bạn có thể tạo hiệu ứng đồ họa động, xử lý ảnh thời gian thực hoặc mô phỏng toán học trực quan chỉ trong vài dòng code.
Cách bắt đầu nhanh
Thay vì clone và build từ source, bạn có thể sử dụng phiên bản đã được biên dịch sẵn qua CDN:
<script src="https://cdn.jsdelivr.net/npm/glsl-canvas@2.1.0/dist/GlslCanvas.min.js"></script>
Ví dụ cơ bản: Gradient động theo thời gian
Tạo một file index.html với nội dung sau:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Shader cơ bản</title></head>
<body style="margin:0;overflow:hidden;">
<canvas
id="shaderCanvas"
width="640"
height="480"
data-fragment="
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.x, u_resolution.y);
float t = u_time * 0.3;
vec3 color = 0.5 + 0.5 * cos(t + uv.xyx + vec3(0,2,4));
gl_FragColor = vec4(color, 1.0);
}
">
</canvas>
<script>
const canvas = document.getElementById('shaderCanvas');
const renderer = new GlslCanvas(canvas);
</script>
</body>
</html>
Khi mở file này trong trình duyệt, bạn sẽ thấy một gradient xoay vòng mượt mà — toàn bộ hiệu ứng được tính toán bởi GPU thông qua shader GLSL.
Tích hợp hình ảnh làm texture
Để truyền ảnh vào shader, sử dụng thuộc tính data-textures với đường dẫn tương đối hoặc URL tuyệt đối:
<canvas
id="textureCanvas"
width="640"
height="480"
data-textures="https://picsum.photos/512/512"
data-fragment="
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform sampler2D u_tex0;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
vec4 tex = texture2D(u_tex0, uv);
gl_FragColor = vec4(tex.rgb * 0.7 + 0.3 * uv.xyy, 1.0);
}
">
</canvas>
Lưu ý: Hình ảnh phải tuân thủ chính sách CORS nếu tải từ domain khác. Với mục đích phát triển cục bộ, bạn nên chạy server đơn giản (ví dụ: npx serve) thay vì mở file trực tiếp bằng file://.
Các biến uniform tích hợp
GlslCanvas tự động cung cấp các biến toàn cục tiện lợi cho shader:
u_time: Thời gian trôi qua tính bằng giây kể từ khi khởi tạo canvas.u_resolution: Độ phân giải hiện tại của canvas (vec2).u_mouse: Vị trí chuột trong hệ tọa độ chuẩn hóa[0,1]×[0,1].u_tex0,u_tex1, …: Các bộ lọc texture tương ứng với danh sách đường dẫn trongdata-textures.
Bạn cũng có thể thiết lập giá trị tùy chỉnh từ JavaScript:
renderer.setUniform('u_speed', 2.5); // gửi số thực
renderer.setUniform('u_color', [0.1, 0.9, 0.4]); // gửi mảng 3 phần tử
renderer.setUniform('u_transform', [1,0,0, 0,1,0, 0,0,1]); // gửi ma trận 3x3
Tải shader từ file ngoài
Với shader phức tạp, nên tách riêng thành file .frag:
<!-- shader.frag -->
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
float d = sin(uv.x * 10.0 + u_time) * cos(uv.y * 8.0);
gl_FragColor = vec4(vec3(d * 0.5 + 0.5), 1.0);
}
Sau đó tải bằng phương thức load():
const canvas = document.getElementById('externalShader');
const app = new GlslCanvas(canvas);
app.load('shader.frag');
Một số lưu ý thực tiễn
- Luôn kiểm tra console trình duyệt để phát hiện lỗi biên dịch shader (GLSL syntax error).
- Tránh dùng
pow(x, y)vớix < 0— dễ gây NaN trên GPU. - Giới hạn số lượng texture: hầu hết thiết bị hỗ trợ tối đa 8–16 texture đồng thời.
- Đối với hiệu ứng tương tác cao, kết hợp
u_mousevới hàmsmoothstep()để làm mượt chuyển động.