首页 > 编程知识 正文

形学坐标变换,形变换与坐标

时间:2023-05-03 20:03:35 阅读:241512 作者:1311

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

物体放置到世界中后,在欧拉相机模型下转换成相机坐标。

欧拉相机模型是使用位置和旋转角度(欧拉角度)定义的,其中旋转角度决定了相机的朝向。

相机位置在(camx, camy, camz),观察角度为(0,angy,0),即相机绕y轴顺时针旋转angy。如图:

如图所示,要想转换成相机坐标,首先将相机移动到原点处,这样物体的每个点都平移(-camx,-camy,-camz),如图:

物体的每个点都进行平移运算,可以通过矩阵运算完成,平移矩阵Tcam:

顶点v( world_x, world_y, world_z, 1 ) * Tcam = ( world_x - camx, world_y - camy, world_z - camz, 1)

完成平移运算后进行旋转操作,欧拉相机的指向方向是绕Y轴顺时针旋转angy,所以要想完成相机坐标变换,让相机的朝向与Z轴重合,相机和物体需要旋转 -angy,即逆时针旋转angy,如图:

这样相机位置(0,0,0),相机角度(0,0,0),就完成了欧拉相机的相机坐标变换,上面是针对相机朝向为(0,angy,0)的情况,一般情况下相机朝向为(angx,angy,angz),所以相机需要进行一系列的旋转转换,3个角度的旋转顺序有6种,我们取yxz的顺序,先绕Y轴旋转-angy,再绕x轴旋转-angx,最后绕Z轴旋转-angz。但是旋转操作需要如何计算呢,以相机绕X轴旋转为例,在相机绕X轴旋转的过程中,相机朝向的x分量是不变的,所以我们可以在二维平面上推导,如图:

如图所示是左手坐标系下,我们站在正X轴方向向负X轴看去得到的平面图,我们设当前欧拉相机的朝向在YOZ平面的投影为OA方向,OA与Z轴正向夹角为α,此时相机绕着X轴顺时针旋转β到OB,点A在Z轴投影为A´,点B再Z轴投影为B´,A点坐标为(z1,y1),B点坐标为(z2,y2),OA的长度为r,因此我们有以下两个推导:

y2 = r * sin( α - β ) = r * (sinα*cosβ - cosα*sinβ) = r * sinα*cosβ - r * cosα*sinβ =  z1 * (-sinβ ) + y1*cosβ

z2 = r * cos( α - β ) = r * (cosα*cosβ + sinα*sinβ)  = r * cosα*cosβ + r * sinα*sinβ = z1 * cosβ + y1 * sinβ

所以相机绕X轴顺时针旋转β时的计算公式为:

y2 = y1*cosβ + z1 * (-sinβ )

z2 = y1 * sinβ + z1 * cosβ 

同理我们可以t通过同样的方式算出相机绕其他两个轴的计算公式,上述是相机旋转β后的计算公式,我们要完成相机坐标变换只需要将物体顶点反方向旋转β,即 使用-β带入上面公式中就可以了。根据推导结果我们可以看出旋转操作可以通过矩阵运算来完成,物体顶点v (x, y, z, 1),经过绕X轴旋转 -β:

(x, y, z, 1) *    = ( x, y * cos(-β) - z * sin(-β), y * sin(-β) + z * cos(-β), 1)

所以,绕X轴旋转的相机坐标变换矩阵Rcamx为:

通过计算,绕Y轴旋转的相机坐标变换矩阵Rcamy:

绕Z轴旋转的相机坐标变换矩阵Rcamz:

这样我们得到了3个轴的旋转变换矩阵Rcamx,Rcamy,Rcamz,加上之前的相机平移矩阵Tcam,对于物体的顶点v( world_x, world_y, world_z)经过相机坐标转换后的结果为:

( world_x, world_y, world_z, 1) * Tcam * Rcamy * Rcamx * Rcamz

操作为点v先经过平移( -camx, -camy, -camz, 1),然后绕Y轴旋转-angy,在绕X轴旋转-angx,最后绕Z轴旋转-angz。而矩阵

Tres = Tcam * Rcamy * Rcamx * Rcamz 就是欧拉相机坐标变换矩阵。

构建欧拉相机坐标变换矩阵源码:

#include <math.h>//点和向量四维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;//视口中心xfloat viewport_center_y;//视口中心yfloat 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 Mat_Mul_4X4(MATRIX4X4_PTR ma, MATRIX4X4_PTR mb, MATRIX4X4_PTR mc){for (int row = 0; row < 4; row++){for (int col = 0; col < 4; col++){float tmp = 0;for (int i = 0; i < 4; i++){tmp += ma->M[row][i] * mb->M[i][col];}mc->M[row][col] = tmp;}}}//构建欧拉相机相机转换矩阵void BuildMatrixCamEuler(CAM4DV1_PTR cam){MATRIX4X4 mt_inv, mx_inv, my_inv, mz_inv, mrot, mtmp;//相机平移矩阵Mat_Init_4X4(&mt_inv, 1, 0, 0, 0,0, 1, 0, 0,0, 0, 1, 0,-cam->pos.x, -cam->pos.y,-cam->pos.z, 1);//旋转矩阵double theta_x = cam->dir.x;double theta_y = cam->dir.y;double theta_z = cam->dir.z;//x的正弦和余弦double cos_theta = cos(theta_x);double sin_theta = -sin(theta_x);Mat_Init_4X4(&mx_inv, 1, 0, 0, 0,0, cos_theta, sin_theta, 0,0, -sin_theta, cos_theta, 0,0, 0, 0, 1);//y的正弦和余弦cos_theta = cos(theta_y);sin_theta = -sin(theta_y);Mat_Init_4X4(&my_inv, cos_theta, 0, -sin_theta, 0,0, 1, 0, 0,sin_theta, 0, cos_theta, 0,0, 0, 0, 1);//z的正弦和余弦cos_theta = cos(theta_z);sin_theta = -sin(theta_z);Mat_Init_4X4(&mz_inv, cos_theta, sin_theta, 0, 0,-sin_theta, cos_theta, 0, 0,0, 0, 1, 0,0, 0, 0, 1);//逆矩阵积yxz顺序Mat_Mul_4X4(&my_inv, &mx_inv, &mtmp);Mat_Mul_4X4(&mtmp, &mz_inv, &mrot);//相机变换矩阵Mat_Mul_4X4(&mt_inv, &mrot, &cam->mcam);}

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。