[Babylon.js]如何重新设定引入的文件的中心(更改positionGizmo的显示位置)

[Babylon.js]如何重新设定引入的文件的中心(更改positionGizmo的显示位置)

关键词:

  • 加载外部文件
  • 重定中心
  • 更改positionGizmo显示位置

前言:

​ 在Babylon.js的使用过程中,难免需要引入一些外部文件来构建模型,例如obj,stl文件,还有Babylon.js官方所建议使用的babylon文件。这些外部文件本身都是包含位置信息和中心点信息的,所以在加载完成后可能出现一个现象,那就是加载后的mesh的中心点和世界坐标系的中心点重合,直观一点的表达就是加载的mesh的positionGizmo显示在整个空间的中心,就像下面这张图。在这里插入图片描述

原始问题:

​ 更改positionGizmo的显示位置,将显示位置显示在模型上,或者显示在模型的正中央。

困难:

  1. 没有什么可以直接调用的方法用于移动positionGizmo的显示位置
  2. 由于文件本身包含位置信息,所以世界坐标系和模型本身坐标系是重合的,更改坐标系的办法并不可行

解决:

  • 引入文件,并添加Gizmo

    BABYLON.SceneLoader.ImportMesh("", "/scenes/", "Rabbit.babylon", scene, function (newMeshes) {
        	var mesh = newMeshes[0];
            var gizmoManager = new BABYLON.GizmoManager(scene);  
            gizmoManager.positionGizmoEnabled = true;
            gizmoManager.boundingBoxGizmoEnabled = gizmoManager.rotationGizmoEnabled = gizmoManager.scaleGizmoEnabled = false;
            gizmoManager.attachToMesh(mesh);
    
            document.onkeydown = (e)=>{
                if (e.key == '&' || e.key == 'é' || e.key == 'r' || e.key == 'q'){
                    gizmoManager.positionGizmoEnabled = false;
                    gizmoManager.rotationGizmoEnabled = false;
                    gizmoManager.scaleGizmoEnabled = false;
                    gizmoManager.boundingBoxGizmoEnabled = false;
                    if(e.key == '&'){
                        gizmoManager.positionGizmoEnabled = true;
                    }
                    if(e.key == 'é'){
                        gizmoManager.rotationGizmoEnabled = true;
                    }
                    if (e.key == 'r'){
                        gizmoManager.scaleGizmoEnabled = true;
                    }
                    if(e.key == 'q'){
                        gizmoManager.boundingBoxGizmoEnabled = true;
                    
                    }
                }
                if(e.key == '²'){
                    gizmoManager.attachToMesh(null);
                }
    
                if(e.key == 'a'){
                gizmoManager.gizmos.positionGizmo.updateGizmoRotationToMatchAttachedMesh = !gizmoManager.gizmos.positionGizmo.updateGizmoRotationToMatchAttachedMesh;
                gizmoManager.gizmos.rotationGizmo.updateGizmoRotationToMatchAttachedMesh = !gizmoManager.gizmos.rotationGizmo.updateGizmoRotationToMatchAttachedMesh;
    
                }
    
                if(e.key == 's'){
                    if (gizmoManager.gizmos.scaleGizmo.snapDistance == 0){
                        gizmoManager.gizmos.scaleGizmo.snapDistance = 0.3;
                        gizmoManager.gizmos.rotationGizmo.snapDistance = 0.3;
                        gizmoManager.gizmos.positionGizmo.snapDistance = 0.3;
                    }else{
                        gizmoManager.gizmos.scaleGizmo.snapDistance = 0;
                        gizmoManager.gizmos.rotationGizmo.snapDistance = 0;
                        gizmoManager.gizmos.positionGizmo.snapDistance = 0 ;
                        } 
                    }
                }
    
        });
    

    此时运行代码,可以看到上面那副图中所显示的情况,此时希望重设加载的mesh的中心点,也就是将positionGizmo的显示位置移动到mesh上。

  • 借助Boundingbox的中心点信息解决问题,Boundingbox的中心点就是所需要的mesh的中心点,也就是positionGizmo应该正确显示的位置

    var oldPivotTranslation = mesh.getBoundingInfo().boundingBox.centerWorld.clone();
    

    使用这样的一行代码来获取Boundingbox的中心点坐标。

  • 然后再使用如下的代码来将mesh设置在boundingbox的中心点,此步骤的目的是为了后面重新设定mesh的中心点

    mesh.position.set(oldPivotTranslation.x, oldPivotTranslation.y, oldPivotTranslation.z);
    
  • 此时,mesh被放在了世界坐标系的中心,下一步重新设置mesh的中心点

    mesh.setPivotMatrix(BABYLON.Matrix.Translation(0, 0, 0), false);
    
  • 重设完成后进行如下处理

    mesh.bakeCurrentTransformIntoVertices();
    
  • 这个方法基于世界坐标系重置了mesh的坐标,Babylon.js官方描述如下:

    Modifies the mesh geometry according to its own current World Matrix. The mesh World Matrix is then reset. This method returns nothing but really modifies the mesh even if it’s originally not set as updatable. Note that, under the hood, this method sets a new VertexBuffer each call.

    Babylon.js相关文档地址:

    bakeCurrentTransformIntoVertices

    Baking Transformations

  • 最后,重新设定mesh的坐标,让其回到其原本的位置上

    mesh.position.set(oldPivotTranslation.x, oldPivotTranslation.y, oldPivotTranslation.z);
    

最终结果:

在这里插入图片描述

完整代码:

var createScene = function () {
    var scene = new BABYLON.Scene(engine);

    //Adding a light
    var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(20, 20, 100), scene);

    //Adding an Arc Rotate Camera
    var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI/2, 1.4, 500, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, false);
    camera.setTarget(new BABYLON.Vector3(0, 0, 0));

    // The first parameter can be used to specify which mesh to import. Here we import all meshes
    BABYLON.SceneLoader.ImportMesh("", "/scenes/", "Rabbit.babylon", scene, function (newMeshes) {
        
        var mesh = newMeshes[0];   

        var oldPos = mesh.position.clone();
        var oldPivotTranslation = mesh.getBoundingInfo().boundingBox.centerWorld;
        mesh.position.set(-oldPivotTranslation.x, -oldPivotTranslation.y, -oldPivotTranslation.z);    
        mesh.setPivotMatrix(BABYLON.Matrix.Translation(0, 0, 0), false);
        mesh.bakeCurrentTransformIntoVertices();
        var PosAfterBCTIV = mesh.position.clone();

        var gizmoManager = new BABYLON.GizmoManager(scene);
        //inicializar todos los gizos    
        gizmoManager.positionGizmoEnabled = true;
        gizmoManager.boundingBoxGizmoEnabled = gizmoManager.rotationGizmoEnabled = gizmoManager.scaleGizmoEnabled = false;
        gizmoManager.attachToMesh(mesh);

        //Modificador de gizo
        document.onkeydown = (e)=>{
            if (e.key == '&' || e.key == 'é' || e.key == 'r' || e.key == 'q'){
                gizmoManager.positionGizmoEnabled = false;
                gizmoManager.rotationGizmoEnabled = false;
                gizmoManager.scaleGizmoEnabled = false;
                gizmoManager.boundingBoxGizmoEnabled = false;
                if(e.key == '&'){
                    gizmoManager.positionGizmoEnabled = true;
                }
                if(e.key == 'é'){
                    gizmoManager.rotationGizmoEnabled = true;
                }
                if (e.key == 'r'){
                    gizmoManager.scaleGizmoEnabled = true;
                }
                if(e.key == 'q'){
                    gizmoManager.boundingBoxGizmoEnabled = true;
                
                }
            }
            if(e.key == '²'){
                gizmoManager.attachToMesh(null);
            }

            if(e.key == 'a'){
            gizmoManager.gizmos.positionGizmo.updateGizmoRotationToMatchAttachedMesh = !gizmoManager.gizmos.positionGizmo.updateGizmoRotationToMatchAttachedMesh;
            gizmoManager.gizmos.rotationGizmo.updateGizmoRotationToMatchAttachedMesh = !gizmoManager.gizmos.rotationGizmo.updateGizmoRotationToMatchAttachedMesh;

            }

            if(e.key == 's'){
                if (gizmoManager.gizmos.scaleGizmo.snapDistance == 0){
                    gizmoManager.gizmos.scaleGizmo.snapDistance = 0.3;
                    gizmoManager.gizmos.rotationGizmo.snapDistance = 0.3;
                    gizmoManager.gizmos.positionGizmo.snapDistance = 0.3;
                }else{
                    gizmoManager.gizmos.scaleGizmo.snapDistance = 0;
                    gizmoManager.gizmos.rotationGizmo.snapDistance = 0;
                    gizmoManager.gizmos.positionGizmo.snapDistance = 0 ;
                    } 
                }
            }

    });

    scene.onBeforeRenderObservable.add(function(){
        light.position = camera.position;
    });

    return scene;
}

PlayGround地址

PlayGround

总结:

​ 我把这个问题发在了Babylon.js的官方论坛上求助,首先大家就教导我“要用PlayGround解决问题,我们都喜欢用PlayGround解决问题”,在解决这个问题的过程中体验了一把,确实,这个工具的确很好用。

​ 一位title是Babylonian的热心网友的一句话打动了我:I have so much to learn,我不知道这个title的含义是不是Babylon创始人或者Babylon项目组成员,但是,保持一颗学习的心是无比重要的。

​ 另外,英语也是尤为重要的,以往学习的技术大多有详细的中文文档和教程,但是Babylon.js相对冷门一点,国内没有成熟的学习环境,因此,必须阅读原版的英文文档和使用英文和其他人交流学习。很快就出六级成绩了,希望能过,以后可能不再有机会了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值