■D3DXMatrixRotationY. Xoay đối tượng quanh trục Y.
■D3DXMatrixScaling. Phép tỉ lệ (thu phóng) một đỗi tượng.
■D3DXMatrixTranslation. Dịch chuyển đối tượng theo các trục.
Di chuyển đối tượng
Để di chuyển đối tượng lòng vòng trong game, bạn cần phải thực hiện phép tịnh tiến. Phép tịnh tiến sẽ tác động làm cho đối tượng di chuyển theo các trục tọa độ. Nếu bạn muốn di chuyển đối tượng sang phải chẳng hạn, bạn có thể tịnh tiến nó dọc theo trục X về
hướng dương.
Tịnh tiến các vật thểđược thực hiện thông qua hàm D3DXMatrixTranslation như dưới đây: D3DXMATRIX *D3DXMatrixTranslation( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z ); Hàm D3DXMatrixTranslation cần 4 đối số.
■pOut. Ma trận đầu ra. Con trỏđến đối tượng D3DXMATRIX.
■ x. Khoảng dịch chuyển theo trục X. Chấp nhận cả âm hoặc dương. ■y. Khoảng dịch chuyển theo trục Y.
■z. Khoảng dịch chuyển theo trục Z.
Đoạn code sau cho thấy cách sử dụng hàm D3DXMatrixTranslation
D3DXMATRIX matTranslate; D3DXMATRIX matFinal;
// Đưa ma trận matFinal về ma trận đồng nhất D3DXMatrixIdentity(&matFinal);
// tịnh tiến đối tượng 64 đơn vị về bên phải theo trục X. // Ma trận kết quả lưu vào matTranslate
D3DXMatrixTranslation(&matTranslate, 64.0f, 0.0f, 0.0f);
// Nhân ma trận tịnh tiến và ma trận đồng nhất để có ma trận biến đổi // ma trận biến đổi lưu trữ trong finalMat
D3DXMatrixMultiply(&finalMat, &finalMat, & matTranslate); // thực hiện phép biến đổi đối tượng trong không gian thực pd3dDevice->SetTransform(D3DTS_WORLD, &finalMat);
Hàm D3DXMatrixTranslation được sử dụng để tịnh tiến đối tượng 64 đơn vị về bên phải trục X. Để thực hiện phép biến đổi này với đối tượng, ta nhân ma trận tịnh tiến với ma trận đồng nhất, sau đó đối tượng được quy đổi về không gian thực.
Xoay đối tượng
Phép tịnh tiến đối tượng thật tuyệt, nhưng bạn vẫn chưa thực sự làm được những thứ mà game của bạn đòi hỏi. Sẽ còn gì là thú vị nếu như trong một trò đua xe bạn không thể
lượn chiếc xe quanh một vòng cua … bởi lý do xe của bạn chỉ có thể di chuyển trên một
đường thẳng? Đó là lý do mà bạn cần đến phép xoay. Nếu chiếc xe có khả năng xoay thì thì nó có thể ngoặt, và lượn theo các khúc cua.
Kết hợp giữa phép xoay và tịnh tiến các đối tượng 3D cho phép nhân vật của bạn có thể
di chuyển tự do trong không gian game. Phép xoay cho phép những chiếc bánh xe ô tô có thể quay, cánh tay có thể cửđộng, quả bóng chày có thể xoay tròn khi bay…
Phép xoay là một quá trình quay một đối tượng xung quanh các trục tọa độ. Bởi vì phép xoay được thực hiện thông qua ma trận, nên thư viện D3DX đã cung cấp một vài hàm hữu ich để đơn giản hóa quá trình đó.
Phép xoay có thể thực hiện trên các trục vào bất kì thời điểm nào và trên bất kì trục nào trong 3 trục tọa độ. D3DX cung cấp cho mỗi trục tọa độ một hàm xoay. Ví dụ như, nếu bạn muốn xoay đỗi tượng quanh trục X, bạn có thể dùng hàm D3DXMatrixRotationX, nhưđịnh nghĩa dưới đây: D3DXMATRIX *D3DXMatrixRotationX( D3DXMATRIX *pOut, FLOAT Angle ); Hàm D3DXMatrixRotationX chỉ có 2 đối số:
■pOut. Con trỏđến đối tượng kiểu D3DXMATRIX. Chứa ma trận trả về.
■Angle. Góc xoay đối tượng (dạng radian).
Sử dụng hàm D3DXMatrixRotationX hay bất kì gì có liên quan là rất đơn giản. Đầu tiên, ta định nghĩa một cấu trúc D3DXMATRIX chứa ma trận kết quả, sau đó đưa vào góc xoay là xong. Đoạn code sau cho thấy cách sử dụng hàm này:
D3DXMATRIX matRotate; // ma trận kết quả
D3DXMatrixRotationX(&matRotate, D3DXToRadian(45.0f)); Bạn định nghĩa một ma trận đầu ra và gọi hàm D3DXMatrixRotationX. Bạn có thể thấy, với tham số thứ hai ta đã sử dụng một lệnh trợ giúp là D3DXToRadian. Lệnh này nhận vào một góc trong khoảng 0 đên 360 độ và chuyển nó thành dạng radian. Trong ví dụ trên, góc xoay là 45 độ. Kết quả của phép xoay là một đối tượng được xoay quanh trục X 45 độ.
Hình 5.6 biểu diễn một hình hộp được xoay quanh trục Y.
Đoạn code sau cho thấy những bước cần làm để
xoay hình hộp quanh trục Y. Phép xoay sẽ thực
hiện dựa trên bộđếm thời gian và hình hộp Hình 5.6 Hình hộp được
sẽđược xoay liên tục. xoay quanh trục Y
/************************************************************************ * render * render
************************************************************************/ void render(void) void render(void)
{
// xóa back buffer về màu đen pd3dDevice->Clear( 0,
NULL,
D3DCOLOR_XRGB(255,255,255), 1.0f, 1.0f,
0 );
pd3dDevice->BeginScene(); // đặt luồng vecto
pd3dDevice->SetStreamSource( 0, vertexBuffer, 0, sizeof(CUSTOMVERTEX) ); // định dạng vecto pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); // gán meshMat về ma trận đơn vị D3DXMatrixIdentity(&objMat); // cài đặt ma trận xoay D3DXMatrixRotationY(&matRotate, timeGetTime()/1000.0f); // nhân ma trận tỉ lệ và ma trận xoay để có ma trận objMat D3DXMatrixMultiply(&finalMat, &objMat, &matRotate); // thưc hiện phép biến đổi trong không gian thực
pd3dDevice->SetTransform(D3DTS_WORLD, &finalMat); // Render hình hộp bằng kiểu triangle strips
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 4, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 8, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 12, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 16, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 20, 2 ); pd3dDevice->EndScene();
// biểu diễn ra front buffer
pd3dDevice->Present( NULL, NULL, NULL, NULL ); }
Có 3 biến được khai báo ởđầu của hàm render là objMat, matRotate, và finalMat. Những biến này là các ma trận lưu trữ thông tin về hình hộp. Phần trước bạn đã được học cách
đưa một ma trận về dạng đồng nhất , và ở đây ma trận objMat cần được làm như vậy mỗi lần hàm render được gọi. Điều đó nhằm mục đich làm cho phép xoay luôn thực hiện ở
gốc tọa độ. Như vậy objMat biểu diễn vị trí thực của hình hộp. D3DXMatrixIdentity(&objMat);
Ma trận thứ hai là matRotate, chứa thông tin về phép xoay hình hộp. Bởi vì hình hộp cần
được xoay liên tục, do đó bạn cần cập nhật mới ma trận matRotate cho mỗi lần xoay với một vị trí mới của hình hộp. Phép xoay được thực hiện thông qua D3DXMatrixRotationY, là một hàm trong thư viện D3DX. Những hàm xoay trong thư
viện D3DX sẽ viết đè thông tin trên ma trận qua mỗi lần xoay, vì thế mà bạn không cần gọi D3DXMatrixIdentity để đồng nhất hóa ma trận này.
D3DXMatrixRotationY(&matRotate, timeGetTime()/1000.0f);
Hàm timeGetTime sử dụng thời gian hiện tại và chia cho 1000.0f để xoay hình hộp trơn chu hơn.
Tóm lại, bạn có hai ma trận, một cái biểu diễn vị trí của đối tượng và cái kia biểu diễn sự
vận động của đối tượng, bạn cần nhân hai ma trận này với nhau để có được ma trận cuối cùng biểu diễn qua finalMat.
Ma trận kết quả quy đổi hình hộp về không gian thực qua hàm SetTransform dưới đây: pd3dDevice->SetTransform(D3DTS_WORLD, &finalMat);
Kết quả trả về từ SetTransform là một hình hộp được đặt ở vị trí mới và định hướng trong không gian thực. Hàm render sẽ vẽ hình hộp qua các lời gọi DrawPrimitive.
Bạn có thể tìm thấy mã nguồn về các phép xoay đối tượng trong thư mục chapter5\example2 trên đĩa CD.
Tâm của phép xoay
Tâm của phép xoay một đối tựợng phụ thuộc vào trục mà nó xoay quanh. Nếu một đối tượng, ví như hình hộp trong hình 5.6 đã xoay , tâm xoay của nó làm cho nó quay tròn xung quanh gốc tọa độ. Nếu một đối tựợng
được tịnh tiến ra xa gốc tọa độ và dọc theo một trục nào đó, thì tâm xoay của cũng dịch chuyển dọc trục đó làm cho đối tượng bị dịch chuyển sang vị trí khác trong quá trình thực hiện phép xoay.
Nhìn vào hinh 5.7, ta thấy một hình hộp được tịnh tiến dọc theo trục X và Y trước khi bị
xoay. Khi hình hộp đó
được xoay quanh trục X, thì nó cũng bị tịnh Hình 5.7: Hình hộp được xoay quanh trục X
tiến trong suốt quá trình xoay này. sau khi được tịnh tiến ra xa gốc tọa độ
Để thay đổi tâm phép xoay, bạn cần phải tịnh tiến đối tượng ra xa gốc tọa độ trước khi tiến hành phép xoay.
Đoạn code sau cho thấy cách mà tâm xoay thay đổi khi tịnh tiến đổi tượng. /************************************************************************
* render
************************************************************************/ void render(void) void render(void)
{
// xóa back buffer về màu đen pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255,255,255), 1.0f, 0 ); pd3dDevice->BeginScene();
pd3dDevice->SetStreamSource( 0, vertexBuffer, 0, sizeof(CUSTOMVERTEX) ); pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
// tịnh tiến đối tượng ra xa gốc tọa độ
D3DXMatrixTranslation(&matTranslate, 64.0f, 0.0f, 0.0f); // cài đặt phép quay
D3DXMatrixRotationY(&matRotate, timeGetTime()/1000.0f); // Nhân ma trận tịnh tiến và ma trận xoay để có ma trận objMat D3DXMatrixMultiply(&objMat, &matTranslate, &matRotate); // thực hiện phép biến đổi trong không gian thực
pd3dDevice->SetTransform(D3DTS_WORLD, &objMat); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 4, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 8, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 12, 2 );
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 16, 2 ); pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 20, 2 ); pd3dDevice->EndScene();
// đưa kết quả ra front buffer
pd3dDevice->Present( NULL, NULL, NULL, NULL ); }
Sự thay đổi lớn nhất trong hàm render là hàm D3DXMatrixTranslation. Hàm này dịch chuyển hình hộp ra xa gốc tọa độ 64 đơn vị.
Trong trường hợp này, hình hộp sẽđược tịnh tiến ra xa gôc tọa độ dọc theo trục X và sau
đó mới xoay. Hai ma trận được dùng ở đây là : matTranslate và matRotate. Hai ma trận này được nhân với nhau để có ma trận objMat, chứa vị trí sau cùng của hình hộp. Kết quả
là ta có một hình hộp được xoay ở cách xa gốc tọa độ
Phép tỉ lệ
Phép tỉ lệ cho phép bạn thay đổi kích thước đối tượng bằng cách nhân các vecto của đối tượng với một lượng nào đó. Để thực hiện phép tỉ lệ trên đối tượng, bạn cần tạo một ma trận chứa các hệ số tỉ lệ. Những hệ số này cho biết các vecto sẽ được phóng to hay thu nhỏ bao nhiêu. Nhưđã đề cập ở trên, các vị trí 1, 6, 11 là các hệ số tỉ lệ theo các phương X, Y và Z. Mặc định, các số đó là 1.0f nghĩa là các đối tượng có kích thước như nó vốn có. Thay đổi bất kì hệ số nào sẽ làm thay đổi kích thước của đối tượng. Nếu các hệ số này lớn hơn 1.0f thì đối tượng sẽ được phóng to ra, ngược lại, nếu hệ số này nhỏ hơn 1.0f thì
đối tượng sẽ bị thu nhỏ lại. ⎥ ⎥ ⎥ ⎥ ⎦ ⎤ ⎢ ⎢ ⎢ ⎢ ⎣ ⎡ 16 15 14 13 12 10 9 8 7 5 4 4 2 Z Y X
Nhưđã đề cập ở trên, phép tỉ lệ được điều khiển thông qua các giá trị trong ma trận. Để
tạo một ma trận tỉ lệ, ta chỉ cần định nghĩa một ma trận đồng nhất và thay đổi các hệ số
như đã nói ở trên. Bạn vừa có thể tự mình thay đổi các giá trị này vừa có thể sử dụng thông qua hàm D3DXMatrixScaling nhưđịnh nghĩa dưới đây:
D3DXMATRIX *D3DXMatrixScaling( D3DXMATRIX *pOut, FLOAT sx, FLOAT sy, FLOAT sz ); Hàm D3DXMatrixScaling cần 4 đối số:
■pOut. Con trỏđến đối tượng D3DXMATRIXchứa ma trận tỉ lệ
■sx. Hệ số tỉ lệ theo phương X
■sy. Hệ số tỉ lệ theo phương Y
■sz. Hệsố tỉ lệ theo phương Z
Đoạn code sau cho thấy cách dùng hàm D3DXMatrixScaling để tăng gấp đôi kích thước một vật thể.
D3DXMATRIX matScale; // đặt hệ số tỉ lệ
D3DXMatrixScaling(&matScale, 2.0f, 2.0f, 2.0f); // Nhân ma trận đối tượng với ma trận tỉ lệ
D3DXMatrixMultiply(&objMat, & objMat, &matScaling);
Biến objMat ở trên biểu diễn ma trận gốc của đối tượng. nhân ma trận của đối tượng với ma trận tỉ lệ ta sẽ có thể thu phóng đối tượng khi vẽ.
Thứ tự trong các phép tính toán ma trận
Thứ tự trong các phép toán là rất quan trọng. Ví dụ như, nếu bạn muốn xoay một đối tượng quanh tâm của nó và sau đó dịch chuyển nó đi đâu đó, thì trước tiên bạn cần tính toán với ma trận xoay trước tiếp đó là đến ma trận tịnh tiến. Nếu hai phép tính này được
đổi chỗ cho nhau, thì đối tượng sẽ được tịnh tiến đến 1 vị trí khác sau đó mới được xoay quanh gốc tọa độ. Điều này có thể làm cho đối tượng được đặt ở một ví trí khác và hướng theo một hướng khác trong không gian. Đoạn code sau chỉ ra trình tự đúng để thực hiện phép xoay và tịnh tiến đối tượng: D3DXMATRIX objRotate; D3DXMATRIX objTranslation; D3DXMATRIX objFinal; // phép xoay D3DXMatrixRotationY(&objRotate, D3DXToRadian(45)); // phép tịnh tiến D3DXMatrixTranslation(&objTranslation, 1.0f, 0.0f, 0.0f); // nhân ma trận xoay và ma trận tịnh tiến với nhau
D3DXMatrixMultiply(&objFinal, &objRotate, &objTranslation); // thực hiện phép biến đổi trong không gian thực
pd3dDevice->SetTransform(D3DTS_WORLD, &objFinal);
Bước thứ nhất là tạo ma trận xoay đối tượng, objRatate. Sử dụng hàm D3DXMatrixRotationY như trên, đối tượng sẽđược quay một góc 45 độ quanh trục Y. Tiếp theo ta tịnh tiến đối tượng đã xoay một đơn vị về bên phải bằng cách sử dụng hàm D3DXMatrixTranslation.
Cuối cùng, ta tạo ra ma trận biến đổi bằng cách nhân ma trận xoay và ma trận tịnh tiến với nhau với hàm D3DXMatrixMultiply. Nếu ma trận xoay và ma trận được đảo chỗ cho nhau (hoán vị) trong lời gọi hàm D3DXMatrixMultiply, thì phép tịnh tiến sẽ được thực hiện trước phép xoay, và đối tượng bị rời sang vị trí khác.