MFC实现三维图像绘制(2)投影变换

将三维物体投影到二维平面需要考虑投影变换,分为三步,即照相机变换,投影变换和视口变换。

照相机变换:考虑到照相机和物体相对静止,故将照相机规范化为(1)放在坐标原点 (2)看向负z轴 (3)向上的方向为Y正向。此过程中物体做相同运动,则看到的效果与变换前一致。

投影变换:分为正交投影和透视投影,此处具体算法的实现主要参考闫令琪老师的课程GAMES101-现代计算机图形学入门-闫令琪

视口变换:将物体规范化投影到屏幕上。

类的设计如下:(此处需要用到CVector3类,即向量类的相关运算)

#pragma once
#include "P3.h"
#include "Vector3.h"
#include "ModelTransform3.h"
class CViewingTranformation
{
public:
	CViewingTranformation(void);
	virtual ~CViewingTranformation(void);
	void SetCamera(CP3 p);//设置照相机的位置(可以是直角坐标,也可以是球坐标)
	void ChangeCameraPos(int dx, int dy, int dz);//改变照相机位置
	void ChangeLookAtDir(int theta);//改变照相机看向的方向
	void ChangeUpDirection(int theta);//改变照相机看向的方向
	CP3 GetCamera(void);//读取视点照相机的信息;
	CP3 RviewTview(CP3 WorldPoint);//照相机变到原点
	CP3 TransportTrans(CP3 ViewPoint,int scale);//将图移到原点进行规范化
	CVector3 GetLookAtDir(void);//读取照相机看向的方向
	CP3 OrthogonalProjection(CP3 WorldPoint);//正交投影 :计算三维点投影后的点坐标
	CP3 PerspectiveProjection(CP3 WorldPoint);//透视投影:计算三维点投影后的点坐标
public:
	//照相机的描述;  
	CP3 EyePoint;//照相机的位置;
	CVector3 LookAtDir;//照相机看向的方向;
	CVector3 UpDirection;//照相机向上的方向;
	CModelTransform3 tran;
	//正交投影视上下左右面
	double  l, r, t, b;//长方体左右上下面的位置
	//视景锥的描述:
	double fovY;
	double aspect;//宽纵比(可以看成是映射成的长方体的近平面的宽高比)
	double n, f;//近平面,原平面
};


具体代码实现如下:

#include "pch.h"
#include "ViewingTranformation.h"
#define PI 3.1415926

CViewingTranformation::CViewingTranformation(void) {
	EyePoint.x = 0;EyePoint.y = 0;EyePoint.z = 15;
	LookAtDir = CVector3(0, 0, -1);
	UpDirection = CVector3(0, 1, 0);;
	f = -1000;n = -6;
	fovY = 90 * PI / 180;
	aspect = 3;
	t = tan(fovY / 2) * -n; b = -t;
	r = aspect * t; l = -r;
}

CViewingTranformation::~CViewingTranformation(void) {

}

void CViewingTranformation::ChangeCameraPos(int dx, int dy, int dz) {
	EyePoint.x += dx;
	EyePoint.y += dy;
	EyePoint.z += dz;
}

void CViewingTranformation::ChangeLookAtDir(int theta) {
	double the = theta * PI / 180;
	double Newx = cos(the) * LookAtDir.x + sin(the) * LookAtDir.z;
	double Newz = -sin(the) * LookAtDir.x + cos(the) * LookAtDir.z;
	LookAtDir.x = Newx;
	LookAtDir.z = Newz;
}

void CViewingTranformation::ChangeUpDirection(int theta) {
	double the = theta * PI / 180;
	double Newx = cos(the) * UpDirection.z - sin(the) * UpDirection.y;
	double Newz = sin(the) * UpDirection.z + cos(the) * UpDirection.y;
	UpDirection.z = Newx;
	UpDirection.y = Newz;
}

void CViewingTranformation::SetCamera(CP3 p) {
	this->EyePoint = p;
}

CVector3 CViewingTranformation::GetLookAtDir(void)
{
	// TODO: 在此处添加实现代码.
	return this->LookAtDir;
}

CP3 CViewingTranformation::GetCamera(void) {
	CP3 Point;
	Point = EyePoint;
	return Point;
}

CP3 CViewingTranformation::RviewTview(CP3 WorldPoint)
{
	// TODO: 在此处添加实现代码.
	WorldPoint.x = WorldPoint.x - EyePoint.x * WorldPoint.w;
	WorldPoint.y = WorldPoint.y - EyePoint.y * WorldPoint.w;
	WorldPoint.z = WorldPoint.z - EyePoint.z * WorldPoint.w;
	CP3 ViewPoint;

	double M[4][4];
	CVector3 u, v, w;
	u = CrossProduct(LookAtDir, UpDirection);
	u.Normalize();
	w = UpDirection.Normalize();
	v = CrossProduct(w, u);
	M[0][0] = u.x;M[0][1] = u.y;
	M[0][2] = u.z;M[0][3] = 0;
	M[1][0] = w.x;M[1][1] = w.y;M[1][2] = w.z;M[1][3] = 0;
	M[2][0] = -v.x;M[2][1] = -v.y;M[2][2] = -v.z;M[2][3] = 0;
	M[3][0] = 0;M[3][1] = 0;M[3][2] = 0;M[3][3] = 1;

	M[0][0] = LookAtDir.y * UpDirection.z - LookAtDir.z * UpDirection.y;M[0][1] = LookAtDir.z * UpDirection.x - LookAtDir.x * UpDirection.z;
	M[0][2] = LookAtDir.x * UpDirection.y - LookAtDir.y * UpDirection.x;M[0][3] = 0;
	M[1][0] = UpDirection.x;M[1][1] = UpDirection.y;M[1][2] = UpDirection.z;M[1][3] = 0;
	M[2][0] = -LookAtDir.x;M[2][1] = -LookAtDir.y;M[2][2] = -LookAtDir.z;M[2][3] = 0;
	M[3][0] = 0;M[3][1] = 0;M[3][2] = 0;M[3][3] = 1;

	ViewPoint.x = M[0][0] * WorldPoint.x + M[0][1] * WorldPoint.y + M[0][2] * WorldPoint.z + M[0][3] * WorldPoint.w;
	ViewPoint.y = M[1][0] * WorldPoint.x + M[1][1] * WorldPoint.y + M[1][2] * WorldPoint.z + M[1][3] * WorldPoint.w;
	ViewPoint.z = M[2][0] * WorldPoint.x + M[2][1] * WorldPoint.y + M[2][2] * WorldPoint.z + M[2][3] * WorldPoint.w;
	ViewPoint.w = M[3][0] * WorldPoint.x + M[3][1] * WorldPoint.y + M[3][2] * WorldPoint.z + M[3][3] * WorldPoint.w;
	ViewPoint.c = WorldPoint.c;
	return ViewPoint;
}


CP3 CViewingTranformation::OrthogonalProjection(CP3 WorldPoint) {

	WorldPoint.x = 2 * (WorldPoint.x - (-1.0) * (r + l) * WorldPoint.w / 2) / (r - l);
	WorldPoint.y = 2 * (WorldPoint.y - (-1.0) * (t + b) * WorldPoint.w / 2) / (t - b);
	WorldPoint.z = 2 * (WorldPoint.z - (-1.0) * (n + f) * WorldPoint.w / 2) / (n - f);
	//WorldPoint = TransportTrans(WorldPoint);

	return WorldPoint;
}


CP3 CViewingTranformation::PerspectiveProjection(CP3 WorldPoint) {

	CP3 ViewPoint;
	
	ViewPoint.x = n * WorldPoint.x;
	ViewPoint.y = n * WorldPoint.y;
	ViewPoint.z = (n + f) * WorldPoint.z - (1.0) * n * f * WorldPoint.w;
	ViewPoint.w = WorldPoint.z;
	ViewPoint.c = WorldPoint.c;
	CP3 ScreenPoint = OrthogonalProjection(ViewPoint);
	
	ScreenPoint.x = ScreenPoint.x / ScreenPoint.w;
	ScreenPoint.y = ScreenPoint.y / ScreenPoint.w;
	ScreenPoint.z = ScreenPoint.z / ScreenPoint.w;
	ScreenPoint.w = ScreenPoint.w / ScreenPoint.w;

	return ScreenPoint;
}

CP3 CViewingTranformation::TransportTrans(CP3 ViewPoint,int scale) {
	CP3 ViewportPoint;
	ViewportPoint.x = (r - l) / 2 * scale * ViewPoint.x;
	ViewportPoint.y = (t - b) / 2 * scale * ViewPoint.y;
	ViewportPoint.z =  scale * ViewPoint.z;
	ViewportPoint.w = ViewPoint.w;
	ViewportPoint.c = ViewPoint.c;
	
	return ViewportPoint;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值