自学计算机图形学9-用北太天元辅助理解gluLookAt和平移旋转等变换

% 北太天元 学习 opengl 提供的 gluLookAt , glMultMatrix,
%
%
%立方体
%
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' ; %每个点的坐标改成列向量
target = [20;20;0];
points = points + target; %把立方体的中心平移到target;
pitch = 30;
yaw = 45;
direction = pitch_yaw(pitch, yaw)
up = [0,0,1];
ca_axes = camera_axes(up, direction)
camera_axes(up, pitch_yaw(0,pitch)) * camera_axes(up,pitch_yaw(yaw,0))
ca_axes_inverse = camera_axes(up, pitch_yaw(-yaw,0)) * camera_axes(up,pitch_yaw(0,-pitch))
%先做平移,把观察物体的中心点移动到原点
ca_points_p = points - target;
%
ca_points = ca_axes_inverse * ca_points_p;
ca_min = min(ca_points,[],2)
ca_max = max(ca_points,[],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 = ca_points - distance
%实际上我们不需要计算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] ] * ... % %旋转矩阵
[ [ eye(3), -target(:) ];
[ 0 0 0 1] ] ; %平移矩阵
qi_points = [ points ; ones(1, length(points(1,:)))];
ca_points_1 = mat2*qi_points;
%相机的位置在哪儿呢? 我们知道通过我们其他渠道求出的LookAt矩阵mat2
% mat2乘以相机的位置 = (0,0,0), 于是我们轻松求出相机的位置
% 下面是齐次坐标
camera_position_2 = mat2 \ [ 0 ; 0 ; 0; 1 ]
%我们如果要使用gluLookAt 就必然要计算出camera position 和 target
%相机的方向是我们通过pitch 和 yaw 计算出来的,
% target 我们假设是观察物体的中心,这里就是给出的target
% 需要平移的距离大小是 distance(2), 方向是direction
camera_position = target + distance(2)*direction;
camera_position = camera_position_2(1:3);
mat = gluLookAt( camera_position, target, up )
ca_points_2 = mat * 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