自學(xué)計(jì)算機(jī)圖形學(xué)11: 北太天元用三種方式給出平移、放縮、旋轉(zhuǎn)變換的組合起來的矩

% 北太天元 學(xué)習(xí) opengl 提供的 gluLookAt ,?glMultMatrix,
% glScalef
%
%
%立方體
%
points = [
???% 下底面的四個(gè)點(diǎn)
???-1 -1 -1??; %第一個(gè)點(diǎn)
???-1 1 -1??; %第二個(gè)點(diǎn)
???1 1 -1??;
???1 -1 -1??;
??????%上底面的四個(gè)點(diǎn)
???-1 -1 3??;
???-1 1 3??;
???1 1 3??;
???1 -1 3??;
??????%原點(diǎn)
??????0 0?0
???];
points = points' ; %每個(gè)點(diǎn)的坐標(biāo)改成列向量
%求出所有的點(diǎn)的"中心" center
center = ( max(points,[],2) + min(points, [], 2) ) / 2.0;
%我們就是盯著上面定義的中心點(diǎn)看
target = center;
%把target點(diǎn)平移到原點(diǎn)
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('所有的點(diǎn)的z坐標(biāo)相等')
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)
%現(xiàn)在看的方向就是eta軸的正方向
%可以考慮把相機(jī)平移
distance(2) = ca_min(2) - 0.1*(ca_max(2) - ca_min(2))
%相機(jī)在(xi,eta,zeta)下的坐標(biāo)
distance = [0; distance(2); 0 ]; %僅僅考慮在direction方向上的移動(dòng)
%如果假想相機(jī)還在原點(diǎn),我們移動(dòng)的是觀察的物體,那么觀察物體的移動(dòng)方向和上面
% 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(?)
*/
%實(shí)際上我們不需要計(jì)算camera的position, 只需要看ca_points_1 是如何計(jì)算出來
% 就知道這么費(fèi)勁算出來的gluLookAt 矩陣實(shí)際上等于
mat2 = [ [ eye(3), [0; -distance(2); 0] ];
?????????[ 0 0 0 1] ] *?...?%平移矩陣
?????????[ [ca_axes', [ 0; 0; 0 ]];
?????????[ 0 0 0 1] ] * ...?%?%旋轉(zhuǎn)矩陣
?????????[ [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;
%相機(jī)的位置在哪兒呢? 我們知道通過我們其他渠道求出的LookAt矩陣
% 乘以相機(jī)的位置 = (0,0,0), 于是我們輕松求出相機(jī)的位置
% 下面是齊次坐標(biāo)
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 ]
%我們?nèi)绻褂胓luLookAt 就必然要計(jì)算出camera position 和 target
%相機(jī)的方向是我們通過pitch 和 yaw 計(jì)算出來的,
% target 我們假設(shè)是觀察物體的中心,這里就是給出的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 軸
% 開始的時(shí)候人眼看的方向是 y 軸正向, 然后 pitch 和 yaw
%根據(jù) pitch 和 yaw 確定 camer 的方向
% 開始的camera的方向是(0,1,0), 首先繞x軸正向逆時(shí)針方向旋轉(zhuǎn)pitch角度
% 然后再繞z軸正向逆時(shí)針方向旋轉(zhuǎn) 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
%對(duì)于開始給定的up方向和 direction方向
% 計(jì)算出right 方向 : camera_right = direction x up 再normalize
% 然后根據(jù)camera_right方向和direction方向計(jì)算出camera_up:
% camera_up = right x direction?再normalize
% 最后得到的camera坐標(biāo)系的三個(gè)軸是
%?(right, direction, up)
% 注意: https://learnopengl.com/Getting-started/Camera 這篇文章中的
% direction 不是camera 看向的方向,而是相反的。
% 我們這里和上面的帖子不同,direction 還保持camera 看向的方向
% 也就是 (right, direction, camera_up) 是一個(gè)右手系
% https://learnopengl.com/Getting-started/Camera 這篇文章中的
% 的lookat 的矩陣也是怪怪的,可能也會(huì)導(dǎo)致模仿者出錯(cuò)。
function ca_axes = camera_axes(up, direction)
???up = up(:);?% 確保得到的up是一個(gè)列向量
???direction = direction(:);?%確保得到的direction 是一個(gè)列向量
???%確保輸入的direction是一個(gè)單位向量
???norm_d = norm(direction, 2);
???if(norm_d < eps)
??????error('輸入的direction向量接近于0');
???end
???direction = direction /norm_d;
???camera_right =?cross( direction, up ); %?drection 叉乘 up
???% 這個(gè)地方要檢查一下 是不是direction 和 up 貢獻(xiàn)
???norm_r = norm(camera_right,2) ; %計(jì)算camera_right的2范數(shù)
???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 矩陣
% 要求相機(jī)位置ca_positin, 目標(biāo)點(diǎn)target, 上方向up 都是長度為3的向量
function?Mat =?gluLookAt(ca_position, target, up)
???ca_position = ca_position(:)
???target = target(:)
???direction = target - ca_position
???disp('在gluLookAt 計(jì)算的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 幾乎共線, 請(qǐng)修改up方向');
???end
???right = right / norm_r;
???ca_up = cross(right, direction);
???ca_axes = [ right(:), direction(:), ca_up(:) ] % 分別對(duì)應(yīng) \xi , \eta, \zeta 三個(gè)軸
???%確定了right, direction, up 方向之后, 我們確定gluLookAt矩陣
?平移_mat = [ eye(3), -ca_position; [0 0 0 1] ]
?旋轉(zhuǎn)_mat = [ ca_axes', zeros(3,1); [0 0 0 1] ]
???Mat =?旋轉(zhuǎn)_mat * 平移_mat;?
end
%繞著方向 n 的旋轉(zhuǎn)變換, 逆時(shí)針旋轉(zhuǎ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);?% 角度轉(zhuǎn)成弧度
???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