65.9K
CodeProject 正在变化。 阅读更多。
Home

3D 向量图形类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (4投票s)

2012 年 5 月 29 日

CPOL
viewsIcon

14695

downloadIcon

9

3D 向量图形类。

引言

关于 3D 变换

在 2D 屏幕上显示 3D 对象时,我们需要将 3D 坐标转换为相应的 2D 坐标。我们称之为投影。为了创建投影,我们需要进行一些向量代数运算。

背景 

基本上有很多类型的投影;在这里我们只涉及两种类型的投影。

  1. 正交投影
  2. 在正交投影中,3D 点 A(x, y, z) 在投影 P(x', y') 上的计算如下。

    x'=|Amag| *(Wx(.)A.Unitvector ());
    y’=|Amag|*(Wy(.)A.UnitVector ());

    其中 Wx= [1 0 0]

    & Wy= [0 1 0]

    & (.) 是向量的点积。

    基本上 Wx &Wy 是单位向量。

  3. 透视投影
  4. 透视投影有三种类型。

    1. 单点透视。
    2. 两点透视。
    3. 三点透视。

在这里我们只讨论单点透视。透视投影是通过矩阵乘法计算的。

X’=X/(rz+1);
Y’=Y/(rz+1);

其中 r= -1/Zc

& Zc 是从视点到 Z 方向的距离。

使用代码

编译并构建本文提供的代码。

class C3DCanvas : public CDC  
{
	CBitmap		m_bitmap;		// Offscreen bitmap
	CBitmap*	m_oldBitmap;	// bitmap originally found in CMemDC
	CDC*		m_pDC;			// Saves CDC passed in constructor
	CRect		m_rect;			// Rectangle of drawing area.
	BOOL		m_bMemDC;
	CPen        m_penWhite;
	CPen        *m_oldPen;
	C3DVector   W_X;//(1,0,0);//Unit Vector for X Axis
	C3DVector   W_Y;//(0,1,0);//Unit Vector for Y Axis
	C3DVector   W_Z;//(0,0,1);//Unit Vector for Z Axis
	C3DVector   m_org;

	int m_winOrgX;
	int m_winOrgY;
	BOOL m_bPerpective;
public:
	C3DVector   m_camera;
	void SetCamera(double dx,double dy,double dz);
	void SetWindowOrg(int x,int y);
	void SetViewPortOrg(C3DVector v);
	void TranslateView(C3DVector v);
	void RotateView(float Angle,AXIS axis);
	void Line3D(C3DVector  P,C3DVector Q);
	void EnablePerspectiveView(BOOL bSet=TRUE)
	{
		m_bPerpective=bSet;
	}
	C3DCanvas(CDC* pDC, const CRect* pRect = NULL,COLORREF m_clrBkColor=0xffffff)
		:CDC(),
		W_X(1,0,0),
		W_Y(0,1,0),
		W_Z(0,0,1),
		m_org(0,0,0),
		m_winOrgX(0),
		m_winOrgY(0),
		m_camera(0,0,1000)
	{
		m_bPerpective=FALSE;
		ASSERT(pDC != NULL); 
		
		// Some initialization
		m_pDC = pDC;
		m_oldBitmap = NULL;
		m_bMemDC = !pDC->IsPrinting();

		// Get the rectangle to draw
		if (pRect == NULL) {
			pDC->GetClipBox(&m_rect);
		} else {
			m_rect = *pRect;
		}

		if (m_bMemDC) {
			// Create a Memory DC
			CreateCompatibleDC(pDC);
			pDC->LPtoDP(&m_rect);
			
			m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
			m_oldBitmap = SelectObject(&m_bitmap);
			
			SetMapMode(pDC->GetMapMode());

			SetWindowExt(pDC->GetWindowExt());
			SetViewportExt(pDC->GetViewportExt());

			pDC->DPtoLP(&m_rect);
			SetWindowOrg(m_rect.left, m_rect.top);
		} else {
			// Make a copy of the relevent parts of the current DC for printing
			m_bPrinting = pDC->m_bPrinting;
			m_hDC       = pDC->m_hDC;
			m_hAttribDC = pDC->m_hAttribDC;
		}

		// Fill background 
		FillSolidRect(m_rect, /*pDC->GetBkColor()*/m_clrBkColor);
		m_penWhite.CreatePen(PS_SOLID,1,RGB(255,255,255));
		m_oldPen=SelectObject(&m_penWhite);
		SetTextColor(RGB(255,255,255));
		
	}
	~C3DCanvas()
	{
		if (m_bMemDC) {
			// Copy the offscreen bitmap onto the screen.
			
			m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
				this, m_rect.left, m_rect.top, SRCCOPY);		
			//Swap back the original bitmap.
			SelectObject(m_oldBitmap);
			SelectObject(m_oldPen);
			m_penWhite.DeleteObject();
		} else {
			// All we need to do is replace the DC with an illegal value,
			// this keeps us from accidently deleting the handles associated with
			// the CDC that was passed to the constructor.			
			m_hDC = m_hAttribDC = NULL;
		}	
	}

	C3DVector ToPerspectiveView(C3DVector v, double z);
};

//

void C3DCanvas::Line3D(C3DVector P, C3DVector Q)
{
	int x1,y1,x2,y2;
	P=P-m_org;
	Q=Q-m_org;
	double r=1;
	
	if(m_bPerpective)
	{
		P=ToPerspectiveView(P,m_camera.Magnetude());
		Q=ToPerspectiveView(Q,m_camera.Magnetude());
	}
	
	double dMag1=P.Magnetude();
	x1=(int)( ( ( dMag1 ) * ( P.UnitVector() * W_X ) ) )-m_winOrgX;
	y1=(int)( ( ( dMag1 ) * ( P.UnitVector() * W_Y ) ) )-m_winOrgY;
	
	double dMag2=Q.Magnetude();
	x2=(int)( ( ( dMag2 ) * ( Q.UnitVector() * W_X) ) )-m_winOrgX;
	y2=(int)( ( ( dMag2 ) * ( Q.UnitVector() * W_Y) ) )-m_winOrgY;
	
	MoveTo(x1,y1);
	LineTo(x2,y2);
}

C3DVector C3DCanvas::ToPerspectiveView(C3DVector v, double z)
{
	double r=0;
	
	r=-1/z;
	v.m_x=v.m_x/((r*v.m_z)+1);
	v.m_y=v.m_y/((r*v.m_z)+1);
	v.m_z=v.m_z/((r*v.m_z)+1);
	
	return v;
}

void CMy3DTransformationsView::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	CRect rectClient ;
	GetClientRect(rectClient);
	C3DCanvas canvas(&dc,&rectClient,RGB(0,0,0));
	C3DVector v(-x1,-y1,-z1);
	canvas.SetViewPortOrg(v);
	canvas.EnablePerspectiveView(TRUE);
	canvas.SetCamera(0,0,1650);
	canvas.m_camera.Rotate(x,X_AXIS);
	canvas.m_camera.Rotate(y,Y_AXIS);
	canvas.m_camera.Rotate(z,Z_AXIS);
	canvas.SetWindowOrg(-600,-300);
	C3DVector v1(0,-300,0),v2(0,300,0);
	CPen pen1(PS_DASHDOT,1,RGB(255,0,0));
	CPen *oldPen=canvas.SelectObject(&pen1);
	v1.Rotate(x,X_AXIS);
	v1.Rotate(y,Y_AXIS);
	v1.Rotate(z,Z_AXIS);
	v2.Rotate(x,X_AXIS);
	v2.Rotate(y,Y_AXIS);
	v2.Rotate(z,Z_AXIS);
	canvas.Line3D(v1,v2);
	canvas.SelectObject(oldPen);
	
	CPen pen2(PS_DASHDOT,1,RGB(0,255,0));
	C3DVector v3(-300,0,0),v4(300,0,0);
	v3.Rotate(x,X_AXIS);
	v3.Rotate(y,Y_AXIS);
	v3.Rotate(z,Z_AXIS);
	v4.Rotate(x,X_AXIS);
	v4.Rotate(y,Y_AXIS);
	v4.Rotate(z,Z_AXIS);
	oldPen=canvas.SelectObject(&pen2);
	canvas.Line3D(v3,v4);
	canvas.SelectObject(oldPen);

	CPen pen3(PS_DASHDOT,1,RGB(0,0,255));
	C3DVector v5(0,0,-300),v6(0,0,300);
	v5.Rotate(x,X_AXIS);
	v5.Rotate(y,Y_AXIS);
	v5.Rotate(z,Z_AXIS);
	v6.Rotate(x,X_AXIS);
	v6.Rotate(y,Y_AXIS);
	v6.Rotate(z,Z_AXIS);
	oldPen=canvas.SelectObject(&pen3);
	canvas.Line3D(v5,v6);
	canvas.SelectObject(oldPen);
	CPen pen4(PS_SOLID,1,RGB(122,255,255));
	oldPen=canvas.SelectObject(&pen4);

	C3DVector vect[8];

	vect[0].m_x=50;
	vect[0].m_y=50;
	vect[0].m_z=50;

	vect[1].m_x=250;
	vect[1].m_y=50;
	vect[1].m_z=50;

	vect[2].m_x=50;
	vect[2].m_y=250;
	vect[2].m_z=50;
	
	vect[3].m_x=250;
	vect[3].m_y=250;
	vect[3].m_z=50;
	
	vect[4].m_x=250;
	vect[4].m_y=250;
	vect[4].m_z=250;
	
	vect[5].m_x=50;
	vect[5].m_y=250;
	vect[5].m_z=250;
	
	vect[6].m_x=250;
	vect[6].m_y=50;
	vect[6].m_z=250;

	vect[7].m_x=50;
	vect[7].m_y=50;
	vect[7].m_z=250;
	for(int i=0;i<8;i++)
	{	vect[i].Rotate(x,X_AXIS);
		vect[i].Rotate(y,Y_AXIS);
		vect[i].Rotate(z,Z_AXIS);
	}
	canvas.Line3D(vect[0],vect[1]);
	canvas.Line3D(vect[2],vect[0]);
	canvas.Line3D(vect[3],vect[1]);
	canvas.Line3D(vect[3],vect[2]);
	canvas.Line3D(vect[3],vect[4]);
	canvas.Line3D(vect[5],vect[4]);
	canvas.Line3D(vect[5],vect[2]);
	canvas.Line3D(vect[4],vect[6]);
	canvas.Line3D(vect[7],vect[6]);
	canvas.Line3D(vect[7],vect[0]);
	canvas.Line3D(vect[7],vect[5]);
	canvas.Line3D(vect[6],vect[1]);
	canvas.SelectObject(oldPen);
}

享受 3D 向量图形。

© . All rights reserved.