Introduction
About 3D Transformations
While displaying 3D objects on 2D, we have to convert the 3D Coordinates to corresponding 2D
coordinates. Let us call it as projections. To create projections we have to do
some sort of Vector Algebra.
Background
Basically there are many types of projections; here we are
referring only two types of projections
- Orthographic Projections
In Orthographic projections, Projection P (x’, y’) on the 3D Point A(x, y, z) is computed as follows.
x'=|Amag| *(Wx(.)A.Unitvector ());
y’=|Amag|*(Wy(.)A.UnitVector ());
Where Wx= [1 0 0]
& Wy= [0 1 0]
& (.) is the dot product of Vectors.
Basically Wx &Wy are the Unit Vectors.
- Perspective Projections
There are Three Types of Perspective Projections.
- Single Point Perspective.
- Two Point Perspective.
- Three Point Perspective.
Here we are discussing only Single Point perspective. The Perspective Projection is calculated by Matrix Multiplication.
X’=X/(rz+1);
Y’=Y/(rz+1);
Where r= -1/Zc
& Zc is the Distance at Z Direction from the Viewing Point.
Using the code
Compile and Build the code Provided with this article.
class C3DCanvas : public CDC
{
CBitmap m_bitmap; CBitmap* m_oldBitmap; CDC* m_pDC; CRect m_rect; BOOL m_bMemDC;
CPen m_penWhite;
CPen *m_oldPen;
C3DVector W_X; C3DVector W_Y; C3DVector W_Z; 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);
m_pDC = pDC;
m_oldBitmap = NULL;
m_bMemDC = !pDC->IsPrinting();
if (pRect == NULL) {
pDC->GetClipBox(&m_rect);
} else {
m_rect = *pRect;
}
if (m_bMemDC) {
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 {
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
FillSolidRect(m_rect, 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) {
m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
this, m_rect.left, m_rect.top, SRCCOPY);
SelectObject(m_oldBitmap);
SelectObject(m_oldPen);
m_penWhite.DeleteObject();
} else {
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); 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);
}
Enjoy 3D Vector Graphics.