1 实验目的
1)掌握4*4矩阵乘法运算的编程实现。
2)掌握平移、比例、旋转三种基本三维几何变换矩阵生成。
3)掌握正交投影图的生成和绘制方法。
2 实验要求
1)三维坐标系的原点位于屏幕中心,X轴水平向右,Y轴垂直向上,Z轴垂直于坐标屏幕,指向屏幕外。
2)设计实现三维图形变换类,具有平移、比例、旋转三维几何变换功能,以及正交投影变换功能。
3)使用第二章的直线类绘制正四面体的是三维线框模型,要求体心位于坐标原点,使正四面体同时绕Y轴匀速旋转,并相对于体心点来回缩放。
4)使用双缓冲机制,绘制正四面体三维线框模型的二维正交投影图,要求投影到XOY平面。
3 详细设计
3.1 核心算法及类型设计
void CTrans3DView::BuildPointEdge()
{
double d=400;
P[0].x=d/2; P[0].y=d/2; P[0].z=d/2;
P[1].x=d/2; P[1].y=-d/2; P[1].z=-d/2;
P[2].x=-d/2; P[2].y=-d/2; P[2].z=d/2;
P[3].x=-d/2; P[3].y=d/2; P[3].z=-d/2;
E[0].SetPointsIndex(0,1);
E[1].SetPointsIndex(0,2);
E[2].SetPointsIndex(0,3);
E[3].SetPointsIndex(1,2);
E[4].SetPointsIndex(1,3);
E[5].SetPointsIndex(2,3);
}
void CTrans3DView::OnDraw(CDC*pDC)
{
CTrans3DDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(),rect.Height());
pDC->SetViewportExt(rect.Width(),-rect.Height());
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);
//双缓冲机制
CDC MemDC;
CBitmap NewBitmap,*pOldBitmap;
MemDC.CreateCompatibleDC(pDC);
NewBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height()); //兼容位图
pOldBitmap = MemDC.SelectObject(&NewBitmap); //将兼容位图选入MemDc
MemDC.FillSolidRect(rect,pDC->GetBkColor());
MemDC.SetMapMode(MM_ANISOTROPIC);
MemDC.SetWindowExt(rect.Width(),rect.Height());
MemDC.SetViewportExt(rect.Width(),-rect.Height());
MemDC.SetViewportOrg(rect.Width()/2,rect.Height()/2);
Line *line = new Line; //动态创建直线绘制类对象
//绘制坐标轴
line->SetLineColor(RGB(0,0,0));
line->MoveTo(CP2(-rect.Width()/2,0)); //X轴
line->LineTo(CP2(rect.Width()/2,0),&MemDC);
line->MoveTo(CP2(0,-rect.Height()/2)); //Y轴
line->LineTo(CP2(0,rect.Height()/2),&MemDC);
//旋转、缩放、正交投影变换
CTrans3 tans;
tans.SetPoints(P,4);
//在0.5~2.0之间缩放
static double s = 1.0;
static double step = 0.01;
if(s>=2.0 || s<=0.5)
step = -step;
s += step;
tans.Scale(s,s,s);
//绕Y轴匀速逆时针旋转
static float theta = 0.0;
theta += 1.0;
if (theta > 360)
theta = 0.0; tans.RotateY(theta); //二维正交投影 tans.ProjXOY();
//绘制动态旋转和缩放的四面体 for (int i=0; i<6; i++) { line->SetLineColor(RGB (0,255,0));
line->MoveTo(tans.m_p2Screen[E[i].Start]); line->LineTo(tans.m_p2Screen[E[i].End],&MemDC);
}
delete line;
//将内存位图拷贝到屏幕
pDC ->BitBlt(-rect.Width()/2,-rect.Height()/2,rect.Width(),rect.Height(),&MemDC,-rec t.Width()/2,-rect.Height()/2,SRCCOPY );
MemDC.SelectObject(pOldBitmap); NewBitmap.DeleteObject(); Invalidate(FALSE );
}
3.2 程序设计实现及流程图
平移变换矩阵
⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢
⎢⎣⎡=1010
000100001z y
x
t t t t T 绕x ,y ,z 旋转变换矩阵
⎥⎥⎥⎥⎦
⎤⎢
⎢⎢
⎢⎣⎡-=010
00
0cos sin 00sin cos 000
01
ααααrx T ⎥⎥⎥⎥⎦
⎤⎢⎢⎢
⎢⎣⎡-=10
0cos 0sin 0100sin 0cos ααα
αry T
⎥⎥
⎥⎥⎦
⎤⎢⎢⎢
⎢⎣⎡-=100
01000cos sin 00sin cos ααααrz T 比例变换矩阵
⎥⎥⎥⎥⎦
⎤⎢⎢⎢
⎢⎣⎡=10
00
000000000z y x s S S S T 流程图:
4 典型测试结果
5 实验问题总结
通过这次试验让我知道了要实现三维图形几何变换主要还是依靠二位图形几何变换的变换矩阵,包括平移变换矩阵,绕X、Y、Z旋转变换矩阵,比例变换矩阵,正交投影变换矩阵。
通过这几个变换矩阵相乘即可可到三维图形最终的变换矩阵,将其与原来的矩阵做一次相乘即可得到最终矩阵。
透视投影变换的过程分为两步:从世界坐标系到观察坐标系的观察变换;从观察坐标系到屏幕坐标系的透视变换。
观察变换和透视变换也分别通过一个变换矩阵实现。