欢迎来到NiceSpace!祝大家开心每一天!
  • C++
  • 图形学
3D图形学总结(五)—屏幕坐标变换

物体顶点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);
}
随机文章
3D图形学总结(十二)—纹理滤波 破解图片防盗链 一个简单的CSS加载动画 python爬虫之爬取捧腹网段子 深入理解字符串(编码,解码,乱码问题)