3D图形学学习总结(五)—屏幕坐标变换

原文链接:http://www.nicemxp.com/articles/22

物体顶点v经过透视变换后在视平面上的投影坐标(xper, yper),现在要将视平面坐标变换到屏幕上,需要经过屏幕坐标变换,缩放投射到屏幕上。

屏幕宽度:SCREEN_WIDTH,屏幕宽度:SCREEN_HEIGHT,如图:

注意,屏幕的y轴坐标是反转了的,我们现在进行映射变换。

物体顶点的透视坐标(经过归一化的透视坐标)xper范围(-1, 1),yper范围(-1, 1),所以有:

xper:(-1, 1) => xscreen:(0, SCREEN_WIDTH-1)

yper:(-1, 1) => yscreen:(0, SCREEN_HEIGHT-1)

据上我们可以很容易得出映射变换公式:

xscreen = (xper + 1) * (SCREEN_WIDTH-1) / 2 = (0.5*SCREEN_WIDTH-0.5) * xper + (0.5*SCREEN_WIDTH-0.5)

yscreen = (SCREEN_HEIGHT - 1) - (yper + 1) * (SCREEN_HEIGHT-1) / 2 =  - (0.5*SCREEN_HEIGHT-0.5) * yper + (0.5*SCREEN_HEIGHT-0.5)

我们假定:

α:(0.5*SCREEN_WIDTH-0.5),β:(0.5*SCREEN_HEIGHT-0.5),则:

xscreen = xper * α + α

yscreen = yper * (-β) + β

因为透视坐标z分量无关紧要,所以我们可以设透视坐标为(xper, yper, 0, 1),这样我们可以通过矩阵运算的方式完成屏幕坐标转换,屏幕变换矩阵Tscr:

可以得到:

(xper, yper, 0, 1) * 

= (xper * α + α, -yper*β+β, 0, 1)

到此屏幕坐标转换就完成了。

屏幕坐标转换矩阵源码:

//点和向量四维
typedef struct VECTOR4D_TYP
{
	union
	{
		float M[4];
		struct
		{
			float x, y, z, w;
		};
	};
} VECTOR4D, POINT4D, *VECTOR4D_PTR, *POINT4D_PTR;

//4x4矩阵
typedef struct MATRIX4X4_TYP
{
	union
	{
		float M[4][4];
		struct
		{
			float M00, M01, M02, M03;
			float M10, M11, M12, M13;
			float M20, M21, M22, M23;
			float M30, M31, M32, M33;
		};
	};
} MATRIX4X4, *MATRIX4X4_PTR;

//相机结构
typedef struct CAM4DV1_TYP
{
	int state;
	int attr;

	POINT4D pos; //相机在世界坐标中的位置
	VECTOR4D dir; //欧拉角度或者UVN相机模型的注视方向

	VECTOR4D u;
	VECTOR4D v;
	VECTOR4D n;
	POINT4D target;

	float view_dist;//视距
	float fov; //水平方向和垂直方向视野
	float near_clip_z;//近裁剪面
	float far_clip_z;//远裁剪面

	//上下左右裁剪面 略

	float viewplane_width;//视平面宽度
	float viewplane_height;//视平面高度

	float viewport_width;//视口宽度
	float viewport_heght;//视口高度
	float viewport_center_x;//视口中心x
	float viewport_center_y;//视口中心y

	float aspect_radio; //宽高比

	MATRIX4X4 mcam; //相机变换矩阵
	MATRIX4X4 mper; //透视变换矩阵
	MATRIX4X4 mscr; //屏幕变换矩阵

}CAM4DV1, *CAM4DV1_PTR;

//矩阵初始化
void Mat_Init_4X4(MATRIX4X4_PTR ma,
	float m00, float m01, float m02, float m03,
	float m10, float m11, float m12, float m13,
	float m20, float m21, float m22, float m23,
	float m30, float m31, float m32, float m33)

{
	ma->M00 = m00; ma->M01 = m01; ma->M02 = m02; ma->M03 = m03;
	ma->M10 = m10; ma->M11 = m11; ma->M12 = m12; ma->M13 = m13;
	ma->M20 = m20; ma->M21 = m21; ma->M22 = m22; ma->M23 = m23;
	ma->M30 = m30; ma->M31 = m31; ma->M32 = m32; ma->M33 = m33;

}

//屏幕坐标转换矩阵
void BuildPerspectToScreenMatrix(CAM4DV1_PTR cam)
{	
	float alpha = 0.5 * cam->viewport_width - 0.5;
	float beta = 0.5 * cam->viewport_heght - 0.5;
	Mat_Init_4X4(&cam->mscr, alpha, 0, 0, 0,
		0, -beta, 0, 0,
		0, 0, 1, 0,
		alpha, beta, 0, 1);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值