Thiết Kế Giao Diện Cho Dữ Liệu Cảnh Trong Động Cơ 3D
Thiết kế giao diện dữ liệu cảnh trong động cơ 3D
Đây là lần đầu tiên tôi trực tiếp thiết kế một động cơ 3D, dù đồng nghiệp phụ trách phần lớn mã 3D đã có kinh nghiệm. Dự án kéo dài hơn hai năm, về mặt định hướng thiết kế chính tôi là người quyết định. Tuy nhiên do thiếu kinh nghiệm, chúng tôi liên tục phải điều chỉnh lại.
Vào cuối tuần này, khi xem lại các thiết kế cũ, tôi nhận thấy cần tinh chỉnh lại một số giao diện. Ví dụ như giao diện điều khiển sprite, giao diện điều khiển camera, giao diện mô tả cảnh… Từ góc độ lập trình viên game, tôi mong muốn giao diện phải như thế nào?
Tôi hy vọng có thể dễ dàng mô tả mối quan hệ giữa các đối tượng trong thế giới ảo, đồng thời động cơ sẽ che giấu các chi tiết phức tạp như kiến thức toán học 3D, thuật ngữ chuyên môn, phép chuyển đổi tọa độ phức tạp… Bài viết này không nhằm đưa ra kết luận cuối cùng, mà chỉ ghi lại quá trình suy nghĩ.
Tôi muốn hiểu rõ: Đối với các nhà phát triển sử dụng động cơ 3D, cách mô tả cảnh ảo như thế nào là phù hợp nhất? Giao diện cần được thiết kế ra sao?
Trong game của chúng tôi (cũng như đa số game khác), tọa độ nhân vật trong cảnh thường là 2D chứ không phải 3D. Giống như khi mô tả vị trí trên Trái Đất, thông thường kinh độ và vĩ độ là đủ. Chỉ khi ở môi trường phức tạp (ví dụ trong tòa nhà cao tầng) mới cần thêm chiều cao so với mặt đất.
Chúng tôi sử dụng chiều cao tính từ mặt đất, không phải từ tâm Trái Đất. Vì vậy bạn đứng ở Nam Cực gần mặt đất hơn so với xích đạo, hay đứng ở Lhasa cao hơn Thượng Hải… là những yếu tố không cần quan tâm.
Chiều cao không yêu cầu độ chính xác cao như kinh-vĩ độ. Khi cần thông tin độ cao, ví dụ trong tòa nhà, chỉ cần biết đang ở tầng nào. Ở khu vực sông nước, chỉ cần xác định vị trí trên cầu hay dưới cầu. Vì đa số trường hợp, nhân vật luôn tiếp xúc mặt đất.
Cuối cùng, tôi mong muốn khi động cơ 3D tải xong dữ liệu cảnh, nhà phát triển chỉ cần thiết lập kinh độ và vĩ độ là có thể đặt vật thể tại vị trí đó. Mặc định, vật thể luôn bám sát mặt đất. Nếu muốn vật thể lơ lửng, chỉ cần thêm thuộc tính chiều cao - giá trị này biểu thị độ cao so với mặt đất tại tọa độ tương ứng.
Vấn đề phát sinh khi cùng một tọa độ có nhiều tầng mặt đất? Giải pháp là phân tầng không gian. Ví dụ: Con sông có bờ hai bên, mặt nước và cây cầu sẽ được chia thành ba tầng riêng biệt.
Bờ sông và đáy sông thuộc tầng 1, mặt nước là tầng 2, mặt cầu là tầng 3.
Khi sông cạn, tầng mặt nước biến mất, chỉ còn hai tầng. (Trong mô hình hóa, bờ và đáy thường được thiết kế liền nhau, mặt nước là lớp bổ sung).
Khi nhân vật lên cầu, họ chuyển từ tầng thấp sang tầng cao hơn - vị trí chuyển giao này cần được đánh dấu đặc biệt. Tương tự, khi xuống nước cũng là quá trình chuyển tầng, đồng thời kích hoạt sự kiện bơi lội. Lặn xuống mặt nước cũng tuân theo cơ chế tương tự.
Theo nhu cầu logic, động cơ cần cung cấp cơ chế chuyển đổi chiều cao giữa các tầng. Ví dụ chiều cao của mặt cầu có thể được tính tương ứng với khoảng cách từ mặt nước.
Vậy vật thể trên không xử lý thế nào? Giải pháp là thiết lập “tầng 0” - một mặt phẳng ngang trong không gian Euclid (nếu làm game dạng cầu, tầng này có thể là mặt cầu). Vật thể lơ lửng sẽ lấy mặt phẳng này làm chuẩn để tính toán tọa độ.
Động cơ còn cần cung cấp vector pháp tuyến tại mỗi điểm trên tầng, hoặc chênh lệch độ cao giữa hai điểm khác nhau (giá trị này có thể tính từ phương pháp trên). Một ứng dụng quan trọng là đặt vị trí động vật bốn chân.
Không phải mọi điểm trên tầng đều có pháp tuyến hợp lệ. Ví dụ với cây cầu, không gian ngoài phạm vi mặt cầu trong tầng đó là “vùng vô hiệu”. Nếu yêu cầu vật thể di chuyển đến vùng này, hệ thống cần phát hiện và xử lý - vật thể sẽ rơi xuống tầng dưới hoặc bị chặn lại. Thông tin này cũng giúp mô tả vật cản.
Trong thực tế, chúng ta hiếm khi cần tọa độ chính xác. Giống như đời sống, trừ khi cầm máy GPS, chúng ta thường nói “gần siêu thị” chứ không nói “tọa độ 12.3456, 78.9012”. Vì vậy việc xác định tọa độ chính xác là công việc của editor, logic game chỉ cần biết vật thể ở “địa điểm nào”.
Giá trị tọa độ chủ yếu dùng trong tính toán chuyển động, tồn tại ở tầng giao diện thấp. Khi đã trừu tượng hóa, chúng ta không cần quan tâm tọa độ là 2D hay 3D, trạng thái vật thể biểu diễn bằng vector, ma trận hay quaternion… Những chi tiết này sẽ được động cơ che giấu, khiến nhà phát triển không phân biệt được đây là động cơ 3D, 2D hay 2.5D.
Mục tiêu cuối cùng là mô tả mối quan hệ giữa các vật thể thông qua giao diện động cơ, thay vì vị trí tuyệt đối trong không gian. Những giao diện nào cần được thiết kế để phục vụ lập trình viên? Điều này vẫn cần tiếp tục nghiên cứu và cân nhắc kỹ lưỡng.