我正在尝试对一个简单的图形管道进行建模-目前使用Matlab作为建模工具来正确完成转换。我赞赏有一些软件工具可以使此操作更容易-但我希望了解其背后的数学原理,因此希望主要使用从书中学习的简单函数和矩阵(非常复古!)。 />
我已经成功完成了定义简单对象并将其转换为通用世界空间的阶段-但对于将对象转换为视图空间和背面剔除所需的数学却不感兴趣。 />
我相信我的视图空间变换是正确的,因为当我绘制复合矢量时,它们看起来是正确的-但是-当我进行背面剔除时,似乎无法去除正确的三角形。鉴于它仅取决于两点,即视线矢量和面法线,所以我无法弄清我做错了什么。

在局部定义空间中定义三角形时,我这样做是为了使所有法线都朝外。我已将结果放入下图中。



我的问题是:


我错了,还是我的期望不正确吗?
如果在哪里,应该如何解决?


进展

在视野中。它们都已倒置,现在指向内。这是变换的属性吗,可能是造成这种变化的原因吗?或者这应该是无效的,因为所有多边形都受到相同的影响吗? br />
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


评论

轴上的数字范围在三个图表之间变化,并且第二个和第三个标记了更多顶点。这些变换的版本是同一个立方体还是三个单独的形状?

有关在Meta Stack Exchange上突出显示语法的信息,但似乎不支持Matlab。

第一个形状是在其局部坐标上绘制了法线的复合世界空间形状之一的示例。 Middel和右手图是变换后的相同世界空间形状

只是FYI,在GPU中,对顶点的投影后值进行了背面剔除(或可以认为是完成了),因此仅需要考虑3个三角形顶点的X&Y值。 (这样做的原因有很多:避免浮点舍入为一的问题)

#1 楼

我(相信)我已经解决了这个问题(即使已经花了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');