3D坐标变换之自转公转

原文地址:http://www.xuanyusong.com/archives/1353

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

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

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

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

1、生成平移矩阵:

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

2、生成旋转矩阵:

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

3、生成缩放矩阵:

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

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

设置太阳:

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

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

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

设置地球:

设置月球:

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

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

然后说一下视区变换,

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

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

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


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

本文仅供参考,如有不足,还望赐教,大家共同学习进步。

ZXGoto祝大家编程愉快


matlab编程,太阳地球月亮公转自转,球体贴图,基于matlab的仿真,实现了太阳的自转以及地球月球的自转公转。 k=6; n = 2^k-1; [x,y,z]=sphere(n ); A = imread('taiyang.png'); patches0=surf2patch(x,y,z,A); k=6; n = 2^k-1; [x,y,z]=sphere(n ); AA = imread('diqiu00.png'); patches1=surf2patch(x,y,z,AA); k=6; n = 2^k-1; [x,y,z]=sphere(n ); AAA = imread('yueqiu.png'); patches2=surf2patch(x,y,z,AAA); %set(patches,'edgecolor','none') % 设计太阳月亮地球的相对大小 Ssun=1; Searth=0.4; Smoon=0.2; % 设置太阳与地球间的距离 Res=4; % 设置地球与月亮之间的距离 Rme=1; alpha=0; beta=0; theta=0; % 设置旋转速度 step_a=0.1; %a的步长 step_b=0.2; %b的步长 step_t=0.05; %c的步长 % 设置太阳的位置 Csun=[0,0,0]; % 计时器 time=0; h=figure; % 取消坐标轴之类的属性 set(h,'toolbar','none','menubar','none','numbertitle','off') % 进入大循环 while 1==1 clf % 设置地球的位置 Cx=4*cos(alpha); Cy=4*sin(alpha); Cz=0; Cearth=[Cx,Cy,Cz]; Cmoon=[Cx+cos(2*alpha);Cy+sin(2*alpha);0;1]; patches_sun=patches0; % 绕z轴旋转坐标公式 Rz=[cos(5*theta) -sin(5*theta) 0;sin(5*theta) cos(5*theta) 0;0 0 1]; [len]=64*64; for i=1:len P=Rz*[patches0.vertices(i,1);patches0.vertices(i,2);patches0.vertices(i,3)]; patches_sun.vertices(i,1)=P(1); patches_sun.vertices(i,2)=P(2); patches_sun.vertices(i,3)=P(3); end patch(patches_sun),shading flat,hold on patches_moon=patches2; [len,t]=size(patches2.vertices); for i=1:len P=Rz*[patches2.vertices(i,1)*Smoon;patches2.vertices(i,2)*Smoon;patches2.vertices(i,3)*Smoon]+[Cmoon(1);Cmoon(2);Cmoon(3)]; patches_moon.vertices(i,1)=P(1); patches_moon.vertices(i,2)=P(2); patches_moon.vertices(i,3)=P(3); end patch(patches_moon),shading flat % 与改变太阳顶点值一致,改变地球的顶点值 patches_earth=patches1; [len,t]=size(patches1.vertices); for i=1:len P=Rz*[patches1.vertices(i,1)*Searth;patches1.vertices(i,2)*Searth;patches1.vertices(i,3)*Searth]+[Cx;Cy;Cz]; patches_earth.vertices(i,1)=P(1); patches_earth.vertices(i,2)=P(2); patches_earth.vertices(i,3)=P(3); end patch(patches_earth),shading flat daspect([1,1,1]); campos([7,7,2]),camtarget([0,0,0]),camup([0,0,1]),camva(30), % 关闭所有的坐标轴标签、刻度、背景 axis off %set(patches,'edgecolor','none') % 暂停0.1秒 pause(0.1) % 记时+1 time=time+1; % 太阳地球月亮一次改变的数值 beta=beta+step_b; alpha=alpha+step_a; theta=theta+step_t; end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值