塗抹效果,是在CAD軟體中常見的編修方式,在二維空間中是指按下滑鼠的同時開始繪圖,直到放開滑鼠後才停止繪圖的效果。而在三維空間中則是可透過時間函數的加入,加以呈現模型不斷變型的效果,再進階一點還可以搭配滑鼠的移動軌跡速度做均勻塗抹的效果。
首先在 Editor 加入一個變數用來存放時間函數的ID。
this.timer = null;
接著到 mouseDown 加入時間函數 setInterval 用來不斷的執行繪圖功能。
self.timer = window.setInterval(() => {
//Do Something
}, 100);
最後到 mouseUp 中加入 clearInterval ,目的在滑鼠放開後清除時間函數停止繪圖。
window.clearInterval(self.timer);
首先要在時間函數內撰寫繪圖功能,必須不斷的重新取得射線,同樣的要找到最近點的位置與法向量,並給予法向量一個強度係數。
viewer.intersects = viewer.raycaster.intersectObjects(viewer.scene.children);
if (viewer.intersects.length > 0) {
var vertices = self.getVertices();
var nearest = self.getNearest(vertices, self.viewer.intersects[0].point);
var normal = self.pointNormal(nearest);
var scalarNormal = normal.multiplyScalar(1.01);
// Draw Something
}
接著改變網格頂點的位置,只要對模型與拓樸關係都加上已經乘上強度係數的法向量。
var geometry = intersected.object.geometry;
geometry.vertices[nearest.ID].add(scalarNormal);
nearest.vector3.add(scalarNormal);
然後因為頂點被移動後,鄰近的面法向量也會改變,所以根據先前所學到的,利用拓樸關係將每個面的法向量重新計算。
for (var i = 0; i < nearest.faceIDs.length; i++) {
var id = nearest.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];
cb.subVectors(vC, vB);
ab.subVectors(vA, vB);
cb.cross(ab);
geometry.faces[id].normal.copy(cb.normalize());
}
最後同樣的需要告訴 Three.js 需要更新模型資訊,結果如下圖。
geometry.normalsNeedUpdate = true;
geometry.verticesNeedUpdate = true;
geometry.elementsNeedUpdate = true;
模型塗抹效果
https://github.com/QQBoxy/threecad/tree/master/models
https://qqboxy.github.io/threecad/public/example17.html
https://github.com/QQBoxy/threecad/blob/master/client/example17/Editor.js
塗抹效果的原理並不困難,聰明的妳一定發現了,這樣的塗抹效果好像不是很平滑? 大家可以想想看,是什麼原因造成這個問題呢?