我正在研究图形管道流程,特别是透视投影矩阵。
在查看了几个不同的来源之后,以及How does a projection Matrix work?之前的广泛问题,我发现大多数解决方案似乎使用以下两个矩阵;
到目前为止,我一直在期待这些矩阵采用视锥体并将其转换为单位大小的立方体 - 但这似乎并没有发生。
首先考虑左矩阵(我试图先使用它),我假设参数是这样的;
n / f = z 近平面和远平面的值
r / l = x 左右平面的值
t / b = y 顶部和底部平面的值
对于右手矩阵,我的书很模糊,唯一合适的参数是
d / f - 到近/远平面的距离(但不一定是 z 值?) h - 近剪裁平面的高度。
我最初的实验方法是绘制平截头体的顶点并使用变换得到一个结果,X,Y值可以用来显示2D中的图像,Z值可用于决定什么多边形覆盖其他人。
然而,虽然我一直期待一个尺寸为1的立方体 - > -1沿着所有的轴,相反,我只得到一个倒置的截头体。
我觉得我要么犯了一个基本的错误,要么错过了一些关键的东西 - 我会感谢任何帮助,以清除我在将形状从3D转换为2D时需要做的不确定性,以及我应该做些什么期待。到目前为止,我的结果如下。
左图显示视锥体中的形状 - 右侧显示原始平截头体和变换后的平截头体在应用透视变换后我认为应该转换为单位大小的立方体而不仅仅是反射的截头体。
我已将我的代码放在下面,并尝试尽可能地简化它,以便更容易评估!非常感谢!
更新 我更新了视图空间坐标的坐标 - 使用不同的方法生成视图空间坐标,这些坐标朝向负z值'返回'。不确定这是否使它更正确,但我希望它有所帮助(但根据评论)。
clc; clear all; close all;
%======Create View Space (hard-coded values for demo) & Plot ===========
ws_fcs = [1,2,4,3,3,1,6,6,6,6,7,7,9,8,8,8,10,10;
2,4,3,1,4,4,9,8,7,11,9,13,8,12,10,6,11,13;
5,5,5,5,1,2,7,9,11,10,13,11,13,13,12,10,13,12];
ws_vtx = [-1.3416,0.4472,-1.3416,0.4472,-1.3416,-0.8944,0,0,0.8944,-0.8944,0,0,0.8944;
-1.0954,-1.4606,0.7303,0.3651,-1.0954,-0.7303,-0.9129,0,-0.1826,0.1826,0,0.9129,0.7303;
-4.899,-4.0825,-4.0825,-3.266,-2.4495,-4.4907,-4.0825,-6.1237,-5.7155,-4.0825,-3.6742,-5.7155,-5.3072];
position = [0;0;0;1]; focus = [0;0;-3.6742]; %Transformed set points
figure(); grid on; hold on; xlabel('x'); ylabel('y'); zlabel('z');
scatter3(position(1),position(2),position(3),'s');
scatter3([position(1); position(1)+focus(1)],[position(2); position(2)+focus(2)],...
[position(3); position(3)+focus(3)],'s');
plot3([position(1), focus(1)],[position(2), focus(2)],[position(3), focus(3)],'g');
patch('Faces',ws_fcs','Vertices',ws_vtx','Facecolor', 'r', 'FaceAlpha', 0.1);
%====================Create View Volume===========================
asp_rat = 0.75; %Most displays arent square
focus = focus/norm(focus); %Normalise focus vector
nheight = 1; %height of near clip plane
hoz_angle = 2*pi/3;
ndistance = 1/tan(hoz_angle/2); %distance of near view plane from origin
fdistance = 5.5; %Define a far distance
nc = ndistance*focus; %Centre point is focus vector * distance
ntr = nc + [asp_rat*nheight; nheight; 0]; %Go from centre to TL corner
nbr = ntr + [0; -2*nheight;0]; %Go down 2* height to bottom
nbl = nbr + [-2*asp_rat*nheight; 0; 0];
ntl = nbl + [0; 2*nheight;0];
nr_plan = [ntr, nbr, nbl, ntl]; %Generate near plane points
fc = fdistance*focus;
fheight = tan(hoz_angle/2)*fdistance; %Find far plane height by trig
ftr = fc + [asp_rat*fheight; fheight; 0]; %Go from centre to TL corner
fbr = ftr + [0; -2*fheight;0]; %Go down 2* height to bottom
fbl = fbr + [-2*asp_rat*fheight; 0; 0];
ftl = fbl + [0; 2*fheight;0];
fr_plan = [ftr, fbr, fbl, ftl]; %Generate near plane points
frust_vtx = horzcat(nr_plan, fr_plan); %Create frustum vertex array
frust_fcs = [1,8,5,6,4,5; %Faces defined with normals inwards
4,5,1,2,8,8;
3,6,2,3,7,4;
2,7,6,7,3,1];
patch('Faces',frust_fcs','Vertices',frust_vtx', 'FaceAlpha', 0.05);
xlabel('x'); ylabel('y'); zlabel('z');
%=============Create Perspective Matrix ==============================
figure(); grid on; hold on; xlabel('x'); ylabel('y'); zlabel('z');
scatter3(frust_vtx(1,:),frust_vtx(2,:),frust_vtx(3,:)); %Plot orig frustrum
patch('Faces',frust_fcs','Vertices',frust_vtx', 'FaceAlpha', 0.05);
left = nc(1) - asp_rat*nheight; %Get values for projection matrix
right = nc(1) + asp_rat*nheight;
top = nc(2) + nheight;
bottom = nc(2) -nheight;
near = ndistance;
far = fdistance;
proj_mat = [2*near/(right - left),0,(right + left)/(right - left),0;
0, 2*near/(top-bottom),(top+bottom)/(top-bottom),0;
0,0, -(far+near)/(far-near), -2*far*near/(far-near);
0,0,-1,0];
%====================Perspective Projection Transformation=============
frust_vtx = proj_mat*vertcat(frust_vtx,(ones(1,length(frust_vtx))));
scatter3(frust_vtx(1,:),frust_vtx(2,:),frust_vtx(3,:)); %Plot frustrum points
patch('Faces',frust_fcs','Vertices',frust_vtx(1:3,:)','FaceColor','g','FaceAlpha', 0.05);