Direct3D研究院之通过坐标变换实现简单太阳系(六)

最近工作比较忙,好长时间没更新了,今天得闲,再来一篇。

上一章讲了坐标变换的相关知识,包括图形的平移、旋转与缩放,这一章,我将结合具体项目来讲解一下,坐标变换在实际开发中的应用。

我们拿太阳系为模型,主要实现太阳自转、地球自转、地球公转、月球自转、月球公转效果。由于现在还没有说到模型的绘制,我们现在暂时用正方体来代表三个星球。

先来看一下,在Direct3D中是如何生成平移、旋转、缩放矩阵的。

1、生成平移矩阵:

C#

1

2

D3DXMATRIX* WINAPI D3DXMatrixTranslation

    ( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z );

pOUt是最终生成的平移矩阵指针,x、y、z分别表示各方向上的移动量。

2、生成旋转矩阵:

C#

1

2

3

4

5

6

D3DXMATRIX* WINAPI D3DXMatrixRotationX

    ( D3DXMATRIX *pOut, FLOAT Angle );

D3DXMATRIX* WINAPI D3DXMatrixRotationY

    ( D3DXMATRIX *pOut, FLOAT Angle );

D3DXMATRIX* WINAPI D3DXMatrixRotationZ

    ( D3DXMATRIX *pOut, FLOAT Angle );

这三个函数分别生成绕x、y、z轴旋转的旋转矩阵。其中pOut是生成的旋转矩阵指针,Angle为旋转的角度。

3、生成缩放矩阵:

C#

1

2

D3DXMATRIX* WINAPI D3DXMatrixScaling

    ( D3DXMATRIX *pOut, FLOAT sx, FLOAT sy, FLOAT sz );

pOut为生成的缩放矩阵指针,sx、sy、sz分别为在三个坐标轴上的缩放系数。同设置不同的缩放系数可以实现一些特殊效果。

将要实现的简单太阳系就是通过这一系列的有序组合实现的。我们分别为太阳、地球、月球进行设置。

设置太阳:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

void SetSunMatrix()

{

//世界变换

D3DXMATRIX matWorld;

D3DXMatrixIdentity(&matWorld);

 

//自转

D3DXMatrixRotationY(&matWorld, (timeGetTime() % 50000) * (2.0f * D3DX_PI) / 50000.0f);

g_pDevice->SetTransform(D3DTS_WORLD, &matWorld);

 

//观察变换

D3DXVECTOR3 eyePos(0.0f, 10.0f, -20.0f);

D3DXVECTOR3 lookatPos(0.0f, 0.0f, 1.0f);

D3DXVECTOR3 updir(0.0f, 1.0f, 0.0f);

 

D3DXMATRIX matView;

D3DXMatrixLookAtLH(&matView, &eyePos, &lookatPos, &updir);

g_pDevice->SetTransform(D3DTS_VIEW, &matView);

 

//投影变换

D3DXMATRIX matProj;

D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);

g_pDevice->SetTransform(D3DTS_PROJECTION, &matProj);

}

在此方法中首先进行了世界变换,也就是我们的太阳自转操作,然后是观察、投影的变换。在声明一个矩阵后,调用函数D3DXMatrixIdentity在将矩阵转换为单位矩阵(矩阵左上角到右下角这条对角线上的值为1,其他值为0的矩阵)以防止意外操作产生的不利影响。在世界变换中实现太阳的自转此处设置y轴为太阳中心轴,角速度由系统时间得出。设置观察变换,主要需要三个向量:眼睛的位置、所观察的位置、眼睛摆放向上方向。

C#

1

2

3

D3DXMATRIX* WINAPI D3DXMatrixLookAtLH

    ( D3DXMATRIX *pOut, CONST D3DXVECTOR3 *pEye, CONST D3DXVECTOR3 *pAt,

      CONST D3DXVECTOR3 *pUp );

此方法生成观察变换矩阵(此处为左手坐标系),pOut为生成的观察矩阵指针,pEye为眼睛的摆放位置指针,pAt为观察的点的指针,pUp为眼睛摆放的向上方向指针。

C#

1

2

D3DXMATRIX* WINAPI D3DXMatrixPerspectiveFovLH

    ( D3DXMATRIX *pOut, FLOAT fovy, FLOAT Aspect, FLOAT zn, FLOAT zf );

此方法生成投影变换矩阵(此处为左手坐标系),pOut为生成的投影变换矩阵指针,fovy为在y轴方向看到的最大范围(弧度),Aspect为视区宽度与高度的比例,zn为近裁剪面的z值,zf为远裁剪面的z值,这样就形成一个近小远大的台体,我们所看到的一切就都在这个台体中。

设置地球:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

void SetEarthMatrix()

{

D3DXMATRIXA16 matWorld;

D3DXMATRIX matTran;

D3DXMATRIX matRot0;

D3DXMATRIX matRot1;

D3DXMATRIX matScal;

 

D3DXMatrixIdentity(&matWorld);

D3DXMatrixIdentity(&matTran);

D3DXMatrixIdentity(&matRot0);

D3DXMatrixIdentity(&matRot1);

D3DXMatrixIdentity(&matScal);

 

//缩放

D3DXMatrixScaling(&matScal, 0.5f, 0.5f, 0.5f);

//自转

D3DXMatrixRotationY(&matRot0,2*D3DX_PI*(timeGetTime()%2000)/2000);

//平移到轨道位置

D3DXMatrixTranslation(&matTran,5,0,0);

//在轨道上绕太阳公转

D3DXMatrixRotationY(&matRot1,2*D3DX_PI*(timeGetTime()%10000)/10000);

 

matWorld = matScal * matRot0 * matTran * matRot1;

g_pDevice->SetTransform( D3DTS_WORLD, &matWorld );

}

设置月球:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

void SetMoonMatrix()

{

D3DXMATRIXA16 matWorld;

D3DXMATRIX matTran0;

D3DXMATRIX matTran1;

D3DXMATRIX matRot0;

D3DXMATRIX matRot1;

D3DXMATRIX matRot2;

D3DXMATRIX matScal;

 

D3DXMatrixIdentity(&matWorld);

D3DXMatrixIdentity(&matTran0);

D3DXMatrixIdentity(&matTran1);

D3DXMatrixIdentity(&matScal);

D3DXMatrixIdentity(&matRot0);

D3DXMatrixIdentity(&matRot1);

D3DXMatrixIdentity(&matRot2);

 

//缩放

D3DXMatrixScaling(&matScal, 0.125f, 0.125f, 0.125f);

//自转

D3DXMatrixRotationY(&matRot0, 2*D3DX_PI*(timeGetTime()%1000)/1000);

//相对地球,平移到绕地球轨道

D3DXMatrixTranslation(&matTran0,2,0,0);

//绕地球公转

D3DXMatrixRotationY(&matRot1,2*D3DX_PI*(timeGetTime()%1000)/1000);

//相对太阳平移

D3DXMatrixTranslation(&matTran1,5,0,0);

//绕太阳公转

D3DXMatrixRotationY(&matRot2,2*D3DX_PI*(timeGetTime()%10000)/10000);

 

matWorld = matScal * matRot0 * matTran0 * matRot1 * matTran1 * matRot2;

 

g_pDevice->SetTransform(D3DTS_WORLD,&matWorld);

}

对地球和月球的设置,主要注意各种矩阵变换的顺序,在这里,矩阵变换的组合操作由矩阵相乘得到,操作的顺序由左向右,需要清楚的一点事,矩阵相乘不支持交换律。当然也可以使用函数D3DXMatrixMultiply数做乘法运算,原型如下:

C#

1

2

D3DXMATRIX* WINAPI D3DXMatrixMultiply

    ( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM1, CONST D3DXMATRIX *pM2 );

pOut为得到的矩阵指针,pM1、pM2为待处理矩阵,两者按顺序相乘(本人比较喜欢使用a*b的形式,书写起来更方便一些)。

然后说一下视区变换,

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

void SetViewPort()

{

RECT rect;

GetClientRect(g_hwnd, &rect);

D3DVIEWPORT9 vp;

ZeroMemory(&vp, sizeof(vp));

vp.X = 0;

vp.Y = 0;

vp.Width = rect.right;

vp.Height = rect.bottom;

vp.MinZ = 0.0f;

vp.MaxZ = 1.0f;

g_pDevice->SetViewport(&vp);

}

视区变换通过函数SetViewport实现,它只有一个参数,就是一个D3DVIEWPORT9结构体的指针,D3DVIEWPORT9中的属性含义:X为视区左上角x坐标,Y为视区左上角y坐标,Width为视区的宽度,Height为视区的高度,MinZ为视区内物体的最小深度值,MaxZ为视区内物体的最大深度值。

在绘制图形的时候,要先执行变换操作,再进行绘制。

运行程序,我们将看到如图效果:

 

好,到这里,简单的太阳系就做好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值