自学计算机图形学6: 用北太天元辅助理解从世界坐标系到相机坐标系下的坐标变换

%北太天元 帮助理解 计算机图形学的坐标变换
%立方体
%
points = [
% 下底面的四个点
-1 -1 -1 ; %第一个点
-1 1 -1 ; %第二个点
1 1 -1 ;
1 -1 -1 ;
%上底面的四个点
-1 -1 1 ;
-1 1 1 ;
1 1 1 ;
1 -1 1 ;
%原点
0 0 0
];
points = points' ; %每个点的坐标改成列向量
%开始的up方向 (0, 0, 1);
% pitch = 45, yaw = 0 方向是 (1,1,0)
up = [0; 1; 0];
pitch = 30; yaw = -45;
ca_axes = camera_axes(up, pitch_yaw(pitch,yaw));
ca_points = ca_axes' *points;
max_p = max(ca_points,[], 2); %获得camera view 坐标系下的所有点坐标的最大值
min_p = min(ca_points,[], 2);%获得camera view 坐标系下的所有点坐标的最小值
%现在camera的方向是direction = -ca_axes(3,:)的转置
% 目前假设的camera的位置在(0,0,0)
% 需要把camera 沿着camera的方向反向移动一段距离 distance,
% 使得整个立方体都在camera的前方,
% 现在 ca_points 在 ca_axes(3,:) 的坐标的范围是
min_d = min(ca_points(3,:));
max_d = max(ca_points(3,:));
%相机需要移动的距离是
distance = max_d + 0.1*(max_d - min_d);
% camera 的位置(在移动前的camera 坐标系下)
camera_p = [ 0; 0; distance ];
%相机的位置在世界坐标系下是
camera_position = ca_axes * camera_p ;
% 经过了先旋转,再平移
% 最终得到的 look_at( up, pitch_yaw(pitch,yaw), position) 下的
% 点的坐标(在平移后camera坐标系下)是
final_points = ca_points - camera_p;
%还有一种方式来计算 camera_view 下的坐标, 使用齐次坐标
qi_points = [points ; ones(size(points(1,:))) ]; %最后一行加上了1
%齐次坐标的从world coordinates变换到
% 相机坐标系下的 transform 矩阵
trans_mat = [ ca_axes' , -camera_p; [ 0, 0, 0, 1] ];
平移_mat = [ eye(3), -camera_position; [0 0 0 1] ]
旋转_mat = [ ca_axes', zeros(3,1); [0 0 0 1] ]
% 你可以验证 trans_mat = 平移_mat * 旋转_mat
disp("trans_mat - 平移_mat * 旋转_mat")
trans_mat - 平移_mat * 旋转_mat %
disp("trans_mat - 旋转_mat * 平移")
trans_mat - 旋转_mat * 平移_mat
% 这和 https://learnopengl.com/Getting-started/Camera 的 LookAt
% 矩阵是相同的
qi_final_points = trans_mat * qi_points;
%比较两种方式得到的camera_view 下的坐标
final_points - qi_final_points(1:3, :)
%根据 pitch 和 yaw 确定 camer 的方向
% 开始的camera的方向是(1,0,0), 首先绕z轴正向逆时针方向旋转pitch角度
% 然后再绕y轴正向顺时针方向旋转 ywa 角度
% 最后得到的camera的方向
% 例如 pitch_yaw(0,-90) 得到的方向是 (0,0,-1);
% 不过,最后的向量都写成了列向量
function direction = pitch_yaw( pitch, yaw)
direction = [
cos( deg2rad(pitch) )*cos( deg2rad(yaw) );
sin( deg2rad(pitch) );
cos( deg2rad(pitch) )*sin( deg2rad(yaw) );
];
end
%对于开始给定的up方向和 direction方向
% 计算出right 方向 : camera_right = direction x up 再normalize
% 然后根据camera_right方向和direction方向计算出camera_up:
% camera_up = right x direction 再normalize
% 最后得到的camera坐标系的三个轴是
% (right,
% https://learnopengl.com/Getting-started/Camera 这篇文章中的
% direction 不是camera 看向的方向,而是相反的。
% 我们这里和上面的帖子不同,direction 还保持camera 看向的方向
% 也就是 (right, camera_up, -direction) 是一个右手系
% 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 和 directin 共线")
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, camera_up, -direction ];
end