三维图形变换与投影

329 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

一、实验目的及要求

实验要求: 1.掌握对三维物体进行平移、旋转、放缩、错切等变换的方法; 2.掌握利用透视变换算法生成立方体的一点、两点和三点透视的方法; 3.掌握旋转立方体的透视投影图的方法。 4.良好的交互设计。

二、实验仪器设备与软件环境

Windows 7以上操作系统 Microsoft Visual Studio 2010

三、实验过程及实验结果分析

(包括实验原理、步骤、数据、图表、结果及分析。软件类实验应写出程序代码;硬件类实验画出电路原理图(或逻辑框图)、列出实验数据,并对实验结果进行分析)

主要实验步骤:

创建新项目Test; 同时添加点类,选择“添加”,添加类CP2,虚析构函数 P2.h:

class CP2
{
public:
	CP2();
	virtual ~CP2();
public:
	double x;
	double y;
	UINT rc;
};

CP3同理: P3.h :

#pragma once
#include "p2.h"
class CP3 :
	public CP2
{
public:
	CP3(void);
	virtual ~CP3();
	CP3(double,double,double);
public:
	double z;
};

P3.cpp :

#include "StdAfx.h"
#include "P3.h"
CP3::CP3()
{
	z=0.0;
}
CP3::~CP3()
{
	this->z=z;
}

颜色类: RGB.h:

#pragma once
class CRGB
{
public:
	CRGB();
	CRGB(double,double,double);
	virtual ~CRGB();
	void Normalize();
public:
	double red;
	double green;
	double blue;
};

RGB.cpp:

#include "StdAfx.h"
#include "RGB.h"


CRGB::CRGB()
{
	red=1.0;
	green=1.0;
	blue=1.0;
}

CRGB::CRGB(double r,double g,double b)
{
	red=r;
	green=g;
	blue=b;
}

CRGB::~CRGB()
{
}
Line.h:
class CLine
{
public:
	CLine();
	virtual ~CLine();
	void MoveTo(CDC *,CP2);
	void MoveTo(CDC *,double,double);
	void LineTo(CDC *,CP2);
	void LineTo(CDC *,double,double);
public:
	CP2 P0;
	CP2 P1;
};

CFace.h:

#pragma once
class CFace
{
public:
	CFace();
	virtual ~CFace();
	void SetNum(int);
public:
	int vN;
	int *vI;
};

CFace.cpp:
CFace::CFace()
{
	vI=NULL;
}


CFace::~CFace()
{
	if(vI!=NULL)
	{
		delete []vI;
		vI=NULL;
	}
}

void CFace::SetNum(int en)
{
	vN=en;
	vI=new int[vN];
}

CTestView.h:

#include"Line.h"
#include"Face.h"
#include"P3.h"

CTestview.cpp:

void CTestView::DoubleBuffer(CDC *pDC)
{
	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.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);
	rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
	DrawObject(&memDC);
	pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memDC,-rect.Width()/2,-rect.Height()/2,SRCCOPY);
	memDC.SelectObject(pOldBitmap);
	NewBitmap.DeleteObject();
}

void CTestView::DrawObject(CDC* pDC)
{
	CP2 t;
	CLine *line=new CLine;
	for(int nFace=0;nFace<6;nFace++)
	{		
		for(int nPoint=0;nPoint<F[nFace].vN;nPoint++)
		{
			PerProject(P[F[nFace].vI[nPoint]]);
			if(0==nPoint)
			{
				line->MoveTo(pDC,ScreenP);
				t=ScreenP;
			}
			else
				line->LineTo(pDC,ScreenP);
		}
		line->LineTo(pDC,t);
	}
	delete line;
}

等6个成员函数。 类视图, CTestView,类向导,虚函数, 双击OnInitialUpdate

void CTestView::OnInitialUpdate()
{
	CView::OnInitialUpdate();
	ReadPoint();
	ReadFace();
	InitParameter();
}

工具栏,资源视图Test/Icon,添加资源,Icon/导入,打开picture7文件夹,文件类型选图标文件

结果如下: 在这里插入图片描述

打开资源视图,找工具栏,Test/Toolbar/IDR_MAINFRAME,双击IDR_MAINFRAME

在这里插入图片描述

将尺寸改为32 32

在这里插入图片描述

导入图标: 在这里插入图片描述

同样方法将 在这里插入图片描述 在这里插入图片描述图标加入到工具栏中,他们的ID 分别为ID_TWOPOINT, ID_THREEPOINT, IDM_PLAY.

类视图,右击CTestView, “类向导“,命令下找到ID ID_ONTPOINT,并双击 默认使用系统分配的函数名,确认

函数OnOnepoint代码 void CTestView::OnOnepoint() { AfxGetMainWnd()->SetWindowText(CString("一点透视")); KillTimer(1); bPlay=FALSE; Phi=90; Theta=0; InitParameter(); Invalidate(FALSE); } void CTestView::OnTwopoitnt() {

AfxGetMainWnd()->SetWindowText(CString(",二点透视"));
KillTimer(1);
bPlay=FALSE;
Phi=90;
Theta=30;
InitParameter();
Invalidate(FALSE);

}

void CTestView::OnThreepoint() { AfxGetMainWnd()->SetWindowText(CString("三点透视")); KillTimer(1); bPlay=FALSE; Phi=45; Theta=45; InitParameter(); Invalidate(FALSE); }

void CTestView::OnPlay() { AfxGetMainWnd()->SetWindowText(CString(“透视")); bPlay=bPlay?FALSE:TRUE; if(bPlay) SetTimer(1,150,NULL); else KillTimer(1); }

类视图,右击TestView,选择类向导,消息/WM_TIMER 在这里插入图片描述

代码: void CTestView::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 Phi-=5; Theta-=5; InitParameter(); Invalidate(FALSE); CView::OnTimer(nIDEvent); }

编辑函数 void CTestView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if(!bPlay) { switch(nChar) { case VK_UP: Phi+=5; break; case VK_DOWN: Theta+=5; break; case VK_RIGHT: Theta-=5; break; default: break; } } CView::OnKeyDown(nChar, nRepCnt, nFlags); }

实验结果及分析: 按1: 在这里插入图片描述

按2: 在这里插入图片描述

按3: 在这里插入图片描述

按动画:

在这里插入图片描述