Sách: Beginning DirectX 9

Lượt xem: 15,212Lượt tải: 5Số trang: 177

Mô tả tài liệu

WENDY JONES là người đã dành trọn niềm đam mê của cô ấy cho máy tính ngay từ lần đầu tiên cô được nhìn thấy chiếc máy Apple IIe khi còn học ở trường phổ thông. Kể từ khi tiếp cận với nó, cô ấy đã dành mọi khoảng thời gian rảnh rỗi vào công việc học lập trình BASIC và kỹ thuật đồ hoạ, vẽ những ý tưởng của mình lên giấy vẽ và thực hiện nó trên máy tính. Ngoài BASIC thì cô cũng đã lần lượt tiếp cận với các ngôn ngữ khác như Pascal, C, Java và C++....

Tóm tắt nội dung

Hiện tại Wendy đang làm việc các phần mềm dành cho PocketPC và trên những thiết bị Nếu bạn có bất cứ góp ý hay những câu hỏi về quyển sách này, bạn có thể liên hệ với cô DirectX là gì, tại sao và làm thế nào để sử dụng nó ập trình game có thể nói là một công việc cực kỳ thú vị trong thế giới lập trình bởi nó đem lại cho bạn cơ hội được tạo ra một thế giới ảo nơi mà những sinh vật Liệu bạn có thể tìm thấy điều này ở một nơi nào khác? mong muốn và hơn cả là một môi trường để họ có thể sống theo đúng sở thích. trước đây, có lẽ ở cấp độ người sử dụng còn chưa hề biết đến các thiết bị thể hiện hình được phổ biến hơn, OpenGL đã mở rộng nền tảng của mình và điều đó thực sự đã đem đến một cú huých mạnh đầu tiên trong lịch sử phát triển game cũng như những ứng dụng tảng DirectX, nó đã giúp cho những game thủ có thể tận hưởng được một công nghệ đồ tượng (OOP) sẽ giúp bạn có thể hiểu được tất cả những bài giảng được trình bày trong học và hình hoạ, tuy nhiên hầu hết những khái niệm toán học sử dụng cũng sẽ được giải làm thế nào để thiết lập và chạy một ứng dụng sử dụng nền tảng này. cung cấp cho bạn những khái niệm cơ bản phục vụ quá trình thiết kế và xây dựng một nhìn toàn cảnh hơn về tất các các kiến thức chúng ta đã học và áp dụng cụ thể chúng như Nếu bạn đã từng làm quen với môi trường DirectX và cũng đã từng viết một vài ứng dụng sử dụng nền tảng này, bạn có thể bỏ qua phần một. để có thể hiểu hết được những khả năng mà DirectX có thể đem lại. DirectX là gì, tại sao và làm thế nào để sử dụng nó irectX về thực chất là một hệ thống các giao diện lập trình ứng dụng (API) phục viện API “sạch” (đã được chuẩn hoá) để họ có thể viết và chạy trên hầu hết các nền tảng Trong chương này, chúng ta sẽ đề cập tới các vấn đề: DirectX là một tập hợp thư viện các hàm API được Microsoft thiết kế để cung cấp cho những người phát triển game một giao diện lập trình cấp thấp để liên kết tới các phần phát triển có thể viết những game của họ bằng cách sử dụng tập hợp cách hàm này lại với nhau mà không cần phải quan tâm nhiều tới phần cứng mà nó sẽ được sử dụng. sử dụng hoàn toàn độc lập với nhau, bạn có thể chỉ cần thêm những thành phần nào mà Nó cung cấp những hàm API để người dùng có thể quản lý quá Tất cả những gì người dùng nhập vào sẽ được quản lý bởi các hàm Khả năng kết nối mạng được cung cấp cho những hệ thống game của đến cho bạn khả năng phát triển ứng dụng có thể giao tiếp với bất kỳ một máy nào bạn sẽ cần phải sử dụng tới những hàm API do thành phần này cung cấp. năng của DirectSound là cho phép bạn có thể tải và chơi một hoặc nhiều file nhạc Nó có khả năng hỗ trợ hầu hết các chức năng chính của một phần không phải tải tất cả các đối tượng file này lên bộ nhớ, thay vào đó là truy cập trực DirectSetup cung cấp cho bạn những chức năng giúp ứng dụng có thể tự động cài Hệ thống đồ hoạ DirectX bao gồm toàn bộ các chức năng của cả DirectDraw và Direct3D. trợ giao diện đồ hoạ (non-GUI) và cách duy nhất để thực hiện các thao tác đồ hoạ này là truy cập trực tiếp giữa mã game và phần cứng, lập trình viên có thể có được toàn bộ sức Tại thời điểm đó, không phải tất cả các thiết bị đều tuân theo một chuẩn nhất định. điều này đã làm cho quá trình thao tác trên màn hình đồ hoạ cực kỳ khó khăn đặc biệt khi game sử dụng độ phân giải 640 x 480 cũng đã khiến các lập trình viên phải truy cập trực giảm đi tài nguyên hệ thống giành cho các game và nó cũng đã loại bỏ toàn bộ khả năng DirectX đã cung cấp cho các lập trình viên một thư viện độc lập để phát triển, nó là lớp trung gian giữa game và các phần cứng của PC. vẫn chưa hỗ trợ được nhiều dạng phần cứng khác nhau, nhưng đó thực sự đã là một thay đổi rất có ý nghĩa và thực sự đáp ứng được mong muốn của những người phát triển game. Các thành phần của DirectX được kết hợp lại như thế nào Microsoft muốn đảm bảo rằng mỗi một thành phần của DirectX có khả năng hỗ trợ các Để thực hiện được điều này, Microsoft đã thiết kế DirectX trên C++, nhưng các đối tượng COM cần thiết phải có một giao diện để truy cập tới các Đây thực sự là một thuận lợi so với cách sử dụng các đối tượng thông thường bởi vì ta có thể xây dựng rất nhiều kiểu giao diện cho một đối tượng Điều này được thể hiện, mỗi một phiên bản của DirectX đều chứa những giao diện mới của DirectDraw và nó có thể truy cập thông qua các hàm API, ngoài ra nó vẫn chứa phiên game được viết để sử dụng Direct7 hoàn toàn có thể hoạt động với Direct9 mà không gặp Thêm một lợi điểm nữa của kỹ thuật này là các đối tượng COM có khả năng hoạt động dụng Visual Basic, C++ hay C# mà vẫn có thể sử dụng cùng một thư viện DirectX. cứng cũng như của các thiết bị điều khiển nên HAL được viết bởi chính các nhà phát triển Bạn không bao giờ phải kết nối tới HAL một cách trực tiếp trong quá trình Thay vào đó chúng ta sẽ sử dụng kết nối gián tiếp thông qua các hàm Trong các phiên bản trước, DirectX còn được phân chia lớp HAL ra thành một lớp khác các chức năng này bằng phần mềm, thông thường thì tốc độ khung hình thể hiện sẽ thấp Lớp HEL này đã được thay đổi thành kiểu thiết bị phần mềm có thể cắm và chạy (tương Thiết bị này thực hiện quá trình hiển thị thông qua các sử dụng kỹ thuật này nữa mà thay vào đó là yêu cầu thiết bị hiển thị hỗ trợ 3D bởi vì gần hình ảnh cũng như trả lời câu hỏi DirectX là gì, tại sao và sự cần thiết của nó như thế nào. Trong chương tiếp theo chúng ta sẽ đi sâu hơn vào những vấn đề kỹ thuật, giúp bạn có thể thông tin cần thiết giúp bạn có khả năng tự phát triển một thiết bị cắm chạy được mô rong phần này sẽ trình bày một ví dụ nhỏ sử dụng DirectX. đi qua tất cả những tiến trình cần thiết cho một chương trình sử dụng công nghệ những ví dụ và hướng dẫn chúng ta sẽ làm theo dưới đây, mặc dù những flatform đó có thể nó đã được viết sẵn trong ví dụ đi kèm của bộ SDK nhưng chúng ta sẽ không sử dụng Điều đó sẽ giúp bạn hình dung được một cách rõ ràng hơn những công việc bạn phải Dưới đây là nội dung những phần chúng ta sẽ xem xét trong chương này: Xác lập các thông số cho ứng dụng Làm thế nào để game của bạn phóng lên toàn màn hình Bước đầu tiên bạn cần làm cho bất kỳ một ứng dụng nào là tạo một project mới trong thoại có tên Application Wizard sẽ xuất hiện với 2 tabs cho bạn lựa chọn và xác lập là: Sau khi bạn thực hiện các bước trên, Visual Studio đã tạo ra một project mới cho bạn tuy lệnh để khởi tạo cho một ứng dụng trong môi trường window. Phần đầu tiên của bất kỳ một ứng dụng nào bao giờ cũng là Entry point (điểm bắt đầu, Trong các ứng dụng được viết dưới dạng Consolo, hàm bắt đầu có tên là main(), trong khi đó hàm bắt đầu của một ứng dụng Window bao giờ cũng là WinMain(). Hàm WinMain này được dùng để khởi tạo ứng dụng của bạn như tạo cửa sổ giao diện // khai báo sử dụng thư viện mẫu của Windows - cần thiết cho tất cả các ứng dụng // Đây là hàm winmain, hàm được gọi đầu tiền của mọi ứng dụng trong window // Kiểm tra các sự kiện được gửi tới trong hàng đợi của ứng dụng Phần quan trọng nhất của hàm trên là phần quản lý các thông điệp của chương trình. này đảm nhiệm quá trình quản lý các thông điệp mà window gửi tới ứng dụng. kỳ một thông điệp nào được gửi tới (hàm GetMessage() trả về giá trị True) thì hàm Sau khi bạn đã tạo xong hàm WinMain, bây giờ là lúc chúng ta xây dựng hàm tạo cửa sổ Trong môi trường Window, bất kỳ một ứng dụng nào muốn tạo một cửa sổ trên màn hình đăng ký ứng dụng của bạn sẽ có thể tạo những cửa sổ cần thiết. ví dụ quá trình đăng kí một cửa sổ thông thường với hệ thống và sau đó lớp này sẽ được NULL, // con trỏ đối tượng menu của chương trình; NULL = không sử dụng Tất cả thông tin, ý nghĩa của các hàm sử dụng ở trên bạn có thể tham khảo thêm trong bất phần này, các mã lệnh sẽ được được viết một số chú thích để bạn dễ hình dung hơn tiến Tất cả các ứng dụng muốn thể hiện một cửa sổ trên màn hình đều phải thực hiện quá trình màu màn hình nền, loại biểu tượng chuột sử dụng, và biểu tượng thể hiện của chương Sau khi đối tượng có kiểu WNDCLASSEX đã được xác lập đầy đủ các thông tin, nó sẽ được truyền làm tham số cho lời gọi hàm đăng ký với hệ thống Hàm RegisterClassEx sẽ lấy thông tin được cung cấp trong đối tượng WNDCLASSEX truyền cho hàm và thực hiện quá trình đăng ký lớp cửa sổ ứng dụng với hệ thống. bạn đã có một lớp cửa sổ được đăng ký, bạn sẽ có thể tạo ra các cửa sổ được sử dụng Bước tiếp theo đó là tạo ra cửa sổ, nó được thực hiện thông qua hàm CreateWindow. Hàm CreateWindow này yêu cầu 11 đối số, mỗi một thông số được cung cấp sẽ được dùng để xác lập kiểu hiển thị của cửa sổ ứng dụng trên màn hình. Hàm WndProc (Window Procedure) là một hàm nữa bạn cần phải khai báo cho một cửa Mã nguồn của hàm này được minh hoạ ở dưới đây, hàm này sẽ làm nhiệm chuột được kích trên cửa sổ ứng dụng, hệ thống sẽ gửi sự kiện kích chuột này tới cho ứng Trong hàm này, bạn sẽ tiến hành khai báo sự những // Kiểm tra xem có thông điệp nào được gửi tới hàng đợi cửa ứng dụng không // Chú ý, hàm này yêu cầu bạn phải cung cấp thông điệp trả về cho quá trình Tại thời điểm này, bạn đã có thể biên dịch ứng dụng và chạy thử, sau khi chạy, ứng dụng Với phiên bản DirectX 8 trước đây, phần vẽ các đối tượng được chia ra làm hai hệ thống DirectDraw được sử dụng để thể hiện các đối tượng được gộp lại toàn bộ trong một giao diện thống nhất thông qua các hàm API của Trong phần này chúng ta sẽ dần dần tiếp cận với cách để thực hiện tất cả quá trình vẽ Trước tiên là các bước sác lập hệ thống để có thể chạy được hệ - Tạo một môi trường Direct3D (thiết bị - device) để thể hiện đối tượng. Đối tượng Direct3D là một đối tượng cung cấp một giao diện được sử dụng bởi các hàm đối tượng Direct3D đem đến cho bạn khả năng tìm và xác nhận xem hệ thống có bao nhiêu thiết bị hiển thị đồ hoạ đã được cài đặt trên hệ thống cũng như kiểm tra khả năng Một đối tượng Direct3D được tạo thông qua cách sau: D3D_SDK_VERSION chỉ là một tham số mặc định có thể gửi cho hàm Direct3DCreate9 Giá trị trả về của hàm sẽ là Bạn có nhớ là tôi đã đề cập tới khả năng truy suất số lượng thiết bị hiển thị video hay Đây là một chức năng đã được cung cấp trong Direct3D, để làm được Hàm GetAdapterCound có khả năng cho phép bạn biết số lượng thiết bị hiển thị của hệ Hàm này không yêu cầu bất kỳ một tham số nào phải truyền cho nó và thông thức cho các ứng dụng có thể sử dụng để kết xuất hình ảnh ra màn hình. diện này tất cả các thao tác vẽ trong game của bạn sẽ được thực hiện. Một thiết bị Direct3D này có thể được tạo bằng cách gọi tới hàm CreateDevice. Đối tượng thiết bị kết quả trả về này sẽ được sử dụng trong toàn bộ game của bạn để truy hàm này thanh công, kết quả trả về sẽ là D3D_OK; trong các trường hợp khác nó có thể là một trong các giá trị dưới đây: Một trong những tham số cung cấp cho hàm không hợp lệ. Các tham số cần thiết của hàm CreateDevice: Có giá trị là số hiệu của card đồ hoạ mà thiết bị dùng để Hầu hết các ứng dụng game sẽ gửi giá trị D3APAPTER_DEFAULT cho hàm để mặc định sử dụng thiết bị đồ hoạ chính của hệ thống. Nếu hệ thống chỉ có một thiết bị hiển thị được cài đặt (card đồ hoạ), thì thiết bị đó sẽ được Trong trường hợp có nhiều hơn 1 thì thiết bị đầu tiên sẽ là Một thói quen tốt mà bạn nên tạo lập đó là luôn luôn kiểm tra kết quả trả về của hàm để Các tính năng của Direct3D sẽ được cài đặt trong Đây là con trỏ của cửa sổ sử dụng thiết bị đó. chúng ta chỉ sử dụng giá trị cờ trạng thái xác lập tiến trình sử lý vertex sẽ được điều khiển quá trình hiển thị của thiết bị như xác lập kiểu hiển thị cửa sổ ứng Sau khi một thiết bị hiển thị đã được khởi tạo bạn sẽ có thể gọi tiếp các phương thức khác của Direct3D để lấy hoặc vẽ bất kỳ một đối tượng nào lên màn hình. trong chế độ cửa sổ ứng dụng bạn phải truyền cho hàm Windowed Có giá trị TRUE nếu ứng dụng kiểu cửa sổ và FALSE cho dụng, tham số này phải được xác lập là 0. Sau khi một thiết bị Direct3D đã được tạo ra, bây giờ bạn có thể bắt đầu tô điểm lên màn hình, bạn có thể làm điều này với các bức ảnh hay thông qua một số đa giác. công việc đầu tiên bạn phải làm trong vòng lặp chính của ứng dụng game là xoá sạch màn Việc xoá màn hình này sẽ cho bạn một khung hình hoàn toàn mới để thao tác và vẽ Tệp tin winmain.cpp đã được cập nhật thêm hàm này bạn có thể tìm Bạn có thể xoá toàn bộ màn hình bằng cách gọi tới hàm Clear. của màn hình sẽ được xoá, đây là các tham số hay được sử dụng nhất. Giá trị mà bạn sẽ sử dụng tại thời điểm này là D3DCLEAR_TARGET, nó dùng đề xác lập đối tượng được xoá là vùng dữ liệu hiển thị hiện thời. Color – giá trị màu (có kiểu D3DCOLOR) sẽ được xác lập sau khi xoá. thì bạn phải truyền giá trị này cho hàm là 0. Sau khi bạn đã xoá sạch một khung hình, bây giờ là lúc chúng ta thể hiện nó lên màn Thực chất thì tất cả quá trình bạn thao tác vẽ cho tới thời điểm này đều được thực hiện Bộ nhớ đệm back buffer này là một vùng nhớ để lưu giữ toàn bộ kết quả các thông tin từ bộ nhớ đệm và hiển thị nó lên màn hình. và tất cả những gì bạn thực hiện trên bộ nhớ đệm sẽ được hiển thị lên màn hình. Lật trang là quá trình tráo đổi dữ liệu từ bộ nhớ đệm lên bộ nhớ thực của màn hình, để thực hiện quá trình hiển thị thì bạn phải gọi tới hàm yêu cầu lật trang này mỗi khi thực hiện pSourceRect là một con trỏ có kiểu RECT trỏ tới dữ liệu vùng chữ nhật thể hiện từ Giá trị này phải được gán là NULL nếu bạn muốn sử dụng hDestWindowOverride là con trỏ trỏ tới của sổ đích được dùng để hiển thị. trị này phải được xác lập là NULL nếu bạn sử dụng những xác lập cửa sổ trước đó pDirtyRegion là con trỏ trỏ tới những vùng mà bộ đệm cần được cập nhật dữ liệu. Một lần nữa giá trị này là NULL nếu bạn muốn cập nhật toàn bộ dữ liệu bộ đệm. Công việc cuối bạn phải làm trong bất kỳ một ứng dụng DirectX nào là dọn dẹp vào giải phóng bộ nhớ cho các đối tượng bạn đã sử dụng. bạn cần thiết phải giải phóng những đối tượng đó để trả lại tài nguyên các đối tượng đó đã chiếm Các đối tượng COM, nền tảng của DirectX, luôn được quản lý bởi hệ thống thông qua một biến đếm lưu giữ số lượng đối tượng mà ứng dụng đã tạo ra cũng như còn lại sau khi vừa được loại Bằng việc sử dụng hàm Release, bạn vừa thực hiện việc giải phóng đối tượng và vừa tác Lấy vị dụ, khi giải phóng một thiết bị hiển thị Direct3D, bạn sử dụng lệnh sau: Nếu điều kiện trong câu lệnh If được thoả mãn (tức là biến pd3dDevice có chứa dữ liệu – nó được gán cho địa chỉ của một thiết bị được khởi tạo trước đó), thì thực hiện quá trình giải phóng Sau khi đã tìm hiểu qua một vài lệnh và thông tin cơ bản về DirectX, bây giờ là lúc bạn sẽ xem xét làm thế nào để xác lập và chạy một ứng dụng DirectX, là lúc để chúng ta thêm Những mã lệnh này sẽ được chèn thêm vào trong tệp tin Bước đầu tiên trước khi viết bất kỳ một ứng dụng DirectX nào đó là chèn tệp tin header Tiếp theo bạn cần khai báo 2 biến toàn cục sẽ cần thiết trong quá trình lưu giữ con trò đối Bạn nên kiểm tra xem chắc chắn một đối tượng DirectX có khác rỗng (NULL) không trước Nếu bạn gọi hàm này trên một đối tượng rỗng thì chắc Biến được khai báo kiểu LPDIRECT3D9 là một con trỏ sử dụng giao diện IDirect3D9, Tiếp theo, bạn sẽ cần phải gọi tới hàm initDirrect3D, bạn có thể thực hiện theo cách tôi sử Chú ý là bạn phải đặt đoạn code gọi tới hàm này sau khi đã gọi hàm // hàm này được gọi sau khi quá trình khởi tạo cửa sổ ứng dụng kết thúc Sau khi đã xác lập các thông số khởi tạo, bây giờ là lúc chúng ta thay thế vòng lặp quản lý sự kiện Windows bằng một mã lệnh khác hữu dụng hơn cho các ứng dụng game. hàm GetMessage để kiểm tra sự kiện mỗi khi nó được gửi tới và chờ ứng dụng sử lý; Chính vì thế trong phần này thay vì sử dụng hàm GetMassage thì chúng ta sẽ sử dụng hàm PeekMessage, hàm này cũng có chức năng kiểm tra thông điệp tuy nhiên nó trả điều khiển về ngay lập tức, cho phép ứng dụng game của bạn có thể gọi lại chính Trong ví dụ này, chúng ta sẽ chèn thêm mệnh đề else sau lời gọi PeekMessage để gọi tới Hàm render này sẽ thực hiện quá trình vẽ các đối tượng lên màn hình, hàm này sẽ được định nghĩa ngay ở phần sau. Trong hàm initDirect3D này chúng ta sẽ thực hiện việc tạo một đối tượng Direct3D và Tại đoạn đầu của hàm trên, chúng ta đã tạo một lời gọi tới hàm Direct3DCreate9. thực hiện lệnh tạo một đối tượng Direct3D, từ đó bạn có thể tạo một thiết bị hiển thị Tiếp đến là quá trinh xác lập các thông số hiển thị của ứng dụng. Tiếp theo là hàm CreateDevice sẽ được gọi với tham số thứ 2 ở cuối cùng là biến cấu trúc dụng thiết bị hiển thị đồ hoạ chính của hệ thống nên giá trị truyền vào là rằng ví dụ của chúng ta sẽ chạy được trên hầu hết tất cả các phần cứng. chức năng Vertex trên phần cứng chỉ có được trên một vài card đồ hoạ mới. cuối cùng &pd3dDevice là biến lưu giữ kết quả tạo đối tượng thiết bị Direct3D mà hàm này sẽ được gọi bên trong vòng lặp chính và được gọi sau mỗi khung hình hiển thị. Trên đây chỉ là một ví dụ đơn giản của hàm render. chắc chắn kết quả trả về sau khi gọi hàm CreateDevice, nếu nó có giá trị NULL tức là có Tiếp đó, chúng ta sử dụng hàm Clear đã được giới thiệu ở trên. toàn bộ bộ đệm, nên bạn cần truyền tham số 0 và NULL cho 2 tham số đầu của hàm. Ngoài ra bạn cũng cần phải truyền một giá trị thực 1.0 để xác lập độ sâu của vùng đệm. Bạn có thể xác lập giá trị này trong khoảng 0.0 tới 1.0. Bộ đệm stencil (!) cho phép bạn đánh dấu vùng chính diện của bức ảnh mà chúng không Bởi vì chúng ta không sử dụng nó nên tham số này sẽ được xác lập là 0. Công việc cuối cùng cần phải thực hiện trong hàm render là thể hiện đối tượng từ bộ đệm hiện toàn bộ vùng đệm lên màn hình, giá trị NULL sẽ được truyền cho tất cả các tham số Dĩ nhiên là sau khi ứng dụng kết thúc, bạn sẽ muốn giải phóng hết tất cả các đối tượng đã Trước khi giải phóng một đối tượng nào, bạn cần phải kiểm tra xem đối tượng đó có khác Nếu đối tượng đó thực ra đã được tạo ra, phương thức Release sẽ được gọi Hàm này sẽ được đặt trước lời gọi xác Cuối cùng thì bạn cũng đã có tất cả những đoạn code cần thiết đều tạo một ứng dụng Tuy nhiên trước khi bạn có thể biên dịch ứng dụng và chạy nó, bạn sẽ Đối tượng này sẽ được mở rộng và cho Không giống như ví dụ ban đầu, cửa sổ ứng dụng này sẽ có DirectX có thể làm, nhưng nó đã cung cấp cho bạn những kiến thức nền tảng để bắt đầu Trong ví dụ mà chúng ta đã thực hiện ở trên, ứng dụng của chúng ta đều là dạng cửa sổ có phù hợp cho các ứng dụng thông thường tuy nhiên đối với một ứng dụng game, bạn cần Chính vì vậy bạn không thể không sử dụng chế độ chạy ứng dụng ở dạng toàn màn hình. Để tạo ứng dụng dạng này bạn chỉ cần phải thay đổi một đoạn code rất nhỏ trong ứng dụng mà chúng ta vừa tạo, thay đổi này được xác lập chủ yếu trong hàm CreateWindow. Bạn có thể thấy tham số thứ ba, chúng ta đã xác lập kiểu ứng dụng là dạng cửa sổ với giá Trước khi chúng ta tiến hành xác lập cửa sổ dạng thể hiện toàn màn hình, kiểu dáng cửa Phần xác lập đầu tiên, WS_EX_TOPMOST, có tác dụng đặt vị trí hiên thị của cửa sổ này Có rất nhiều tệp tin thư viện cần thiết cho những chức năng khác nhau của DirectX. chỉ cần liên kết tới những thư viện nào chứa những hàm cần thiết mà bạn muốn sử dụng. Tiếp theo chúng ta sẽ tiến hành thay đổi một chút mã lệnh trong hàm initDirect3D. biến có kiểu cấu trúc D3DPRESENT_PARAMETERS chúng ta đã truyền cho hàm Để xác lập ứng dụng dạng toàn màn hình trong DirectX, tham số Windowed và Thay đổi mà bạn có thể thấy ngay được đó là thuộc tính d3dpp.Windowed đã được đảo dụng của bạn là dạng chiếm toàn màn hình. Đối với ứng dụng kiểu cửa sổ mà chúng ta đã tạo lúc đầu, bạn không cần thiết phải quan tâm tới giá trị này bởi vì bạn sử dụng những xác lập mặc định của màn hình desktop bằng chiếm toàn bộ màn hình, bạn cần thiết phải tự mình xác lập các thông số D3DFORMAT D3DFMT_X8R8G8B8 thể hiện bạn sẽ sử dụng 32-bit để định dạng cho một điểm ảnh Tất cả các xác lập lại code trên bạn có thể tìm thấy trong mã nguồn chương trình tại thư Trong phần tiếp theo, chúng ta sẽ đi tìm hiểu cách để kiểm tra xem hệ thống có khả năng Nếu ứng dụng game của bạn chạy ở chế độ cửa sổ trên màn hình desktop thì việc kiểm tra trị D3DFMT_UNKNOWN cho hàm, chương trình sẽ tự động xác lập giá trị mặc định mà bạn chạy ở chế độ toàn bộ màn hình (fullscreen) , thì việc xác định những chế độ hiển thị Chúng ta phải sử dụng tham số D3DFMT_UNKNOWN cho kiểu bộ đệm BackBufferFormat Đó là lý do tại sao khi bạn viết một game ở chế độ toàn bộ màn hình, thì tốt nhất là bạn nên kiểm tra phần cứng để chắc rằng nó hỗ trợ những gì mà Để thực hiện điều đó, Direct3D cung cấp cho bạn một số hàm thông Hàm đầu tiên mà bạn cần đã được giới thiệu ở phần trên: Thông thường, hàm này sẽ trả về một giá trị kiểu integer không dấu (unsigned integer) chỉ Viêc nắm được thông tin chắc chắn về thiết bị đồ hoạ trên máy của bạn là rất hữu ích. dụ, bạn có thể muốn biết độ phân giải mà thiết bị đồ hoạ hỗ trợ, hoặc thông tin hãng sản Sử dụng hàm GetAdapterIdentifier, bạn có thể thu thập được rất nhiều thông tin. ■ Tham số đầu tiên có kiểu integer không dấu để xác định thiết bị đồ hoạ nào mà bạn ■ Tham số thứ hai, là một cờ (flag), xác nhận WHQLLevel của trình điều khiển. ■ Tham số thứ ba là con trỏ tới vùng nhớ của cấu trúc D3DADAPTER_IDENTIFIER9. Cấu trúc này lưu giữ toàn bộ những đặc trưng có liên quan đến thiết bị và trình điều khiển Bước tiếp theo là lấy thông tin chi tiết về các chế độ hiển thị mà thiết bị đồ hoạ hỗ trợ. làm được điều đó, trước tiên bạn phải kiểm tra xem có bao nhiêu chế độ hiển thị có thể. Việc này được thực hiện qua hàm GetAdapterModeCount, định nghĩa như sau: Đoạn code này chỉ ra chính xác từng bước và các lệnh cần thiết để đưa ra một hộp thoại Tôi đã lấy hàm initDirect3D ở ví dụ trên và chỉnh sửa lại để nó có thể lấy ra thông tin về Thông qua nó bạn sẽ sử dụng được Ở đây ta định nghĩa một cấu trúc IDENTIFIER9 và đưa vào hàm GetAdapterIdentifier. Ở đây hàm addItemToList dùng để bổ sung thông tin vào hộp thoại sẽ sau này. Tiếp theo, ta sử dụng GetAdapterModeCount để lấy ra số chế độ tương ứng với định dạng Đây chỉ đơn giản là một hàm trợ giúp việc xuất số liệu, với đầu vào là một chuỗi, và nó sẽ // Biến adapterDetails là một vector chứa các chuỗi (string), mỗi chuỗi sẽ chứa thông tin Trong chương này chúng ta đã lần lượt đi qua rất nhiều các kiến thức cơ bản, từ làm thế nào để tạo một dự án mới trong Visual C cho tới xác lập và xây dựng một dự án sử dụng Những ví dụ mà chúng ta đã thực hiện có thể khá đơn giản nhưng nó thực sự là những bước mà chúng ta sẽ phải làm khi xây dựng bất kỳ một dự án nào. Trong chương này, chúng ta đã lần lượt đi qua các lý thuyết cơ bản về các phần: Làm thế nào để khởi tạo một đối tượng và thiết bị Direct3D. Thực hiện các quá trình khai báo cho một ứng dụng sử dụng DirectX. Làm thế nào để nhận biết khả năng hỗ trợ của các thiết bị đồ hoạ của hệ thống. Trong chương tiếp theo, chúng ta sẽ đề cập tới một số vấn đề về bề mặt và hoạt cảnh cũng Những câu trả lời của phần Hỏi đáp và Bài tập tự làm bạn có thể tra cứu trong phụ lục A 1. Đối tượng DirectX đầu tiên mà bạn cần phải tạo cho bất kỳ ứng dụng nào là gì? 4. Hàm nào trong DirectX có khả năng xoá và xác lập mầu nền hiển thị màn hình? 5. Hàm nào bạn sử dụng để nhận biết số lượng kiểu độ phân giải màn hình mà thiết bị 2. Cập nhật lại ví dụ 4 trên CD-ROM để tìm các kiểu màu mà thiết bị đồ hoạ hỗ trợ cả các game đều cần thiết phải có những hệ thống phần cứng 3D mới nhất mới những cách đơn giản nhất để sử dụng DirectX cho quá trình tạo một khung hình cơ sở Những phần mà bạn sẽ được giới thiệu trong chương này: Làm thế nào để tạo và sử dụng sprites (những khung hình) Làm thế nào để xác lập các thông số thời gian sao cho hiệu quả thể hiện hoạt cảnh tốt nhất. Surfaces là một phần của DirectX. khối liên tiếp nhau và thông thường là trên card đồ hoạ, tuy nhiên đôi khi nó cũng có thể Cả hai đều là vùng bộ nhớ để ứng dụng game của bạn thực hiện các thao Bộ đệm chính là những vùng bề mặt có thể nhìn trên cửa sổ ứng dụng game. gì bạn có thể thấy trong các ứng dụng windows đều sử dụng bộ đệm chính hay vùng vẽ. Trong chế độ chạy toàn màn hình, vùng bộ nhớ đệm chính được mở rộng ra và chiếm đề cập ở trên, vùng đệm phụ - back buffer là nơi bạn thực hiện tất cả các thao tác vẽ. khi quá trình vẽ hoàn tất, bạn sẽ sử dụng hàm Present để thể hiện chúng (copy dữ liệu từ Vùng đệm phụ được tạo trong quá trình gọi tới hàm CreateDevice bằng cách xác lập Offscreen surfaces là vùng trên bộ nhớ đồ hoạ hay hệ thống được dùng đề lưu trữ những tạo một game nhập vai, bạn sẽ cần phải có một vùng để lưu trữ những dữ liệu để thể hiện nhiều dạng địa hình khác nhau, hay những hình ảnh cho nhận vật của bạn. Thông thường các hình ảnh sử dụng trong DirectX đều là dạng bitmaps. 3.1 kế bên là ví dụ cho các ảnh bitmaps có thể được sử dụng trong ứng dụng game của bạn để thể hiện các dạng địa hình khác nhau. Việc thực hiện vẽ trực tiếp lên bộ đệm chính sẽ làm cho hình ảnh thể hiện bị nháy và giật. Các đối tượng đồ hoạ thông thường phải được vẽ lên bộ đệm phụ trước, sau đó gọi tới bạn có thể tạo được các surface lớn hơn. Bạn có thể lựa chọn một trong các kiểu Dữ liệu sẽ được copy vào bộ nhớ chính khi cần thiết. Quá trình khởi tạo sẽ được thực hiện trên bộ nhớ hệ này dùng để quản lý đôi tượng surface sau khi được tạo ra. Đây là tham số dùng để dự phòng và nó luông được gán giá trị NULL. Trong đó đối tượng surface sẽ có độ phân giải 640x480 và định dạng kiểu thể hiện là D3DPOOL_DEFAULT, // kiểu dữ liệu bộ nhớ pool được sử dụng Bởi vì định dạng ảnh kiểu Bitmap rất hay được sử dụng trong các ứng dụng đồ hoạ Chính vì thế chúng ta cũng sẽ sử dụng định dạng này trong các ví dụ tiếp theo. DirectX cung cấp ta khá nhiều hàm trong thư viện D3DX để trợ giúp chúng ta có thể dễ Có rất nhiều kiểu định dạng ảnh đang được sử dụng trong quá trình phát triển game hiện người phát triển game khác có thể chỉnh sửa hoặc sử dụng lại dữ liệu ảnh đó. Bạn có thể sử dụng những hàm trong thư viện D3DX này bằng cách thêm dòng lệnh khai này phải được xác lập là NULL. Con trỏ đối tượng có cấu trúc RECT dùng để thể hiện vùng chữ nhật Con trỏ đối tượng kiểu RECT lưu trữ vị trí vùng dữ liệu ảnh gốc sẽ được Tham số có kiểu D3DX_FILTER dùng để xác định kiểu bọ lọc được sử ảnh (số lượng màu mà một điểm ảnh có thể thể hiện – được tính bằng -bit). Sau đây là một ví dụ đơn giản gọi tới hàm D3DLoadSurfaceFromFile, nó thực hiện tải Sau lời gọi trên đây, dữ liệu toàn bộ ảnh bitmap trong tệp tin test.bmp sẽ được tải vào bộ Sử dụng DirectX để thể hiện một hình ảnh Chúng ta đã học cách tạo một surface cũng như làm thế nào để tải một ảnh bitmap vào trong nó, bây giờ là lúc chúng ta sẽ thể hiện nó. Để làm được điều này, bạn phải tạo một số thay đổi trong hàm Render mà chúng ta đã tạo trước đó Để hiển thị ảnh bitmap đó lên màn hình, bạn cần phải sử dụng hàm StretchRect, hàm này Các tham số đầu vào của hàm StretchRect này bao gồm: này là NULL, toàn bộ dữ liệu surface gốc sẽ được sao chép. Con trỏ kiểu RECT chứa dữ liệu vùng thể hiện đối tượng được sao Tham số này có thể là NULL nếu bạn kô muốn xác lập vùng Bạn có thể xác lập giá trị này là Có lẽ bạn sẽ tự hỏi làm thế nào đế có thể lấy được con trở chứa dữ liệu của bộ đệm back Hàm để thực hiện chức năng này có tên là GetBackBuffer, cấu trúc của nó // 0 nếu chỉ có một bộ đệm được sử dụng Kết hợp thêm các lời gọi tới hàm StretchRect và GetBackBuffer, hàm Render của chúng Bạn có thể tìm thấy mã nguồn của ví dụ này trong thư mục chapter3\example1 trên CD- Biên dịch và chạy ứng dụng, một cửa sổ chương trình sẽ xuất hiện có dạng sau: Trong phần trước, chúng ta đã sử dụng hàm StretchRect để sao chép toàn bộ ảnh StretchRect còn cho phép bạn sao cheo một hoặc nhiều khung hình nhỏ của ảnh offscreen surface, nó cho phép một surface có thể tạo nền từ nhiều hình nhỏ hơn. dụ, một ảnh offscreen surface có thể chứa rất nhiều khung hình chuyển động nhỏ của một số - pSourceRect và pDesRect – dùng để xác định vùng dữ liệu sẽ copy từ đâu đến đâu. Trong ví dụ tiếp theo chúng ta sẽ sử dụng chức năng này để thể hiện một thông điệp lên màn hình từ dữ liệu ảnh gốc chứa toàn bộ các chữ trong bảng chữ cái. ảnh dữ liệu gốc này, như bạn có thể thấy tất cả các chữ cái được lưu trong các vùng chữ chúng ta tiện lợi hơn rất nhiều trong quá trình xử lý và tìm tới chữ cái cần thiết một cách Kết quả của ví dụ trên là thể hiện dòng chữ “HELLO WORLD” và đem lại cho người Trước khi vòng lặp được thực hiện đọc từng chữ cái của thông điệp, nó phải được định Trong mỗi bước nhảy của vòng lặp, chúng ta sẽ tiến hành lọc trên từng chữ cái một. Đoạn mã tiếp theo sẽ tính toán vùng chữ nhật gốc bao gồm toạ độ X và Y của đỉnh trên Sau khi chúng ta đã có toạ độ của điểm này, chúng ta sẽ biết được đoạ độ điểm dưới cùng Tiếp đến chúng ta sẽ phải xác định vị trí mà chữ cái sẽ được đặt trên bộ đệm. Chúng ta đã xác lập biến cout dùng để kiểm tra xem bao nhiêu chữ cái đã được vẽ trên Thông qua biến count này, chúng ta sẽ tính toán được toạ độ điểm của các chữ Như đã đề cập ở trong phần trước, bạn có thể thực hiện quá trình sao chép những vùng Trong ví dụ thứ 2, chúng ta đã thể hiện một dòng thông bao từ các Sử dụng phương pháp tương tự, chúng ta cũng sẽ có thể xây dựng được một Sprites là những đối tượng đồ hoạ dạng 2D và nó thường được sử dụng trong các trò chơi dưới dạng hình ảnh của các nhân vật hay bất kỳ một đối tượng nào. nền của game, một sprite có thể được thể hiện quá trình nhân vật di chuyển trên màn Sprites đơn giản là một chuỗi các khung hình của hoạt cảnh về một nhân vật hay đối tượng nào đó trong game, nó có thể được di chuyển bởi người chơi, có thể tương tác với Trong phần này chúng ta sẽ đi qua các khái niệm cơ bản cũng như học cách tạo và sử dụng chúng trong game. Điều đầu tiên mà tất cả các sprites đều cần đó là hình ảnh để thể hiện. thể được sử dụng làm một hay nhiều khung hình thể hiện trong một hoạt cảnh. Sprites cũng cần một thông số khác đó là vị trí mà sprites được hiển thị trên màn hình. Giá trị này thường là tham số X, Y trong hệ toạ độ. Để có thể sử dụng được trong các trò chơi, sprites có thể còn phải lưu trữ thêm một vài thông tin khác nữa tuy nhiên 2 thông số trên thực sự cần thiết cho bất kỳ một sprites nào. Cấu trúc của đối tượng sprite sẽ lưu giữ toàn bộ thông tin về từng sprite mà bạn muốn tạo, Trong cấu trúc spriteStruct ở trên, dữ liệu ảnh của sprite được xác định thông quá biến có Giá trị toạ độ X và Y được sử dụng là giá trị kiểu nguyên. Bạn cũng có thể sử dụng hàm StretchRect để thực hiện quá trình kéo dãn, phóng to một hay nhỏ hơn thì hình ảnh đó sẽ tự động điều chỉnh lại sao cho được phủ đầy vùng ảnh kết Một khung hình đơn giản chỉ là một hình ảnh trong chuỗi các hình ảnh của một hoạt cảnh. Việc thể hiện liên tiếp các hình ảnh này sẽ tạo nên hiệu ứng chuyển động tương tự trong Những gì chúng ta đã làm ở trên chỉ là một xác lập ban đầu hết sức đơn giản cho một Tiếp đến chúng ta sẽ thực hiện quá trình thể hiện chúng lên màn hình. Để tạo một sprite, bạn sẽ cần phải sử dụng một vài hàm mà chúng ta đã đề cập trước đó. Mỗi một hàm được liệt kê ở trên đều có một chức năng riêng trợ giúp quá trình tạo và sử sprites từ tệp tin, hàm CreateOffscreenPlainSurface tạo một vùng trên bộ nhớ để lưu trữ những hình ảnh bạn cần sử dụng và hàm StretchRect trợ giúp hiện thị hình ảnh lên màn Bạn có thể sử dụng hàm D3DXLoadSurfaceFromFile để đọc dữ liệu ảnh cho một đối Để thực hiện quá trình trên, chúng ta sẽ đặt chúng vào trong một hàm duy nhất có tên là Hàm này chỉ có một tham số đầu vào duy nhất là một chuỗi Trước tiên bạn tạo một biến để lưu một surface mới, sao đó gọi tới hàm Hàm GetSurfaceFromBitmap sẽ được sử dụng trong toàn bộ các phần tiếtp theo của quấn Sau khi bạn đã đọc dữ liệu ảnh của sprite, bây giờ là lúc chúng ta xác lập thông tin chính Bời vì chúng ta sẽ sử dụng từng đối tượng surface đơn lẻ để chứa đựng lần lượt tất cả các sprité, một ý tưởng tốt là đặt tất cả những đoạn mã khởi tạo cho Vòng lặp for sẽ thực hiện quá trình khởi tạo trong 10 lần lặp, kết quả trả về là 10 sprite Tham số cuối cùng X và Y lưu toạ độ hiển thị của sprite, trong trường hợp này chúng ta sẽ đặt một vị trí ngẫu nhiên để hiển thị sprite trên màn hình. Đến thời điểm này, công việc cuối cùng bạn phải làm là thể hiện các sprites đó lên màn Một lần nữa, chúng ta sẽ thực hiện một vài thay đổi trong hàm render. vòng lặp for đã được tạo trước đó sẽ gọi tới hàm StretchRect nhiều lần, mỗi một lần đó Bên trong vòng lặp chúng ta đã thực hiện tạo và xác lập giá trị cho một biến Hàm StretchRect sẽ sử dụng biến kiểu RECT mà bạn đã tạo này để yêu cầu DirectX thể hiện đúng toạ độ sprite sẽ được hiển thị. hàm StretchRect như đã nói, quá trình này được thực hiện lần lượt từng bước, từng bước. Dữ liệu của sprites sẽ được đặt lên bộ nhớ đệm trước. sprites được hiển thị lên màn hình sau khi kết thúc lời gọi tới hàm render. Bạn có thể tìm thấy toàn bộ mã nguồn của ví dụ này trong thư mục chapter3\example3 Các sprites của bạn đã được hiển thị toàn bộ lên màn hình, liệu bạn đã hài lòng với cách Một trong những kỹ thuật nổi bật của một đối tượng sprite là cách và hướng đi mà nó cần phải di chuyển trong mỗi một khung hình. Để khắc phục vấn đề này, bạn cần khai báo thêm một vài biến khác trong cấu trúc của dụng để lưu giữ giá trị số lượng pixels trên mỗi khung hình mà bạn muốn sprite đó di Giá trị moveX và moveY này sẽ được cộng thêm vào cho giá trị posX và posY một khung hình chúng ta có thể sử dụng đoạn mã nguồn sau: Các sprites sau đó sẽ được gửi tới hàm Render để thực hiện quá trình hiển thị. khung hình, biến lưu trữ toạ độ sẽ được cập nhật, kết quả là sprite đó sẽ được di chuyển Dĩ nhiên, bạn sẽ phải kiếm tra vị trí posX và posY để chắc chắn sprite đó được hiển thị Ví dụ, trong đoạn mã ví dụ trên có thể được thay đổi để đảm bảo các sprites luôn nằm trong vùng hiển thị 640x480 của ứng dụng: // Bởi vì sprite cũng có thể chuyển động ngược lại nên một ý tưởng tốt là chúng ta // sẽ kiểm tra cả trường hợp toạ độ của sprite có nhỏ hơn 0 không Đoạn mã nguồn trên sẽ làm cho sprite luôn chuyển động trên vùng hiển thị 640x480 của Trong phiên bản trước của sprite chúng ta đã cập nhật để nó hỗ trợ khả năng di chuyển của sprite trên màn hình, nhưng thực sự thì những sprites này vẫn chưa hấp dẫn. sprites này chỉ thể hiện một hình ảnh tĩnh duy nhất. Nếu trong quá trình ứng dụng game đang chạy mà bạn thay đổi lại kích thước của cửa sổ ứng dụng, bạn phải chắc chắn giá trị posX và posY phải được kiểm tra lại để chắc chắn hiện chèn thêm nhiều khung hình của sprite hơn để tạo một sprite chuyển động thực sự Để thực hiện được khả năng này, chúng ta sẽ tiến 3.8 ở bên là dữ liệu của một sprite mẫu. int curFrame; // khung hình đang được hiển thị của sprite Để hỗ trợ khả năng hiển thị chuyển động của sprite, chúng ta thêm vào 2 biến: Số lượng khung hình của một animation sprite. Khung hình hiện tại đang được hiển thị của animation sprite. Hai biến này sẽ giúp chúng ta quản lý và lưu giữ trạng thái hiển thị các ảnh động của Bởi vì chúng ta đã thêm vào các biến mới trong kiểu cấu trúc của sprite nên chúng ta sẽ spriteStruct[i].numFrames = 4; // Số lượng khung hình của một sprite Bây giờ thì sprite đã được khởi tạo với toạ độ và dữ liệu ảnh động của nó, chúng đã sẵn Hàm render một lần nữa sẽ được cập nhật để hỗ trợ các dữ liệu mới. Khi số này lớn hơn số lượng khung hình của một hình sprite động (biến numFrames) thì biến curFrame này sẽ được xác lập lại thành giá trị 0. // Tăng biến lưu giá trị khung hình đang được hiện thị của sprite // Tạo một biến có kiểu RECT để lưu trữ dữ liệu tạm Nếu bạn biên dịch và chạy ứng dụng với đoạn mã đã được cập nhật ở trên, bạn sẽ thấy Bạn có thể tìm toàn bộ mã nguồn đã được cập nhật ở trên trong thư Trong quá trình chạy ví dụ trên, bạn có thể thấy rằng những chú cá được hiển thị thông trạng này là chúng ta đã sử dụng kỹ thuật hoạt hoạ để thể hiện các khung hình. không có cách nào đê tăng hay giảm chuyển động hoạt hình của sprite, nên khả năng hiển Trong phần tiếp theo, chúng ta sẽ đề cập tới vấn đề làm thế nào để giảm tốc độ của các hình sprite động cũng như đảm bảo các khung hình sẽ được hiển thị chính xác thông qua Để tạo một hoạt cảnh có thể chuyển động mượt mà thì ứng dụng game của bạn phải là timer, các hoạt cảnh chuyển động có thể được xác lập để xuất hiện tại những thời điểm Ví dụ, nếu bạn muốn chạy hoạt cảnh với tốc độ 30 khung hình trong một giây (fps) nhưng tốc độ khung hình hiện tại ứng dụng game của bạn lại là 60 fps, bạn muốn trường hợp này, bạn sẽ sử dụng một timer để quản lý quá trình cập nhật của hoạt cảnh chậm hơn một nửa so với bình thường, kết quả bạn sẽ có tốc độ cập nhật là 30 fps. Bạn có thể sử dụng hai hàm trong Windows hỗ trợ để xác định và quản lý chính xác thời Hàm GetTickCount, sử dụng bộ định giờ của hệ thống nên có đôi chút giới hạn về khả Giới hạn của hàm này là nó chỉ sử dụng một bộ định giờ chính xác hơn là cần thiết. được sử dụng trực tiếp bộ đếm thời gian của phần cứng thay cho giải pháp phần mềm hệ thống của hàm GetTickCount, nó cho phép bạn có thể định giời gian theo microseconds Nó rất là hữu dụng trong các ứng dụng game – rất cần những hàm quản lý thời gian thật chính xác để hiển thị các hoạt cảnh một cách chính xác nhất. Hàm trên yêu cầu duy nhất một tham số đầu vào: đó là con trỏ kiểu LARGE_INTEGER. Sau khi hàm này được thực hiện xong, tham số đầu vào lpPerformanceCount sẽ chứa giá Tiếp theo sẽ là một đoạn mã nhỏ ví dụ sử dụng hàm QueryPerformanceCount này. Ở ví dụ trên, biến timeStart sẽ lưu giá trị trả về từ hàm QueryPerformanceCount để xác Để thể hiện chính xác chuyển động của các sprite, bạn cần phải gọi tới hàm quả trả về của bộ đếm thời gian của hệ thống tại thời điểm hàm được gọi. Từ đó bạn có thể xác định được giá trị chênh lệnh giữa hai lần gọi và sử dụng chúng làm thước đo trong quá trình hiển thị các khung hình tiếp theo. Ví dụ, bạn có thể sử dụng đoạn mã nguồn minh hoạ dưới đây: Sau khi các đoạn mã trên đã được thực hiện xong, biến numCounts sẽ chứa giá trị số tương đương 64bit dữ liệu trên bộ nhớ và được dùng để nhận giá trị trả về của bộ đếm Sau khi bạn đã có giá trị chênh lệch khoảng thời gian giữa hai lần gọi, bạn sẽ cần thực hiện một bước nữa trước khi bạn có được một giá trị hữu dụng trong quá trình hiển thị Đó là bạn cần phải chia giá trị numCounts này cho tần số hoạt động Hàm QueryPerformanceFrequency dùng để lấy về giá trị tần số của bộ đếm thời gian này tượng có kiểu LARGE_INTEGER để lưu giữ kết quả trả về của hàm. Sau khi bạn có giá trị tần số hoạt động của bộ đếm, bạn có thể sử dụng kết hợp với giá trị Bây giờ thì chúng ta đã có giá trị tỷ lệ cần thiết để thể hiện các hình ảnh động một cách Trong phần này chúng ta sẽ ứng dụng những kiến thức đã học ở trên để thay đổi lại mã nguồn ví dụ 4 có sử dụng kỹ thuật hiển thị hình động trên bộ định thời gian hệ thống. Bước đâu tiên chúng ta cần thực hiện đó là thay đổi lại cấu trúc dữ liệu của Animation. trong phần trước chúng ta đã khai báo các biến moveX và moveY là các biến kiểu Chúng ta sẽ phải thay đổi kiểu dữ liệu này sang kiểu thực float để các hình ảnh của sprite sẽ được di chuyển chính xác hơn. Dưới đây là cấu trúc của sprite đã được cập Tần số hoạt động của bộ đếm là giá trị đại diện cho số xung nhịp mà đồng hồ thực hiện Như bạn có thể thấy, các biến posX và posY cũng đã được chuyển sang kiểu thực float để Tiếp đến, bạn cần cập nhật lại giá trị đã được sử dụng trong hàm initSprite cho biến Biến moveX này trước đó đã được xác lập giá trị là 1, nhưng bạn phải phải thay đổi nó thành một giá trị mới tương ứng với giá trị tỷ lệ mà ta đã tính toán ở trên. mới này là số lượng pixel mà bạn muốn sprite di chuyển trong một giây thể hiện các những chú ca có thể bơi lội dọc theo màn hình với một tốc độ hợp lý. Dòng lệnh này điều khiển quá trình di chuyển của mỗi sprite trên màn hình. rằng toạ độ X – biến posX – sẽ được tăng lên bằng cách cộng với giá trị biến moveX lưu Để quá trình hiển thị ảnh được chính xác sau khi ta tiến hành cập nhật mã nguồn hỗ trợ bộ định thời tốc độ hiển thị, bạn cần phải thay đổi dòng mã nguồn trên về dạng như sau: vì biến anim_rate này được cập nhật mỗi lần một khung hình được hiển thị, nó sẽ cung Bây giờ thì bạn đã cập nhật xong mã nguồn cho sprite, tiếp đến bạn sẽ phải chèn thêm các Tiếp đến chúng ta sẽ thực hiện lời gọi tới hàm QueryPerformanceFrequence để lấy về tần Bạn có thể biên dịch ví dụ đã được chỉnh sửa và xem hết quả của những gì chúng ta vừa cập nhật, các hình động đã được thể hiện mượt mà hơn. Tại thời điểm này, bạn đã được tiếp cận tới những kiến thức đơn giản về cách hoạt động của DirectX và làm thế nào để tạo và sử dụng các surface. Bạn cũng đã được tiếp cận tới kiến thức về bộ định thời timer và làm thế nào để tạo một thức về bộ định thời timer này trong suốt các phần tiếp theo của quyển sách, chính vì vậy Trong chương tiếp theo, bạn sẽ thực sự được tiếp cận tới thế giới đồ hoạ 3 chiều. Trong chương này chúng ta đã đề cập tới các vần đề sau đây: Làm thế nào để tải một ảnh bitmap thông qua các hàm trong thư viện D3DX Làm thế nào để hiển thị một ảnh lên màn hình bằng DirectX Sprite là gì và làm thế nào để sử dụng chúng Làm thế nào để tạo một sprite động bằng cách sử dụng kỹ thuật hiển thị các khung hình của sprite theo một bộ định thời timer. Bạn có thể tìm thấy câu trả lời của phần Kiểm tra kiến thức và Những bài tập tự làm trong 3. Các kiểu dữ liệu có thể lưu trữ trong offscreen surface? 1. Viết một ví dụ nhỏ sử dụng hàm StretchRect để thu nhỏ các phần của một bức ảnh. 2. Viết một chương trình sử dụng các kiến thức đã học trong chương này để di chuyển một Đa số các game bây giờ đều cố sử dụng được sức mạnh của các loại card 3D mới Những gì bạn sẽ được học ở chương này: ■ Những cấu trúc cơ bản bạn có thể sử dụng. Phần trước, tôi đã nói về những game chỉ cho phép di chuyển theo 2 phương, tức là trong Khái niệm (sprites) mà bạn dùng ở trên chủ yếu là cho không gian với DIrect3D cho bạn khả năng đưa thêm một chiều không gian nữa vào thế giới game với sự Trước khi bạn tận dụng được lợi thế của không gian 3D, bạn cần biết cách xây dựng gian 1D, (chỉ có duy nhất một trục), có thể được biểu diễn qua một giá trị. phải của gốc toạ độ là các giá trị dương, ngược lại, ở bên trái gốc toạ độ là các giá trị âm. Hệ toạ độ 2D, vì nó có 2 trục toạ độ, nên đòi hỏi thêm một giá trị nữa để biểu diễn một Để biểu diễn một điểm trong không gian 2D, bạn cần xác định vị trí dọc theo trục X Ví dụ, một điểm trong hệ toạ độ 2D có thể được xác định bằng 2 số là X và Hình 4.3 cho thấy hệ toạ độ 2D với một điểm có toạ độ X=3 và Y=5, người Trong ví dụ này điểm đó được biểu diễn là (3, 5). Như đã đề cập ở phần trên, hệ toạ độ 3D có thêm một trục nữa, gọi là trục Z. Chú ý rằng trong hệ trục toạ độ này, trục X và Y để thể hiện chiều rộng và chiều cao, còn Đây là hệ toạ độ được sử dụng trong Direct3D. Hệ tọa độ tay phải được dùng trong OpenGL, có trục X và trục Y giống như hệ tọa độ tay Bạn có thể tạo một hình nào đó bằng cách dùng giác ta cần có ba vecto để xác định ba đỉnh của Sử dụng vecto để thể hiện một hình Để tạo một hình tam giác cần có 3 vecto Thông tin về màu sắc này có thể chứa trong bốn Mỗi một giá trị trên giúp ta xác định màu của vecto. Sử dụng các biến R, G, B và A, bạn có thể đặt màu cho vecto. có màu trắng, thì các biến R, G và B đều được đặt là 1.0. Bạn có thể tạo được Vertex buffers là những vùng nhớ chứa thông tin về vecto cần thiết để tạo ra các đối Những vecto chứa trong buffer có thể chứa đựng nhiều dạng thông tin khác Để tạo một vertex buffer ta cần khai báo một biến có cấu trúc IDirect3DVertexBuffer9. Bước tiếp theo, ứng dụng cần tạo một vertex buffer và lưu trữ nó ở trong biến vừa khai Sau khi tạo thành công vertex buffer, ta có thể lưu dữ liệu vecto vào đó. Bạn có thể tạo vertex buffer thông qua lời gọi hàm CreateVertexBuffer. nghĩa là những vecto chứa trong buffer có thể chỉ chứa thông tin về vị trí, hoặc có thể Định dạng mềm dẻo của vecto cho phép sự tùy biến về thông tin chứa trong vertex buffer. Bằng cách sử dụng cờ FVF, ta có thể thay đổi buffer để chứa bất kì dạng vecto nào. được xác định bằng R, G và B sẽ là màu đặc. Direct3D có thể sử dụng được tới 8 loại texture khác nhau cho mỗi vecto. Định dạng vecto ta sẽ dùng được tạo ra bằng cách định nghĩa một cấu trúc vecto bổ sung. Cấu trúc vecto sau đây định nghĩa một vecto chứa thông tin về vị trí chưa qua biến đổi và Cấu trúc CUSTOMVERTEX bao gồm tọa độ chuẩn X, Y và Z của vecto, đồng thời có cả báo cho Direct3D rằng những vecto đang được dùng nằm trong vùng thấy được của màn Giá trị này thường được dùng tính toán về làm mờ và xén tỉa và nên gán giá trị là 1.0. Sau khi tạo được cấu trúc vecto, bước tiếp theo là quy định cờ FVF làm tham số cho hàm Code ví dụ dưới đây thể hiện lời gọi hàm CreateVertexBuffer sử dụng cấu trúc trên: Màu của vecto là giá trị kiểu DWORD. Lệnh này trả về một giá trị màu DWORD mà Direct3D có thể sử dụng. Một số lệnh khác là D3DCOLOR_RGBA và D3DCOLOR_XRGB, đã được trình bày chi Như bạn thấy, cấu trúc CUSTOMVERTEX được tạo ra trước, thông báo cho Direct3D Đối số đầu tiên cho CreateVertexBuffer, kích thước của buffer theo byte, tạo ra vùng nhớ Đối số thứ tư đặt vùng nhớ cho vertex buffer, Giá trị D3DPOOL_DEFAULT được dùng để Sau khi vùng nhớ này được khóa, bạn mới có thể Khóa vùng nhớ cho vertex buffer cho phép ứng dụng của bạn ghi dữ liệu lên đó. điểm này, bạn đã định nghĩa xong vertex buffer và kiểu của vecto mà nó chứa. Sau khi khóa vertex buffer, bạn có thể tự do copy dữ liệu vào buffer. các vecto mới vào buffer, vừa có thể sửa đổi những vecto đã nằm trong buffer. theo cho thấy cách sử dụng memcpy để copy một mảng vecto vào trong vertex buffer. g_Vertices và nó chứa những vecto sẽ được copy vào buffer. là con trỏ kiểu void đã được tạo ra qua lời gọi Lock. Hàm Unlock không đòi hỏi đối số và giá trị trả về của nó là D3D_OK nếu thành công. Sau khi nạp dữ liệu vào vertex buffer, ta có thể biểu diễn nó trên màn hình. Hàm SetupVB đòi hỏi biến chứa vertex buffer phải được khai báo bên ngoài phạm vi của thành công, hàm SetupVB trả về một giá trị kiểu HRESULT là S_OK. Sau khi bỏ thời gian để tạo vertex buffer và nạp dữ liệu vecto cho nó, chắc bạn sẽ tự hỏi Luồng trong Direct3D là mảng của những thành phần dữ liệu có bao gồm nhiều thành tố. Vertex buffer bạn tạo ra ở trên chính là một luồng. Trong lời gọi tới hàm SetStreamSource, đối số thứ nhất biểu diễn số của luồng được gán cấu trúc CUSTOMVERTEX được xây dựng, nó dùng hai giá trị trên khi tạo vertex buffer. Sau khi bạn tạo luồng và gắn nó với một vertex buffer, bạn có thể render những vecto Hàm DrawPrimitive sẽ duyệt qua vertex buffer và render dữ liệu của nó lên màn hình. Kiểu gốc có thể là một trong các giá trị: Đoạn code trên thông báo với Direct3D để render những vecto chứa trong vertex buffer được gán là 0, thông báo cho DrawPrimitive bắt đầu với vecto đầu tiên trong buffer. số cuối được gán là 1 bởi vì số vecto trong bộ đệm chỉ đủ để tạo ra một tam giác. Ta cần có thiết bị một Direct3D được khai báo chuẩn. Mã nguồn chi tiết cho phần tạo và render một vertex buffer có thể tìm thấy ở thư mục Ở trên, bạn phải lựa chọn cài đặt kiểu cơ bản mà DrawPrimitive sẽ sử dụng để render strip với mục đích đơn giản hóa việc vẽ và tạo khả năng cho thêm các tam giác một cách Mỗi điểm được xác định qua các tọa độ X, Y và Z. Một line strip là một loạt các đoạn thẳng nối nhau, trong đó mỗi đoạn thẳng thêm vào Một triangle list bao gồm các tam giác không nối với nhau và xuất hiện tự do bất cứ đâu trong hệ Một triangle strip là một loạt các tam giác nối với nhau trong đó mỗi tam giác thêm vào được Sau đó, mỗi khi một vecto được thêm vào, thì sẽ sinh ra hai đoạn thẳng nối hình 4.13, biểu diễn cả thứ tự của các vecto được thêm vào. tiên được tạo thành, mỗi một vecto thêm vào sẽ tạo thành một tam giác mới có một đỉnh bạn sẽ được học thêm một số chủ đề nâng cao hơn, nhưng ngay từ bây giờ bạn cần phải Giờ đây bạn đã có những khái niệm cơ bản về cách làm việc của không gian 3D và làm thế nào để định nghĩa một vật thể ở trong nó, đã đến lúc để học cách len lỏi sâu hơn vào cái Trong chương tiếp theo, bạn sẽ được học cách xoay và di chuyển một vật thể. Trong chương này bạn đã được học: Bạn có thể tìm thấy đáp án của các câu hỏi và bài tập ở phần phụ lục A, “Đáp án phần bài 2. Viết một hàm để render một số tam giác sử dụng kiểu triangle list. Điều này có thể đúng trong một vài năm trước đây, Chương này sẽ giới thiệu cho bạn về ma trận và cho thấy nó giúp bạn giải quyết công Những phần mà bạn sẽ được học trong chương này: ■ Ma trận là gì và nó có tác dụng gì với thế giới 3D ■ Tác động lên các vật thể 3D trong một scene. Giờ đây khi bạn đã biết cách vẽ một tam giác, đã đến lúc để mở rộng kiến thức và tạo ra Một đối tượng 3D có thể được tạo ra từ một đa giác