I'm attempting to model a simple graphics pipeline - using Matlab at the moment as a modelling tool to get the transformations correct. I appreciate there are software tools that would make this easier - but I'm looking to understand the maths behind it and hence am looking to mostly use simple functions & matrices that I'm learning from a book (very retro!).
I've successfully got through the stages of defining simple objects and converting them into a universal world space - but have come unstuck with the mathematics required to convert an object into view space and the back face culling.
I believe my view space transformation is correct because when I plot the composite vectors they appear correct - but - when I do the back-face culling, it seems to fail to remove the correct triangles. Given that it depends only on two things, the line-of-sight vector and face normals, I can't work out what I'm doing wrong.
When defining the triangles in local definition space, I did it so that all the normals pointed outwards. I've put my results into the image below
My questions are:
- Have I gone wrong, or are my expectations incorrect?
- If so where, and how do I fix?
Progress
I've plotted the normal's of all the shapes when in view space. They have all been inverted and now point inwards. Is this a property of the transformation and could it be responsible - or should this have no effect because all the polygons are affected the same?
(Have changed the code to show this)
clc; clear all; close all;
%============Initial verticies & Faces of the shape===========
[s1_vtx,s1_fcs] = Pyramid();
[s2_vtx,s2_fcs] = Cube();
%==============Transform Shape 1 ======================
Tx = 0; Ty = 0; Tz = 0; %Translation vectors for x,y,z axes
Sx = 2; Sy = 2; Sz = 2;%Scaling factors in x,y,z dimensions
Rx = pi/2; Ry = pi/4; Rz = pi/4; %Rotating factors in x,y,z dimensions
transform = scale(Sx,Sy,Sz)*rotate(Rx,0,0)*translate(Tx,Ty,Tz); %Merge transforms together
s1_vtx = transform*vertcat(s1_vtx,(ones(1,length(s1_vtx)))); %Add row of ones to end for multiplication
s1_vtx = s1_vtx(1:3,:); %And remove afterwards
%==============Transform Shape 2 ======================
Tx = 0.5; Ty = 0; Tz = 0.5;
transform = scale(1,2,1)*translate(Tx,Ty,Tz);
s2_vtx = transform*vertcat(s2_vtx,(ones(1,length(s2_vtx))));
s2_vtx = s2_vtx(1:3,:);
%======Create World Space ===========
ws_vtx = horzcat(s1_vtx(1:3,:), s2_vtx(1:3,:)); %remove homogenous column for patching
ws_fcs = horzcat(s1_fcs,(s2_fcs+(length(s1_vtx))));
%======Plot World Space ===========
grid on; hold on;
scatter3(ws_vtx(1,:),ws_vtx(2,:),ws_vtx(3,:)) %Plot all the points
patch('Faces',ws_fcs','Vertices',ws_vtx','Facecolor', 'none');
for i = 1:length(ws_vtx)
str = sprintf('%d',i);
text(ws_vtx(1,i),ws_vtx(2,i),ws_vtx(3,i), str,'FontSize',16, 'Color','r', 'FontWeight','b');
end
points = zeros(3,3); %Contains 1 triangle
for i = 1:length(ws_fcs); %For each triangle
points(:,1:3) = ws_vtx(:,ws_fcs(1:3,i));
U = points(:,2) - points(:,1); %Get two non-parallel vectors
V = points(:,3) - points(:,1);
average = [0,0,0];
for j = 1:length(points)
average(j) = (points(j,1) + points(j,2) + points(j,3))/3;
end
N = cross(U,V)/norm(cross(U,V)); %Normal, normalised to mag 1
scatter3(average(1),average(2),average(3));
plot3([average(1), average(1)+N(1)],[average(2), average(2)+N(2)],[average(3), average(3)+N(3)]);
end
%==================Create view matrix===================
focus = [1.5,0,1.5]; %The point we're looking at
Cx = 3; Cy = -3; Cz = 3; %Position of camera
Vspec = [0;0;1]; %Specified up direction
T = viewMat(focus, [Cx,Cy,Cz],Vspec); %Create viewspace transform matrix
p = norm(focus - [Cx,Cy,Cz]);
U = T(1,1:3); V = T(2,1:3); N = T(3,1:3); %New Up, Right & View direction vectors
%============Plot the camera vectors=================
scatter3(Cx,Cy,Cz,'s') %Plot the camera position
plot3([Cx, Cx+p*N(1)],[Cy, Cy+p*N(2)],[Cz, Cz+p*N(3)]);
plot3([Cx, Cx+V(1)],[Cy, Cy+V(2)],[Cz, Cz+V(3)]);
plot3([Cx, Cx+U(1)],[Cy, Cy+U(2)],[Cz, Cz+U(3)]);
%==================Transform into View Space===================
ws_vtx = T*vertcat(ws_vtx,(ones(1, length(ws_vtx)))); %Transform matrix
ws_vtx = ws_vtx(1:3,:); %Remove homogenous dimension
origin = T*[Cx;Cy;Cz;1]; %Transform origin
Cx = origin(1); Cy = origin(2); Cz = origin(3); %remove homogenous dimension
focus = (T*horzcat(focus,1)')';%Transform focus point
focus = focus(:,1:3);%remove homogenous dimension
%==================Plot View Space=================
figure(); hold on; grid on;
patch('Faces',ws_fcs','Vertices',ws_vtx','Facecolor', 'none');
scatter3(Cx, Cy, Cz, 's');
scatter3(focus(1), focus(2), focus(3), 's');
plot3([Cx, focus(1)],[Cy, focus(2)],[Cz,focus(3)], 'g');
for i = 1:length(ws_vtx)
str = sprintf('%d',i);
text(ws_vtx(1,i),ws_vtx(2,i),ws_vtx(3,i), str,'FontSize',16, 'Color','r', 'FontWeight','b');
end
%================Plot normals of world space==============
for i = 1:length(ws_fcs); %For each triangle
points(:,1:3) = ws_vtx(:,ws_fcs(1:3,i));
U = points(:,2) - points(:,1); %Get two non-parallel vectors
V = points(:,3) - points(:,1);
average = [0,0,0];
for j = 1:length(points)
average(j) = (points(j,1) + points(j,2) + points(j,3))/3;
end
N = cross(U,V)/norm(cross(U,V)); %Normal, normalised to mag 1
scatter3(average(1),average(2),average(3));
plot3([average(1), average(1)+N(1)],[average(2), average(2)+N(2)],[average(3), average(3)+N(3)]);
end