This programming guide is only available in Vietnamese. Switch the language toggle to Vietnamese to read the full article.
Khi chúng ta di chuyển tự do xung quanh một thế giới game 3D, có vẻ như một chiếc "camera ảo" đang chuyển động và quan sát mọi góc độ của môi trường. Tuy nhiên, sự thật bên dưới phần cứng GPU hoàn toàn ngược lại. WebGL không hề có khái niệm Camera vật lý. Toàn bộ hiệu ứng camera được tạo ra nhờ View Matrix (Ma trận góc nhìn) để di chuyển và định hướng toàn bộ thế giới 3D ngược lại so với vị trí camera ảo.
1. Bản chất toán học của View Matrix
Hãy tưởng tượng bạn muốn di chuyển camera sang phải một khoảng là `x`. Điều này hoàn toàn tương đương với việc bạn giữ nguyên camera tại tâm gốc tọa độ (0,0,0) và kéo toàn bộ thế giới xung quanh dịch chuyển sang trái một khoảng tương đương `-x`.
Do đó, nếu mô tả Camera có vị trí và góc quay đại diện bởi ma trận biến đổi `C` (Camera Transformation Matrix), thì ma trận View Matrix (`V`) dùng để biến đổi không gian thế giới về không gian camera chính là ma trận đảo ngược của nó:
V = C-1
2. Thuật toán ma trận LookAt
Để tạo ra một View Matrix một cách trực quan, chúng ta thường sử dụng hàm LookAt. Thuật toán này xây dựng một hệ tọa độ trực chuẩn (Orthogonal Basis) mới cho camera dựa trên 3 thông số đầu vào:
eye: Vị trí của Camera trong thế giới 3D.target: Điểm tiêu điểm mà Camera đang hướng ống kính về.up: Hướng chỉ lên trời của thế giới (thường là vector(0, 1, 0)).
Quy trình tính toán 3 vector định hướng trực giao cho camera:
-
Tính toán vector hướng nhìn Z (Forward Vector - hướng ra xa camera trong WebGL):
zAxis = normalize(eye - target)
-
Tính toán vector ngang X (Right Vector - vuông góc với Up và Forward):
xAxis = normalize(cross(up, zAxis))
-
Tính toán vector dọc Y thực sự (Up Vector của camera):
yAxis = cross(zAxis, xAxis)
Ma trận LookAt cuối cùng là tích của ma trận xoay hệ trục và ma trận tịnh tiến về vị trí eye:
LookAt = [ xAxis.x xAxis.y xAxis.z -dot(xAxis, eye) ]
[ yAxis.x yAxis.y yAxis.z -dot(yAxis, eye) ]
[ zAxis.x zAxis.y zAxis.z -dot(zAxis, eye) ]
[ 0 0 0 1 ]
3. Lập trình xoay quanh mục tiêu (Orbit Camera)
Để camera có thể xoay mượt mà quanh một vật thể trung tâm (giống như Orbit Controls trong Three.js), chúng ta biểu diễn vị trí `eye` của camera bằng hệ tọa độ cầu (Spherical Coordinates) với bán kính `R` (khoảng cách), góc phương vị `theta` (xoay ngang) và góc cực `phi` (xoay dọc):
eyeX = target.x + radius * Math.sin(theta) * Math.cos(phi);
eyeY = target.y + radius * Math.sin(phi);
eyeZ = target.z + radius * Math.cos(theta) * Math.cos(phi);
4. Câu hỏi trắc nghiệm ôn tập
Trắc nghiệm 1: Phép tính cơ sở chéo (Cross Product) trong LookAt
Tại sao ta phải tính xAxis = cross(up, zAxis) trước rồi mới tính yAxis = cross(zAxis, xAxis)?
Trắc nghiệm 2: Di chuyển Camera
Nếu Camera được tịnh tiến tiến lên 5 đơn vị theo trục Z, giá trị tịnh tiến của thế giới trong View Matrix sẽ là bao nhiêu?
Trắc nghiệm 3: Vai trò của vector "up" trong LookAt
Trong hàm LookAt(eye, target, up), vector up có vai trò gì đối với hệ trục tọa độ của camera?
Mã nguồn đầy đủ thuật toán LookAt và Orbit Controls:
Tải về mã nguồn Camera setup
Comments
Bình luận