I'm looking into the graphics pipeline processes and at the moment in particular, perspective projection matrices.After looking in several different sources, and across the breadth of previous questions such as https://stackoverflow.com/questions/25659623/how-does-a-projection-matrix-work, I've found that most solutions seem to use the following two matrices;So far, I've been expecting these matrices to take the view frustum and convert it into a unit sized cube - however this doesn't seem to be happening.Taking the left matrix first (which I attempted to use first), I assumed the parameters were as such;n/f = z value of near and far planesr/l = x values of left and right planest/b = y values of top and bottom planesFor the right hand matrix, my book is very vague, and the only parameters that seem to fit ared/f - distances to near/far planes (but not necessarily the z values?)h - height of the near clip plane.My initial method of experimentation has been to plot the vertices of the frustum and using the transforms get a resultant that the X, Y values can be used to display the image in 2D and with Z values that can be used to decide what polygons overlay others.However, whilst I've been expecting a cube with dimensions of 1 -> -1 along all axes, instead I've been getting just an inverted frustrum.I feel I'm either making an elementary mistake or am missing something key - would appreciate any help in clearing up both my uncertainties in what I need to do to convert my shape from the 3D to the 2D, and what I should be expecting. So far, my results are below. The left hand picture shows the shape in a view frustum - and the right shows the original frustum and transformed frustum in green after applying the perspective transform which I believe should be transformed to a unit sized cube and not just a reflected frustum.I've put my code below, and tried to simplify it as much as possible to make it easier to evaluate!. Thanks very much!UpdatesI've updated my coordinates for view space coordinates - using a different method generates view space coordinates that go 'back' towards negative z values. Not sure if that makes it more correct but I hope it helps (but as per the comment).Following the answer below I've added an attempt to perform perspective division. I've added the following code below the main bulk. Any further recommendations would be massively appreciatedclc; 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 pointsfigure(); 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 squarefocus = focus/norm(focus); %Normalise focus vectornheight = 1; %height of near clip planehoz_angle = 2*pi/3;ndistance = 1/tan(hoz_angle/2); %distance of near view plane from originfdistance = 5.5; %Define a far distancenc = ndistance*focus; %Centre point is focus vector * distancentr = nc + [asp_rat*nheight; nheight; 0]; %Go from centre to TL cornernbr = ntr + [0; -2*nheight;0]; %Go down 2* height to bottomnbl = nbr + [-2*asp_rat*nheight; 0; 0];ntl = nbl + [0; 2*nheight;0];nr_plan = [ntr, nbr, nbl, ntl]; %Generate near plane pointsfc = fdistance*focus;fheight = tan(hoz_angle/2)*fdistance; %Find far plane height by trigftr = fc + [asp_rat*fheight; fheight; 0]; %Go from centre to TL cornerfbr = ftr + [0; -2*fheight;0]; %Go down 2* height to bottomfbl = fbr + [-2*asp_rat*fheight; 0; 0];ftl = fbl + [0; 2*fheight;0];fr_plan = [ftr, fbr, fbl, ftl]; %Generate near plane pointsfrust_vtx = horzcat(nr_plan, fr_plan); %Create frustum vertex arrayfrust_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 matrixright = 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 pointspatch('Faces',frust_fcs','Vertices',frust_vtx(1:3,:)','FaceColor','g','FaceAlpha', 0.05);Perspective Division%========================Perspective Division==========================for i = 1:length(frust_vtx)     frust_vtx(:,i) = frust_vtx(:,i)/frust_vtx(4,i);endfor i = 1:length(ws_vtx)     ws_vtx(:,i) = ws_vtx(:,i)/ws_vtx(4,i);endscatter3(ws_vtx(1,:),ws_vtx(2,:),ws_vtx(3,:)); %Plot shape pointspatch('Faces',ws_fcs','Vertices',ws_vtx(1:3,:)','FaceColor','r','FaceAlpha', 0.05); scatter3(frust_vtx(1,:),frust_vtx(2,:),frust_vtx(3,:)); %Plot frustrum pointspatch('Faces',frust_fcs','Vertices',frust_vtx(1:3,:)','FaceColor','g','FaceAlpha', 0.05);
Choosing & Using a Projection Matrix
transformations;3d;vector graphics;matrices;matlab
The values will only form a cube after performing the perspective divide, which I don't see happening in your code.That is, you take a vector $[x, y, z, 1]$ and transform it by the projection matrix, resulting in a new vector $[x', y', z', w']$. Then divide out the fourth component to get a 3D vector, $[x'/w', y'/w', z'/w']$. This last is the one that should be within a $[-1, 1]$ cube, if the original point was within the view frustum (and if it's an OpenGL-style projection matrixDirect3D-style ones have $[0,1]$ for the post-projective Z range, instead of $[-1, 1]$).Without the divide by $w'$, if you just look at $[x', y', z']$, indeed you'll just get a scaled and possibly reflected frustum. Matrix multiplication alone can't transform a frustum into a cube, as it's not a linear or affine transformation; instead, it's a projective transformation, and the divide by $w'$ accomplishes that.