代码之家  ›  专栏  ›  技术社区  ›  davidhood2

图形管道:视图空间和背面剔除

  •  0
  • davidhood2  · 技术社区  · 9 年前

    我正在尝试对一个简单的图形管道进行建模——目前使用Matlab作为建模工具,以获得正确的转换。我很感激有软件工具可以让这变得更容易,但我希望了解它背后的数学,因此我希望主要使用简单的函数和;我正在学习的矩阵 book (非常复古!)。

    我已经成功地完成了定义简单对象并将其转换为通用世界空间的各个阶段,但在将对象转换为视图空间和背面剔除所需的数学知识方面,我已经脱颖而出。

    我相信我的视图空间变换是正确的,因为当我绘制合成向量时,它们看起来是正确的-但当我进行背面剔除时,它似乎无法删除正确的三角形。鉴于它只取决于两件事,视线向量和面部法线,我无法确定我做错了什么。

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

    enter image description here

    我的问题是:

    • 我做错了吗,还是我的期望不正确?
    • 如果是,我在哪里,如何修复?

    进步

    我已经绘制了视图空间中所有形状的法线。它们都已倒置,现在指向内部。这是变换的一个属性吗?它是不是应该负责?或者因为所有多边形都受到相同的影响,所以这不会产生任何影响?

    (已更改代码以显示此内容)

    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
    
    1 回复  |  直到 9 年前
        1
  •  0
  •   davidhood2    9 年前

    我(相信)我已经解决了这个问题(即使花了两天时间)。我的问题本质上是我想取面部法线和视线矢量的点积,如下所示

    enter image description here

    并确定角度,以查看面部是否朝向或远离视点。

    我的错误步骤是,我是在从世界空间转换到视图空间之后才这样做的,因此我使用的视线矢量不再有效。

    因此,为了解决这个问题,我只是在世界视图空间转换之前,在世界空间中执行了背面剔除!

    我包含了显示背面剔除的功能代码,但没有显示视图空间转换。

    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');