欢迎光临散文网 会员登陆 & 注册

自学计算机图形学11: 北太天元用三种方式给出平移、放缩、旋转变换的组合起来的矩

2023-05-22 08:54 作者:卢朓  | 我要投稿

% 北太天元 学习 opengl 提供的 gluLookAt , glMultMatrix,

% glScalef

%

%


%立方体

%

points = [

   % 下底面的四个点

   -1 -1 -1  ; %第一个点

   -1 1 -1  ; %第二个点

   1 1 -1  ;

   1 -1 -1  ;

      %上底面的四个点

   -1 -1 3  ;

   -1 1 3  ;

   1 1 3  ;

   1 -1 3  ;

      %原点

      0 0 0

   ];


points = points' ; %每个点的坐标改成列向量


%求出所有的点的"中心" center

center = ( max(points,[],2) + min(points, [], 2) ) / 2.0;

%我们就是盯着上面定义的中心点看

target = center;


%把target点平移到原点

points_p = points - target;


%缩放

xyz_max = max(points,[],2); xyz_min = min(points,[], 2);

z_max = xyz_max(3);

z_min = xyz_min(3);

if( z_max == z_min )

   error('所有的点的z坐标相等')

end

scale_z = 1.0/(z_max - z_min);


points_s_p = diag([1.0, 1.0, scale_z]) * points_p; 



pitch = 30;

yaw = 45;

direction = pitch_yaw(pitch, yaw)


up = [0,0,1];

ca_axes = camera_axes(up, direction)


points_r_s_p = ca_axes' * points_s_p;


ca_min = min(points_r_s_p,[],2)

ca_max = max(points_r_s_p,[],2)


%现在看的方向就是eta轴的正方向

%可以考虑把相机平移

distance(2) = ca_min(2) - 0.1*(ca_max(2) - ca_min(2))

%相机在(xi,eta,zeta)下的坐标

distance = [0; distance(2); 0 ]; %仅仅考虑在direction方向上的移动

%如果假想相机还在原点,我们移动的是观察的物体,那么观察物体的移动方向和上面

% distance 给出的方向相反

ca_points_1 = points_r_s_p - distance


/**

opengl代码

glMode(GL_MODELVIEW)

glLoadIdenty()

glTranslatef( 0, -distance(2), 0) ;

glRotaef( yaw , .. )

glRotatef( pitch ... )

glScalef(

glTranslatef( )

*/


%实际上我们不需要计算camera的position, 只需要看ca_points_1 是如何计算出来

% 就知道这么费劲算出来的gluLookAt 矩阵实际上等于

mat2 = [ [ eye(3), [0; -distance(2); 0] ];

         [ 0 0 0 1] ] * ... %平移矩阵

         [ [ca_axes', [ 0; 0; 0 ]];

         [ 0 0 0 1] ] * ... % %旋转矩阵

         [ [diag([1.0, 1.0, scale_z]), [ 0; 0; 0 ]];

         [ 0 0 0 1] ] * ... % 缩放矩阵

         [ [ eye(3), -target(:) ];

         [ 0 0 0 1] ] ;   %平移矩阵

qi_points = [ points ; ones(1, length(points(1,:)))];

ca_points_2 = mat2*qi_points;



%相机的位置在哪儿呢? 我们知道通过我们其他渠道求出的LookAt矩阵

% 乘以相机的位置 = (0,0,0), 于是我们轻松求出相机的位置

% 下面是齐次坐标

camera_position_2 = ( [ [ eye(3), [0; -distance(2); 0] ];

         [ 0 0 0 1] ] * ... %平移矩阵

         [ [ca_axes', [ 0; 0; 0 ]];

         [ 0 0 0 1] ] ) \ [ 0 ; 0 ; 0; 1 ]


%我们如果要使用gluLookAt 就必然要计算出camera position 和 target

%相机的方向是我们通过pitch 和 yaw 计算出来的,

% target 我们假设是观察物体的中心,这里就是给出的target

% 需要平移的距离大小是 distance(2), 方向是direction

camera_position = camera_position_2(1:3);

mat = gluLookAt( camera_position, [0,0,0], up )

ca_points_3 = mat * ( [ [diag([1.0, 1.0, scale_z]), [ 0; 0; 0 ]];

         [ 0 0 0 1] ] * ... % 缩放矩阵

         [ [ eye(3), -target(:) ];

         [ 0 0 0 1] ] ) * qi_points ;


%   ^ z 轴

%   |

%   |     . y 轴

%   |   .

%   | . 

%   |_________> x 轴

% 开始的时候人眼看的方向是 y 轴正向, 然后 pitch 和 yaw

%根据 pitch 和 yaw 确定 camer 的方向

% 开始的camera的方向是(0,1,0), 首先绕x轴正向逆时针方向旋转pitch角度

% 然后再绕z轴正向逆时针方向旋转 yaw 角度

% 最后得到的camera的方向

% 例如 pitch_yaw(-90,0) 得到的方向是 (0,0,-1);

% 不过,最后的向量都写成了列向量

function direction = pitch_yaw( pitch, yaw)

   direction = [

         -cos( deg2rad(pitch) )*sin( deg2rad(yaw) );

         cos( deg2rad(pitch) )*cos( deg2rad(yaw) );

         sin( deg2rad(pitch) );

      ];

end


%对于开始给定的up方向和 direction方向

% 计算出right 方向 : camera_right = direction x up 再normalize

% 然后根据camera_right方向和direction方向计算出camera_up:

% camera_up = right x direction 再normalize

% 最后得到的camera坐标系的三个轴是

% (right, direction, up)

% 注意: https://learnopengl.com/Getting-started/Camera 这篇文章中的

% direction 不是camera 看向的方向,而是相反的。

% 我们这里和上面的帖子不同,direction 还保持camera 看向的方向

% 也就是 (right, direction, camera_up) 是一个右手系

% https://learnopengl.com/Getting-started/Camera 这篇文章中的

% 的lookat 的矩阵也是怪怪的,可能也会导致模仿者出错。

function ca_axes = camera_axes(up, direction)

   up = up(:); % 确保得到的up是一个列向量

   direction = direction(:); %确保得到的direction 是一个列向量

   %确保输入的direction是一个单位向量

   norm_d = norm(direction, 2);

   if(norm_d < eps)

      error('输入的direction向量接近于0');

   end

   direction = direction /norm_d;


   camera_right = cross( direction, up ); % drection 叉乘 up

   % 这个地方要检查一下 是不是direction 和 up 贡献

   norm_r = norm(camera_right,2) ; %计算camera_right的2范数

   if(norm_r < eps)

      error("up 和 direction 共线")

   end

   camera_right = camera_right / norm_r; %把camera_right单位化


   camera_up = cross(camera_right, direction); % right 叉乘 direction

   camera_up = camera_up / norm(camera_up, 2);


   ca_axes = [ camera_right, direction, camera_up]; 

end


%

% gluLookAt 矩阵

% 要求相机位置ca_positin, 目标点target, 上方向up 都是长度为3的向量


function Mat = gluLookAt(ca_position, target, up)

   ca_position = ca_position(:)

   target = target(:)

   direction = target - ca_position

   disp('在gluLookAt 计算的direction')

   direction = direction / norm(direction, 2); 

   right = cross(direction, up);

   %注意检查 up 和 target-ca_position 是否共线? 

   norm_r = norm(right,2);

   if(norm_r < eps)

      error('direction 和 up 几乎共线, 请修改up方向');

   end

   right = right / norm_r;

   ca_up = cross(right, direction);


   ca_axes = [ right(:), direction(:), ca_up(:) ] % 分别对应 \xi , \eta, \zeta 三个轴


   %确定了right, direction, up 方向之后, 我们确定gluLookAt矩阵

 平移_mat = [ eye(3), -ca_position; [0 0 0 1] ]

 旋转_mat = [ ca_axes', zeros(3,1); [0 0 0 1] ]

   Mat = 旋转_mat * 平移_mat; 

end



%绕着方向 n 的旋转变换, 逆时针旋转theta角度

function Mat = glRotate(theta, n)

   n = n(:);

   n = n / norm(n, 2);

   n1 = n(1); n2 = n(2); n3 = n(3);

   theta = deg2rad(theta); % 角度转成弧度

   c = cos(theta);

   s = sin(theta);

   Mat = [ ...

      c + n1^2*(1-c),      n1*n2*(1-c) - n3*s, n1*n3*(1-c) + n2*s ;

      n1*n2*(1-c) + n3*s,  c + n2^2*(1-c),     n2*n3*(1-c) - n1*s ;

      n1*n3*(1-c) - n2*s,  n2*n3*(1-c) + n1*s, c + n3^2*(1-c);

      ];

end



自学计算机图形学11: 北太天元用三种方式给出平移、放缩、旋转变换的组合起来的矩的评论 (共 条)

分享到微博请遵守国家法律