我正在尝试建模一个简单的图形管道 - 目前使用Matlab作为建模工具来使转换正确。我很欣赏有一些软件工具可以让这更容易 - 但我希望了解它背后的数学,因此我希望大多使用简单的功能和放大器。我正在从book学习的矩阵(非常复古!)。
我已经成功地完成了定义简单对象并将它们转换为通用世界空间的各个阶段 - 但是已经解决了将对象转换为视图空间和背面剔除所需的数学问题。
我相信我的视图空间转换是正确的,因为当我绘制合成矢量时它们看起来是正确的 - 但是 - 当我进行背面剔除时,似乎无法移除正确的三角形。鉴于它只取决于两个方面,即视线矢量和面法线,我无法弄清楚我做错了什么。
在本地定义空间中定义三角形时,我这样做是为了使所有法线向外指向。我把结果放在下面的图片中
我的问题是:
我在视图空间中绘制了所有形状的法线。他们都被倒置了,现在指向内部。这是变换的属性吗?它可能是负责任的 - 或者这应该没有效果,因为所有多边形都受到相同的影响?
(已更改代码以显示此内容)
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
答案 0 :(得分:0)
我(相信)我已经解决了这个问题(即使花了2天时间)。我的问题基本上是我想采取面部正常的点积和下面的
视线矢量确定角度以查看脸部是朝向还是远离视点。
我错误的一步是我在从世界空间转换到视野之后这样做 - 因此我使用的视线向量不再有效。
因此,为了解决这个问题,我只是在世界观空间转型之前,在世界空间中进行了背面剔除!
我已经包含显示背面剔除的功能代码,但不包括视图空间转换。
clear; clc; close all;
%======Create World Space (hard-coded values for demo) ===========
ws_vtx = [0,2,0,2,1,0.5,1.5,0.5,1.5,0.5,1.5,0.5,1.5;
0,0,0,0,-2,0,0,2,2,0,0,2,2;
0,0,2,2,1,0.5,0.5,0.5,0.5,1.5,1.5,1.5,1.5];
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];
%==================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=================
grid on; hold on; 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)],'g');
plot3([Cx, Cx+V(1)],[Cy, Cy+V(2)],[Cz, Cz+V(3)],'g');
plot3([Cx, Cx+U(1)],[Cy, Cy+U(2)],[Cz, Cz+U(3)],'g');
%===========Get Face Normals============================
norm_fcs = zeros(3,length(ws_fcs));
for i = 1:length(ws_fcs); %For each triangle
points = zeros(3,3); %Contains 1 triangle
points(:,1:3) = ws_vtx(:,ws_fcs(1:3,i)); %Get points for triangle
U = points(:,2) - points(:,1); %Get two non-parallel vectors
V = points(:,3) - points(:,1);
norm_fcs(:,i) = cross(U,V); %Normal, normalised to mag 1
end
%=================Back Face Culling======================
null_vals = 0;
for i = 1:length(ws_fcs) %Take each triangle & calculate normal
if dot(norm_fcs(:,i), N) > 0 %Dot product line of sight & normal of faces
ws_fcs(:,i) = [0;0;0]; %If > 0, not visible & remove
null_vals = null_vals + 1; %And increment counter
end
end
ws_fcs_cat = zeros(3, length(ws_fcs) - null_vals); %Create new array
null_vals = 0;
for i = 1:length(ws_fcs)
if norm(ws_fcs(:,i)) == 0
null_vals = null_vals + 1;
else
ws_fcs_cat(:,i - null_vals) = ws_fcs(:,i);
end
end
ws_fcs = ws_fcs_cat;
%======Plot World Space ===========
scatter3(ws_vtx(1,:),ws_vtx(2,:),ws_vtx(3,:)) %Plot all the points
patch('Faces',ws_fcs','Vertices',ws_vtx','Facecolor', 'r', 'FaceAlpha', 0.5);
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
xlabel('x'); ylabel('y'); zlabel('z');