KHÁI QUÁT VỀ ĐỒ HỌA BA CHIỀU VÀ BÀI TOÁN TẠO BÓNG
Khái quát về đồ họa 3 chiều
Trong thế giới thực, hầu hết các đối tượng đều có dạng 3 chiều, trong khi thiết bị hiển thị chỉ cho phép hình ảnh 2 chiều Do đó, để tạo ra hình ảnh 3 chiều, chúng ta cần thực hiện quá trình giả lập.
Chiến lược cơ bản là chuyển đổi từng bước Hình ảnh sẽ được hình thành từ từ, ngày càng chi tiết hơn
Trong mô hình 3D, các đối tượng được xác định bằng tọa độ thế giới, bao gồm cả vị trí và hướng của camera ảo Người dùng cần xác định vùng nhìn, tức là không gian hiển thị trên màn hình, để tạo ra trải nghiệm hình ảnh chính xác và sống động.
Việc chuyển từ các tọa độ thế giới sang tọa độ màn hình đƣợc thực hiện theo
Bước đầu tiên trong quá trình thiết lập camera ảo là thực hiện một phép biến đổi để đưa nó về vị trí và hướng tiêu chuẩn Lúc này, điểm nhìn (eyepoint) sẽ được đặt tại gốc tọa độ, với hướng nhìn trùng với hướng âm của trục Z Trục X sẽ chỉ về phía bên phải, trong khi trục Y chỉ lên phía trên màn hình Hệ tọa độ mới này được gọi là Hệ tọa độ Mắt (Eye Coordinate System) Phép biến đổi từ tọa độ thế giới sang tọa độ mắt là một phép biến đổi affine, được biết đến với tên gọi là phép biến đổi hiển thị (Viewing Transformation).
Cả tọa độ thế giới và tọa độ mắt đều đƣợc biểu diễn bởi tọa độ đồng nhất (Homogeneous Coordinates) với w=1
Bước thứ 2 là chuyển tọa độ mắt sang tọa độ của thiết bị chuẩn hóa (Normalized Device Coordinates), nhằm đặt vùng không gian mà chúng ta muốn quan sát trong một khối lập phương tiêu chuẩn.
Các điểm ở gần điểm nhìn (điểm đặt camera) hơn sẽ có thành phần z nhỏ hơn
Phép biến đổi cổng nhìn (Viewport Transformation) là bước cuối cùng trong quá trình chuyển đổi tọa độ, kết hợp giữa phép co giãn tuyến tính và phép tịnh tiến Quá trình này chuyển đổi tọa độ thiết bị chuẩn hóa 1x1 sang tọa độ Pixel của màn hình cho thành phần x và y Đồng thời, thành phần z được chuyển đổi sang đoạn [0,1] và được sử dụng làm giá trị chiều sâu trong thuật toán Z-Buffer, giúp xác định mặt nào sẽ được hiển thị.
Bước thứ 2 bao gồm 3 bước con :
Phép chiếu từ vùng nhìn sang khối lập phương tiêu chuẩn với tọa độ đồng nhất 1 x 1, 1 y 1, 1 z 1 có thể được thực hiện bằng hai phương pháp: chiếu trực giao và chiếu đối xứng Trong chiếu trực giao, vùng nhìn sẽ tạo thành một ống song song 3D, trong khi chiếu đối xứng sẽ tạo ra một hình tháp cụt với đỉnh là gốc tọa độ Hệ tọa độ đồng nhất sau phép chiếu được gọi là hệ tọa độ cắt (Clipping Coordinate System) Đối với phép chiếu trực giao, đây là một phép biến đổi affine, trong khi chiếu phối cảnh không phải là một phép biến đổi affine do giá trị của w thay đổi.
Trong bước tiếp theo, các vùng không gian hiển thị ngoài khối nhìn tiêu chuẩn sẽ bị cắt bỏ Những đa giác và đường thẳng nằm trong hoặc một phần trong khối nhìn này sẽ được điều chỉnh để chỉ giữ lại phần nằm trong khối nhìn tiêu chuẩn mới Phần còn lại sẽ không cần quan tâm nhiều nữa.
Sau khi cắt gọt, các tọa độ đồng nhất sẽ được chuyển đổi sang tọa độ thiết bị bằng cách chia x, y, z cho w Nếu w nhận giá trị đúng qua phép chiếu, phép chia này sẽ tạo ra các động phối cảnh mong muốn trên màn hình Do đó, phép chia này được gọi là phép chia phối cảnh (Perspective Division).
Hình 1.1: Tổng quan về hiển thị 3D và các phép chiếu
1.1.1.2 Phép biến đổi hiển thị (Viewing Transformation)
Phép biến đổi hiển thị tạo ra một camera ảo tùy chỉnh, với điểm nhìn trùng với gốc tọa độ và hướng nhìn dọc theo chiều âm của trục Z Sau khi thực hiện phép biến đổi, trục Y sẽ hướng lên phía trên màn hình, trong khi trục X sẽ chỉ về phía bên phải.
Để xác định vị trí của camera ảo một cách thuận tiện, cần có điểm nhìn E, một điểm tham chiếu R trong khung nhìn, cùng với một hướng V chỉ lên phía trên màn hình.
● Một phép tịnh tiến sẽ đƣa điểm nhìn E về gốc tọa độ Ma trận biến đổi tương ứng sẽ là M t ( E) Kết quả sẽ như sau:
Một phép quay sẽ chuyển hướng nhìn về trục Z, khiến vectơ V quay vào mặt phẳng YZ Vectơ V chỉ có thể quay trùng với trục Y nếu nó vuông góc với hướng nhìn Đầu tiên, chúng ta cần xây dựng tập hợp các véc tơ chuẩn tắc phù hợp trong tọa độ thế giới.
R n E Ngược với hướng nhìn Z ( Oz ) n V n u V Chỉ về phía phải, vuông góc với n X u n v Chỉ lên giống V , nhƣng vuống góc với n và u Y
Nhƣ vậy ma trận của phép quay sẽ là: M r ( u , v , n )
Và do đó ma trận của phép biến đổi sẽ là:
Trong đó u, v và v đƣợc tính từ E, R và V
1.1.1.3 Phép chiếu trực giao (Orthographic Projection)
Trong phép chiếu trực giao, vùng không gian hiển thị được hình thành như một ống song song trong hệ tọa độ mắt, với các mặt song song với hệ tọa độ này Kích thước và vị trí của vùng hiển thị được xác định bởi các tọa độ xleft, xright, ybottom, ytop, zfront và zback Cửa sổ hiển thị, xác định bởi (xleft, ybottom) và (xright, ytop), phải được chuyển đổi về dạng hình vuông [-1, +1]^2 Các mặt phẳng cắt trước và sau được định nghĩa bởi zfront và zback, và tọa độ của các điểm trong không gian cần thỏa mãn điều kiện zback > z > zfront Giá trị chiều sâu của các điểm phải nằm trong khoảng [-1, +1], với các điểm gần mắt hơn có giá trị chiều sâu nhỏ hơn.
Hình 1.2 : Vùng không gian hiển thị của phép chiếu trực giao
Phép chiếu trực giao thu đƣợc bằng cách thực hiện các phép biến đổi sau theo thứ tự:
● Phép tịnh tiến M t ( M) sẽ đƣa tâm của vùng không gian hiển thị về gốc tọa độ của hệ tọa độ mắt
● Một phép co giãn để đưa kích thước của vùng hiển thị về 2 đơn vị mỗi chiều
● Một phép đối xứng qua mặt XY để các điểm nằm gần hơn sẽ nhận giá trị z nhỏ hơn
Phép co giãn và phép đối xứng ở trên có thể thu đƣợc chỉ bằng một phép biển đổi đơn: M s (S) với:
Nhƣ vậy ma trận của phép chiếu trực giao sẽ là:
Phép chiếu trực giao không làm thay đổi thành phần z, vì đây là một phép biến đổi affine Phép chiếu này được áp dụng trong các lĩnh vực cần đến mối quan hệ hình học, như tỉ số khoảng cách, đặc biệt trong thiết kế hỗ trợ máy tính (CAD).
1.1.1.4 Phép chiếu phối cảnh (Perspective Projection)
Phép chiếu phối cảnh trong thế giới 3D mô phỏng gần gũi với cách mà con người quan sát bằng một mắt Tất cả các điểm trên một đường thẳng đi qua điểm nhìn sẽ được ánh xạ vào cùng một điểm trên màn hình 2D, xác định bởi tọa độ thiết bị chuẩn hóa x và y Khi hai điểm được ánh xạ vào cùng một điểm trên màn hình, thuật toán Z-buffer sẽ được sử dụng để xác định điểm nào sẽ được hiển thị bằng cách so sánh chiều sâu của chúng Để thực hiện điều này, chúng ta cần định nghĩa một thành phần tọa độ z, là hàm tăng đơn điệu của khoảng cách từ điểm đến mặt phẳng mắt XY Khoảng cách từ một điểm trong không gian đến mặt phẳng XY được tính toán đơn giản hơn, giúp xác định các mặt sẽ được hiển thị.
Phép chiếu trực giao chuyển đổi một điểm trong hệ tọa độ mắt (x,y,z,1) thành một điểm trong hệ tọa độ cắt (x’,y’,z’,w’) Sau đó, các tọa độ của thiết bị chuẩn hóa (affine) (x”,y”,z”) được tính bằng cách chia x’, y’, z’ cho w’ thông qua phép chia phối cảnh.
Với phép chiếu phối cảnh, vùng không gian hiển thị là một hình tháp cụt với đầu mút là gốc tọa độ
Hình 1.3: Vùng không gian hiển thị của phép chiếu phối cảnh cân xứng (Symmetrical Perspective Projection)
1.1.1.5 Phép biến đổi cổng nhìn (Viewport Transformation)
Phép biến đổi cổng nhìn chỉ gồm một phép tịnh tiến và một phép thay đổi tỉ lệ để:
● Tọa độ thiết bị chuẩn hóa (x, y) với 1 x 1 , 1 y 1 đƣợc chuyển qua tọa độ pixel
● Thành phần z với 1 z 1 đƣợc co lại trong đoạn 0 z w 1
KỸ THUẬT TẠO BÓNG CỨNG BẰNG PHƯƠNG PHÁP SHADOW
Tạo bóng khối bằng thuật toán Z-Pass
Để xác định số mặt trước và mặt sau mà một điểm cắt qua, chúng ta sử dụng một bộ đếm cho từng điểm cần kiểm tra Bộ đếm này sẽ tăng lên 1 khi điểm đi qua mặt trước và giảm đi 1 khi đi qua mặt sau của bóng khối Nếu bộ đếm có giá trị bằng 0, điểm đó không nằm trong vùng bóng Ngược lại, nếu giá trị lớn hơn 0, điểm đó nằm trong vùng bóng và sẽ không được vẽ ra.
Stencil Buffer cung cấp cho mỗi pixel trên màn hình một "bộ đếm" mà chúng ta có thể điều chỉnh khi pixel được ghi vào Frame Buffer Nhờ vào bộ đếm này, chúng ta có thể kiểm tra và quyết định xem pixel đó có được hiển thị trên màn hình hay không.
Khi đã tạo lưới các đa giác bao ngoài bóng khối, bước tiếp theo là vẽ bóng của vật thể cùng với chính nó Để thực hiện điều này, cần xác định xem một pixel có nằm trong vùng bóng khối hay không Thuật toán để xác định điều này khá đơn giản: nối điểm cần kiểm tra với điểm đặt camera Nếu số mặt trước và số mặt sau mà đường nối cắt bằng nhau, điểm đó không nằm trong vùng bóng khối Ngược lại, nếu số mặt trước cắt nhiều hơn số mặt sau, điểm đó nằm trong vùng bóng khối.
Thuật toán sẽ đƣợc mô tả bằng mã giả nhƣ sau:
Procedure IN_SHADOW_TEST // Z-pass
For {tất cả các vật thể cần đổ bóng} do
- Xây dựng danh sách các cạnh viền
- Tính toán các tứ giác bao quanh bóng khối dựa trên các cạnh viền và từ vị trí của nguồn sáng
For {Tất cả các mặt trước của bóng khối nhìn từ vị trí của điểm nhìn} do if Depth test passes then
- Tăng giá trị Stencil Buffer
For {Tất cả các mặt sau của bóng khối nhìn từ vị trí của điểm nhìn} do if Depth test passes then
- Giảm giá trị Stencil Buffer
Các bước thực hiện như sau:
Xóa hết trong Z-buffer và Stencil-Buffer, Chắc chắn rằng Chế độ ghi vào Z- buffer và chế độ Stencil test đƣợc bật
- Tạo ảnh của toàn bộ khung cảnh (bao gồm vật thể và các mặt hứng bóng) với Ambient Light để cho Z-buffer đƣợc cập nhật
- Tắt chế độ ghi vào Z-buffer
- Vẽ ra các mặt trước của bóng khối, Nếu chúng thực sự được vẽ ra
(Có nghĩa là Depth Pass) thì tăng giá trị Stencil Buffer
- Vẽ các mặt sau của bóng khối, Nếu chúng thực sự đƣợc vẽ ra.(Có nghĩa là Depth Pass) thì giảm giá trị Stencil Buffer
- Bật chế độ Stencil test (chỉ những điểm có giá trị Stencil = 0 mới đƣợc vẽ ra màn hình), Xóa Z-buffer, bật chế độ ghi vào Z-buffer, bật nguồn sáng
- Vẽ ra toàn bộ khung cảnh những điểm có giá trị trong stencil Buffer là 0.
Tạo bóng bằng thuật toán Z-Fail
Thuật toán Z-Pass hiện tại chưa giải quyết được vấn đề khi điểm nhìn nằm trong vùng bóng của khối Để khắc phục tình trạng này, có ba giải pháp khả thi.
Giảm giá trị của Stencil Buffer 1 đơn vị cho phần bóng khối nằm trong tầm nhìn, đặc biệt khi có nhiều vật thể, tuy nhiên phương pháp này sẽ tốn kém về chi phí tính toán.
Để tạo hiệu ứng bóng khối, cần thiết lập một mặt phẳng nằm gần điểm nhìn cho từng phần bóng, với điểm nhìn nằm trong khu vực đó Phương pháp này tuy hiệu quả nhưng cũng phức tạp và tốn kém về mặt tính toán.
Thuật toán Z-Fail là một phương pháp trong đó giá trị Stencil không được tính bằng cách tăng các mặt trước của bóng khối và giảm giá trị của các mặt sau khi Z-Buffer Pass Thay vào đó, toàn bộ quá trình được điều chỉnh để đếm từ vô cực thay vì từ điểm nhìn, dẫn đến việc thuật toán này được gọi là Z-Fails.
Thuật toán Z-fail đƣợc thể hiện bằng đoạn mã giả sau:
Procedure IN_SHADOW_TEST // Z-fail
For {tất cả các vật thể cần đổ bóng} do
- Xây dựng danh sách các cạnh viền
- Tính toán các tứ giác bao quanh bóng khối dựa trên các cạnh viền và từ vị trí của nguồn sáng
For {Tất cả các mặt trước của bóng khối nhìn từ vị trí của điểm nhìn} do if Depth test fails then
- Giảm giá trị Stencil Buffer
For {Tất cả các mặt sau của bóng khối nhìn từ vị trí của điểm nhìn} if Depth test fails then
- Tăng giá trị Stencil Buffer
2.5.1 Tất cả các mặt trước của bóng từ vị trí điểm nhìn
//set the neighbour indices to be -1 for(unsigned int i=0; i