Giới thiệu chung

Rồng là một trong những biểu tượng mạnh mẽ và huyền bí nhất trong văn hoá Đông Á, đồng thời cũng là một trong những hình ảnh được ưa chuộng trong cộng đồng lập trình và thiết kế đồ họa, nhất là trong môi trường Processing (P5.js). Nếu bạn là người mới bắt đầu học lập trình đồ họa, hoặc đã có kinh nghiệm nhưng muốn thử sức với một dự án sáng tạo, việc vẽ rồng trong P5.js sẽ là một thử thách thú vị, giúp bạn kết hợp kiến thức về hình học, màu sắc, và thuật toán vẽ.

Bài viết này sẽ cung cấp cho bạn một hướng dẫn chi tiết, từ khởi đầu cho tới các kỹ thuật nâng cao, để bạn có thể tự tin tạo ra một con rồng sống động, đầy sức mạnh và thẩm mỹ. Chúng ta sẽ đi qua:

  1. Cài đặt môi trường P5.js và chuẩn bị công cụ.
  2. Các yếu tố cơ bản của hình rồng: đầu, thân, vây, móng, lửa và các chi tiết phụ.
  3. Lập trình các hình dạng cơ bản (đường thẳng, đường cong, ellipse, polygon) trong P5.js.
  4. Sử dụng hàm curveVertex, bezier và arc để tạo đường cong mượt mà.
  5. Kỹ thuật tạo hiệu ứng vũ khí và lửa bằng noise và perlin.
  6. Tối ưu hoá mã nguồn: tái sử dụng hàm, giảm thiểu vòng lặp, và tránh lag.
  7. Thêm animation: di chuyển, xoay, và thay đổi màu sắc theo thời gian.
  8. Xuất bản dự án lên web và chia sẻ.

Cuối cùng, chúng ta sẽ có một bản demo hoàn chỉnh, có thể chạy ngay trên trình duyệt và tùy chỉnh theo ý muốn.

1. Chuẩn bị môi trường P5.js

1.1. Tại sao chọn P5.js?

  • Dễ học: Thư viện P5.js được thiết kế cho người mới bắt đầu, cung cấp các hàm đồ họa đơn giản.
  • Mở rộng: Hỗ trợ WebGL, cho phép tạo 3D nếu muốn.
  • Cộng đồng mạnh: Nhiều tài liệu, ví dụ và diễn đàn hỗ trợ.

1.2. Cài đặt nhanh

Bạn không cần cài đặt phần mềm nào trên máy tính. Chỉ cần:

  1. Truy cập trang editor.p5js.org.
  2. Đăng nhập (hoặc dùng tài khoản Google) để lưu dự án.
  3. Tạo một sketch mới, sẽ có sẵn hai hàm setup() và draw().

Hoặc nếu muốn làm việc offline:

  • Tải p5.js từ p5js.org.
  • Tạo một file index.html và sketch.js, nhúng thư viện như sau:
<!DOCTYPE html>
<html lang="vi">
<head> <meta charset="UTF-8"> <title>Vẽ Rồng P5.js</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script> <script src="sketch.js"></script>
</head>
<body></body>
</html>

1.3. Cấu trúc file cơ bản

function setup() { createCanvas(800, 600); angleMode(DEGREES); // Đổi sang độ để dễ tính toán noLoop(); // Vẽ một lần, nếu muốn animation sẽ xóa dòng này
} function draw() { background(30, 30, 50); // Nền tối, tạo không gian huyền bí drawDragon(width/2, height/2);
}

2. Phân tích cấu trúc hình rồng

Trước khi viết code, chúng ta cần phác thảo các bộ phận chính:

Bộ phận Mô tả Cách vẽ trong P5.js
Đầu Hình oval, mắt, sừng, hàm răng ellipse, arc, triangle
Thân Đường cong xoắn ốc, gân, vảy curveVertex, bezier, beginShape
Đuôi Dây lượn, có thể dùng noise để tạo độ gợn beginShape + vertex + noise
Cánh Hai cánh lớn, hình lưỡi liềm bezier hoặc curve
Chân & móng Đầu mũi tên, hình tam giác triangle, line
Lửa / hơi thở Hạt noise, gradient strokeWeight, lerpColor

2.1. Tỷ lệ và tỉ lệ phần trăm

  • Đầu chiếm 15% chiều rộng canvas.
  • Thân dài khoảng 50% chiều cao.
  • Đuôi và cánh chiếm còn lại, tạo cảm giác cân đối.

3. Vẽ các thành phần cơ bản

3.1. Vẽ đầu rồng

function drawHead(x, y, size) { push(); translate(x, y); // Đầu chính fill(200, 80, 80); ellipse(0, 0, size 1.2, size); // Mắt fill(255); ellipse(-size 0.2, -size 0.1, size 0.3, size 0.2); fill(0); ellipse(-size 0.2, -size 0.1, size 0.1, size 0.1); // Sừng fill(180, 150, 50); triangle(-size 0.5, -size 0.6, -size 0.4, -size 1.2, -size 0.2, -size 0.6); // Răng stroke(255); strokeWeight(2); line(size 0.1, size 0.2, size 0.25, size 0.3); line(size 0.15, size 0.2, size 0.35, size 0.35); noStroke(); pop();
}

3.2. Vẽ thân bằng curveVertex

Thân rồng thường là một đường xoắn ốc hoặc sine wave để tạo cảm giác uốn lượn.

function drawBody(x, y, length, amplitude) { push(); translate(x, y); stroke(150, 0, 0); strokeWeight(15); noFill(); beginShape(); // Tạo 10 điểm control cho curve for (let i = 0; i <= 10; i++) { let t = map(i, 0, 10, 0, length); let offset = sin(i 30) amplitude; curveVertex(t, offset); } endShape(); pop();
}

3.3. Vẽ đuôi với Perlin noise

function drawTail(x, y, length) { push(); translate(x, y); stroke(180, 30, 30); strokeWeight(12); noFill(); beginShape(); for (let i = 0; i < length; i++) { let nx = i; let ny = noise(i 0.1) 30 - 15; // tạo gợn sóng vertex(nx, ny); } endShape(); pop();
}

3.4. Vẽ cánh

Cách Vẽ Rồng Lo P5
Cách Vẽ Rồng Lo P5
function drawWing(x, y, scale, direction = 1) { push(); translate(x, y); scale(scale); fill(120, 0, 0, 180); noStroke(); beginShape(); vertex(0, 0); bezierVertex(-50, -150, -150, -100, -200, 0); bezierVertex(-150, 100, -50, 150, 0, 0); endShape(CLOSE); pop();
}

3.5. Vẽ lửa (hơi thở)

function drawFire(x, y, len) { push(); translate(x, y); noStroke(); for (let i = 0; i < 20; i++) { let r = map(i, 0, 20, 0, len); let alpha = map(i, 0, 20, 255, 0); fill(255, 100, 0, alpha); ellipse(r, random(-10, 10), r 0.5, r 0.3); } pop();
}

4. Kết hợp các thành phần thành một con rồng hoàn chỉnh

function drawDragon(cx, cy) { // Tỷ lệ các bộ phận let headSize = 80; let bodyLength = 300; let bodyAmp = 30; let tailLength = 120; // Vẽ phần đầu drawHead(cx - bodyLength/2, cy - 50, headSize); // Vẽ thân drawBody(cx - bodyLength/2, cy, bodyLength, bodyAmp); // Vẽ đuôi drawTail(cx + bodyLength/2, cy, tailLength); // Vẽ cánh (trái và phải) drawWing(cx - 50, cy - 100, 0.8, -1); // trái drawWing(cx + 150, cy - 80, 0.8, 1); // phải // Vẽ lửa từ miệng drawFire(cx - bodyLength/2 + headSize0.6, cy - 20, 80);
}

Kết quả sẽ là một con rồng 2D với các bộ phận cơ bản. Bạn có thể chạy ngay trong draw().

5. Tối ưu hoá và mở rộng

5.1. Đóng gói thành lớp (class)

Việc tạo một class Dragon sẽ giúp bạn dễ dàng tạo nhiều con rồng, thay đổi vị trí, kích thước, màu sắc.

class Dragon { constructor(x, y, scale = 1, colorBase = 180, 30, 30) { this.x = x; this.y = y; this.s = scale; this.col = colorBase; } draw() { push(); translate(this.x, this.y); scale(this.s); // Vẽ các bộ phận, truyền màu fill(this.col); drawHead(0, 0, 80); drawBody(-150, 0, 300, 30); drawTail(150, 0, 120); drawWing(-100, -80, 0.8, -1); drawWing(100, -70, 0.8, 1); drawFire(0, -20, 80); pop(); }
}

Sau đó trong setup():

let dragons = ; function setup() { createCanvas(1000, 600); angleMode(DEGREES); // Tạo 3 rồng ngẫu nhiên for (let i = 0; i < 3; i++) { dragons.push(new Dragon(random(width), random(height), random(0.6, 1.2))); }
}
function draw() { background(20, 20, 40); dragons.forEach(d => d.draw());
}

5.2. Thêm animation

  • Di chuyển: Cập nhật this.x và this.y dựa trên sin(frameCount speed).
  • Xoay đầu: Dùng rotate() trước khi vẽ đầu.
  • Thay đổi màu: Sử dụng lerpColor để chuyển dần giữa các màu (đỏ → vàng).
class Dragon { // ... constructor unchanged update() { this.x += sin(frameCount 0.02) 0.5; this.y += cos(frameCount 0.015) 0.5; let c1 = color(180, 30, 30); let c2 = color(250, 150, 30); this.col = lerpColor(c1, c2, (sin(frameCount 0.01) + 1) / 2); } draw() { // như trên }
}
function draw() { background(20,20,40); dragons.forEach(d => { d.update(); d.draw(); });
}

5.3. Tối ưu vòng lặp

  • Không vẽ lại background nếu không cần animation.
  • Sử dụng requestAnimationFrame (được tích hợp trong draw() của P5) để render khi cần.
  • Đối với các đường cong phức tạp, tính toán trước và lưu vào mảng PVector.

6. Hiệu ứng ánh sáng và bóng đổ (Advanced)

Nếu muốn rồng trông ba chiều hơn, chúng ta có thể:

  1. Vẽ bóng đổ: Dùng filter(BLUR, 2) hoặc vẽ một bản sao màu đen, offset.
  2. Gradient cho da rồng: Dùng lerpColor trong vòng lặp for khi vẽ vảy.
function drawScales(x, y, rows, cols, size) { push(); translate(x, y); for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { let inter = map(i, 0, rows, 0, 1); let c = lerpColor(color(180,30,30), color(250,150,30), inter); fill(c); noStroke(); ellipse(jsize1.2, isize1.2, size, size0.6); } } pop();
}

Bạn có thể gọi drawScales phía sau thân để tạo lớp vảy.

7. Xuất bản và chia sẻ

7.1. Lưu dưới dạng file HTML

  • Click File → Export trên editor.p5js.org, sẽ nhận được một folder chứa index.html, sketch.js, và thư viện.
  • Đưa lên GitHub Pages, Netlify, hoặc Vercel để người khác xem.

7.2. Thêm tương tác

  • Mouse drag để di chuyển rồng.
  • Key press để thay đổi màu hoặc kích thước.
function mouseDragged() { dragons0.x = mouseX; dragons0.y = mouseY;
}
function keyPressed() { if (key === 'S') saveCanvas('dragon', 'png');
}

8. Tổng kết

Việc vẽ rồng trong P5.js không chỉ là một bài tập lập trình mà còn là cơ hội để khám phá:

  • Toán học hình học: đường cong, Bézier, Perlin noise.
  • Kỹ thuật đồ họa: gradient, layering, animation.
  • Sáng tạo nghệ thuật: cách kết hợp màu sắc, chi tiết để tạo ra một sinh vật huyền thoại.

Bạn đã nắm được các bước cơ bản: chuẩn bị môi trường, phân tích cấu trúc rồng, lập trình các thành phần, kết hợp chúng, tối ưu và thêm animation. Từ đây, bạn có thể:

  1. Thay đổi phong cách: rồng châu Âu, rồng Nhật, rồng cổ điển.
  2. Thêm chi tiết: móng tay kim cương, mây bốc lên khi rồng bay.
  3. Kết hợp 3D: dùng createGraphics hoặc WEBGL để tạo chiều sâu.

Hãy thử tự tay viết lại một phiên bản của riêng bạn, chia sẻ trên cộng đồng và nhận phản hồi. Khi bạn đã thành thạo, việc vẽ các sinh vật huyền thoại khác như phượng hoàng, kỳ lân sẽ trở nên dễ dàng hơn.

Chúc bạn vui vẻ và sáng tạo với P5.js! 🎨🐉

Rate this post
Mục nhập này đã được đăng trong Blog. Đánh dấu trang permalink.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *