網格頂點的平均法向量,是指一個網格頂點,找尋鄰近的三角網格面,將所有面的法向量進行相加,再取單位向量的結果。
八個面的平均法向量
首先將上回的 getVertices 函數進行改寫,我們改將 vertices 存入拓樸的vertex以夾帶拓樸資訊。
vertices.push(intersected.object.topology.vertex[ids[i]]);
再將 getNearest 函數改寫,距離資訊要使用拓樸網格資訊中的vector3資料。
distance = vertices[i].vector3.distanceTo(point);
然後建立一個 pointNormal 函數用來計算法向量,我們使用點拓樸中的faceIDs資訊,再由 reduce 來計算總和,其中我們透過 THREE.Vector3 的 add 函數來進行每個法向量的加總,最後再執行向量的正規化。
Editor.prototype.pointNormal = function (point) {
var self = this;
var i = 0;
var intersected = self.viewer.intersects[0];
return point.faceIDs.reduce((accumlator, currentValue, currentIndex, array) => {
// 取得每個面的法向量
var normal = intersected.object.geometry.faces[currentValue].normal;
//法向量的加總
return accumlator.add(normal);
}, new THREE.Vector3()).normalize(); //最後需要將結果正規化
};
最後延續上回的程式在 mouseDown 內執行 pointNormal 就完成了平均法向量的計算。
var normal = self.pointNormal(nearest);
首先給法向量一個係數,決定向量要畫的長度。
var scalarNormal = normal.multiplyScalar(3);
接著給予兩個點座標,一個是頂點本身,一個是拷貝頂點後加上法向量的新座標,
var geometry = new THREE.Geometry();
geometry.vertices.push(nearest.vector3);
geometry.vertices.push(new THREE.Vector3().copy(nearest.vector3).add(scalarNormal));
最後給予 LineBasicMaterial 材質並建立 THREE.Line 並加到場景就完成這次的畫法向量範例了,結果如下圖。
var material = new THREE.LineBasicMaterial({ color: 0xffff00 });
var line = new THREE.Line(geometry, material);
line.skip = true;
self.viewer.scene.add(line);
self.viewer.meshs.push(line);
點選網格點並計算平均法向量
https://github.com/QQBoxy/threecad/tree/master/models
https://qqboxy.github.io/threecad/public/example16.html
https://github.com/QQBoxy/threecad/blob/master/client/example16/Editor.js
這次教大家如何找尋網格頂點的平均法向量,在建立與網格頂點有關的編輯工具時,經常會需要計算網格頂點的法向量,在撰寫CAD軟體時也是一個普遍需要用到的功能函式。