法線向量判定法適用於無凹陷的凸多面體,例如正多面體或水晶球,其原理為求出每個面的法線向量,如果法線向量的Z 分量大於0(即面朝向我們),則該面為可視,如果法線向量的Z分量小於0,則看不到那個面,則這是個隱藏面,所以無需繪製。 ![]() 法線向量的選擇是由面上的三個頂點來判定,三個頂點的選擇是依面的逆時針方向的來選出,然後求出這三個頂點所成的兩向量之外積即為法線向量,通常我們取單位法線向量(normalize後的外積),下面這個程式片段可以作為外積計算的參考: // 取得外積
public static Point3D op(Point3D p0, Point3D p1, Point3D p2) { p1.x = p1.x-p0.x; p1.y = p1.y-p0.y; p1.z = p1.z-p0.z; p2.x = p2.x-p0.x; p2.y = p2.y-p0.y; p2.z = p2.z-p0.z; double x = p1.y*p2.z - p1.z*p2.y; double y = p1.z*p2.x - p1.x*p2.z; double z = p1.x*p2.y - p1.y*p2.x; return new Point3D(x, y, z); } // 計算單位向量 public static Point3D ev(Point3D p) { double d = Math.sqrt(p.x*p.x + p.y*p.y + p.z*p.z); if(d > 0.0) return new Point3D(p.x/d, p.y/d, p.z/d); else return p; } // 取得nomalize後的外積 public static Point3D nop(Point3D p0, Point3D p1, Point3D p2) { return ev(op(p0, p1, p2)); } 配合外積,可以利用下面這個程式片段進行隱藏面的判斷與非隱藏面的繪製,其中vet[]是頂點陣列,NFc?表示凸面體的平面數量,Nvt表示一個平面上的頂點數 ,ord[][]表示頂點索引陣列: int N = 0;
Point[][] pvt = new Point[NFc][Nvt]; int[] n = new int[Nvt]; Point3D np; for(int i = 0; i < NFc; i++) { for(int j = 0; j < Nvt; j++) // 取同一個平面的頂點 n[j] = ord[i][j]; // 計算nomalize後的外積 np = nop(vet[n[0]], vet[n[1]], vet[n[2]]); // 如果非隱藏面 if(np.z > 0) { // 儲存頂點 pvt[N][j] = new Point(vet[n[j]].x, vet[n[j]].y); // 可繪製的面+1 N++; } } // 畫實心多邊形 for(int i = 0; i < N; i++) g.fillPolygon(pvt[i], Nvt); 上面這個程式只是個演算的參考,實作時得依您所使用的語言與API作調整。 |