iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 17
1
Modern Web

在Three.js探索CAD的奧秘系列 第 17

Day 17 : 修正面的法向量

前言

面的法向量,除了用來表示該面的正反面以外,也是用來表示面的確切方向的資訊,正確的法向量可以使光源正確的模擬出照射效果並合理的渲染出來。

尋找法向量

前回我們將某一面往法向量方向舉升,造成該網格周圍的面被改變,這時候這些面的法向量其實是會改變的,因此需要將這些面的法向量進行修正,並且運用拓樸關係找到相鄰的面有哪些。
首先宣告一個 faceIDs 用來存放被改變的面。

var faceIDs = [];

接下來可以透過上回跑三個頂點的迴圈,順便利用 點拓墣關係 來找尋與點相鄰的面,這裡偷懶使用ES6的展開運算子(Spread Operator)來進行陣列的合併。

faceIDs.push(...topology.vertex[vid].faceIDs);

最後過濾掉有重複的面,簡單用filter查找就行了。

faceIDs = faceIDs.filter(function (face, index, arr) {
    return arr.indexOf(face) === index;
});

重新計算面的法向量

有了這些面以後,接下來要重新計算法向量,首先在迴圈內建立兩個向量cb、ca表示某片網格的兩個邊,並且取得三個點座標資訊。

for (var i = 0; i < faceIDs.length;i++) {
    var id = faceIDs[i];
    var cb = new THREE.Vector3();
    var ab = new THREE.Vector3();
    var vA = geometry.vertices[geometry.faces[id].a];
    var vB = geometry.vertices[geometry.faces[id].b];
    var vC = geometry.vertices[geometry.faces[id].c];
    // Do Something
}

接下來要將B、C兩點以及A、B兩點各連成一個向量,然後透過高中學過的外積求得垂直的法向量。

cb.subVectors(vC, vB);
ab.subVectors(vA, vB);
cb.cross(ab);

然後將新的法向量正規化就可以用來更新原本每個面的法向量。

geometry.faces[id].normal.copy(cb.normalize());

最後告訴Three.js法向量需要更新就可以了,結果如圖。

geometry.normalsNeedUpdate = true;

https://i.imgur.com/J6tmEbv.gif
修正法向量後變形

範例原始碼

https://github.com/QQBoxy/threecad/blob/master/client/example13/Editor.js

後記

眼尖的你可能發現了,計算法向量時其實有順時針、逆時針的差別,這會導致法向量的方向完全相反,但其實STL三角網格檔案有一個不成文的規定,就是vertex座標在儲存的時候大家都會順著相同的方向儲存,所以一般來說不必太擔心網格翻轉的問題,但如果真的不幸遇到了就必須再透過網格翻轉的演算法進行修復喔。


上一篇
Day 16 : 簡單網格變形
下一篇
Day 18 : 模型所見即得的設計
系列文
在Three.js探索CAD的奧秘30

尚未有邦友留言

立即登入留言