天天看點

BIM輕量化之路(四)-模型優化一、模型居中二、z-fighting 問題二、平滑移動

一、模型居中

上文加載模型後發現threejs的原點對應的是revit的項目基點,這樣導緻初始加載後左右拖動建築是圍繞Y旋轉,體驗很差,是以模型初始化時候模型居中、旋轉,代碼如下:

function setCenter() {
        var box3 = new THREE.Box3();
		// 計算層級模型group的包圍盒
		// 模型group是加載一個三維模型傳回的對象,包含多個網格模型
		//擴充此包圍盒的邊界,使得對象及其子對象在包圍盒内,包括對象和子對象的世界坐标的變換。
        box3.expandByObject(scene);
        var center = new THREE.Vector3(0, 0, 0);
		// 計算一個層級模型對應包圍盒的幾何體中心在世界坐标中的位置
        box3.getCenter(center);
        console.log('檢視幾何體中心坐标', center);
        console.log('坐标', scene.position);
		// 重新設定模型的位置,使之居中。
        scene.position.x = scene.position.x - center.x
        scene.position.y = scene.position.y - center.y
        scene.position.z = scene.position.z - center.z;
        console.log('坐标', scene.position);
    }
           

原理是将場景放入到box中,拓展包圍盒與場景的大小一緻,然後通過包圍盒居中的坐标計算後将場景居中。

如果想和revit展示一緻,需要對模型進行180度的旋轉,因為revit和threejs的坐标系表示不同,左手坐标系和右手坐标系。

BIM輕量化之路(四)-模型優化一、模型居中二、z-fighting 問題二、平滑移動
gLTFLoader.load(url, function(obj) {
        obj.scene.rotateY(Math.PI);//旋轉180度
        .....
   }, onProgress);``
           

二、z-fighting 問題

加載的模型有些疊加的部分随着錄影機的拉動會閃爍,如圖:

BIM輕量化之路(四)-模型優化一、模型居中二、z-fighting 問題二、平滑移動

查詢資料是因為疊加部分的mesh共用了一個深度值,渲染器不知道該渲染那個導緻閃爍,這便是Z-Fighting問題,相關問題的詳細說明:

https://www.cnblogs.com/lst619247/p/9098845.html

this.renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById("canvas-model-view"),
        antialias: true, //設定抗鋸齒
        alpha: true, //背景透明
        autoClear: true,
        logarithmicDepthBuffer: true
    });
           

需要将logarithmicDepthBuffer參數設為true即可

二、平滑移動

要想使錄影機平滑移動至某一點,需要貝塞爾曲線,貝塞爾曲線通過很少的控制點,去生成複雜的平滑曲線,通過擷取到了曲線上的點來移動錄影機進而達到平滑移動的效果,threejs提供了CubicBezierCurve3方法來實作貝塞爾曲線。

function toPosition(targetX,targetY,targetZ){
    //擷取目前camera位置
    let camPosition=viewer.camera.position;         //擷取錄影機目前位置
    let newPosition=new THREE.Vertex(targetX,targetY,targetZ);     //設定目标位置
    let curve=addLines(camPosition,newPosition).curve;    //繪制貝塞爾曲線
    //取curve的10個點
    let points=curve.getPoints(10);
    let index=0;
    //錄影機每50毫秒移動一個點的位置
    let a=setInterval(function () {
        viewer.camera.position.set(points[index].x,points[index].y,points[index].z);
        viewer.camera.lookAt(new THREE.Vertex(0,0,0))
        index++;
        viewer.render();
        if(index>10){
            clearInterval(a);
        }
    },50);
}
// 添加線條
function addLines(v0, v3) {
    // 計算向量夾角
    let angle = v0.angleTo(v3) * 270 / Math.PI / 10; // 0 ~ Math.PI
    let aLen = angle * 50,
        hLen = angle * angle * 120;
    let p0 = new THREE.Vector3(0, 0, 0);
    // 開始,結束點
    // let v0 = groupDots.firstObjectren[0].position;
    // let v3 = groupDots.children[1].position;
    // 法線向量
    let rayLine = new THREE.Ray(p0, getVCenter(v0.clone(), v3.clone()));
    // 頂點坐标
    let vtop = rayLine.at(hLen / rayLine.at(1).distanceTo(p0));
    // 控制點坐标
    let v1 = getLenVcetor(v0.clone(), vtop, aLen);
    let v2 = getLenVcetor(v3.clone(), vtop, aLen);
    // 繪制貝塞爾曲線
    let curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3);
    let geo = new THREE.Geometry();
    geo.vertices = curve.getPoints(10);
    let mat = new THREE.LineBasicMaterial({color: 0xff0000});
    return {
        curve: curve,
        lineMesh: new THREE.Line(geo, mat)
    };
}
// 計算v1,v2 的中點
function getVCenter(v1, v2) {
    let v = v1.add(v2);
    return v.divideScalar(2);
}

// 計算V1,V2向量固定長度的點
function getLenVcetor(v1, v2, len) {
    let v1v2Len = v1.distanceTo(v2);
    return v1.lerp(v2, len / v1v2Len);
}
           

效果如下:

BIM輕量化之路(四)-模型優化一、模型居中二、z-fighting 問題二、平滑移動
bim

繼續閱讀