vue使用three.js实现外部加载模型的自动缩放的效果(进一步优化)

一、vue使用three.js加载外部模型自适应渲染区域大小

1、实现效果

当在http://localhost:8080/#/scale?name=tree2.glb 中name参数中输入不同名字的.glb模型时,都可以自动进行缩放来适用所定义页面的大小。

但需要注意的是:模型需要为.glb格式。若不是glb格式,可以通过blender软件进行导入后再导出为glb格式。

vue使用three.js实现外部加载模型的自动缩放的效果(进一步优化)_第1张图片

2、实现思路

(1)定义一个Scene、PerspectiveCamera、WebGLRenderer以及包含AmbientLight和DirectionalLight的混合光。

(2)设置渲染区域大小:this.renderer.setSize(this.width,this.height);

(3)加载外部模型。使用GLTFLoader加载器加载获取到的外部的.glb模型,并把mesh放在group组中,对group进行操作。

(4)因为模型是不规则的,为了更好的计算模型的大小,我们引入了Box3。使用THREE.Box3().setFromObject(group)计算gruop的包围盒的大小,并放group在原点位置。然后根据公式计算得到3d模型对应的画布上group的大小(2D宽度和高度)。

计算过程:

// 计算相机到物体正面的距离。
let dist =Math.abs(self.camera.position.z - group.position.z- (mdwid/2));

// 将垂直fov转换为弧度 。
let vFov = self.camera.fov * Math.PI/180;

// 可见高度。
let vheight = 2 * Math.tan(vFov * 0.5) *dist;

// 可见高度的分数。
let fraction = mdhei / vheight;

// 立方体的高度(以像素为单位)是画布的高度(以像素为单位)的fraction倍。
let finalHeight = self.height * fraction ; 

// 包围盒计算的高/finalHeight = 包围盒计算的宽/finalWidth 。   
let finalWidth = (finalHeight*mdlen) /mdhei;  

(5)通过该2D宽度和高度分别与设置的渲染区域的宽和高相比得到两个不同的缩放比例value1和value1。选取两者较小的值,设置为group的缩放比例。

    let value1 = self.width/finalWidth;
    console.log('value1缩放比例值为:' + value1);
    let value2 = self.height/finalHeight;
    console.log('value2缩放比例值为:' + value2);

    if(value1 >= value2){
        group.scale.set(value2,value2,value2);
    }
    else{
        group.scale.set(value1,value1,value1);
    } 

(6)再一次使用使用THREE.Box3().setFromObject(group)计算gruop的包围盒的大小(这个是缩放后的group),并重新设置position属性。注意:在z轴上设置group位置时不要忘记减去包围盒深度的1/2。

    let bbox2= new THREE.Box3().setFromObject(group)
    let mdlen2=bbox2.max.x-bbox2.min.x;
    let mdhei2=bbox2.max.y-bbox2.min.y;
    let mdwid2=bbox2.max.z-bbox2.min.z;
    group.position.set(-(bbox2.max.x+bbox2.min.x)/2, -(bbox2.max.y+bbox2.min.y)/2,
     -(bbox2.max.z+bbox2.min.z)/2 - (bbox2.max.z-bbox2.min.z)/2);

(7)最后将group添加到scene中。同时引入了AxisHelper来帮助显示坐标轴,以及OrbitControls轨道控制器来控制模型的平移、旋转和缩放效果。

     let axes = new THREE.AxisHelper(100);
     this.scene.add(axes); 
	
     let controls = new OrbitControls(this.camera, this.renderer.domElement);

二、使用vue对组件封装以及复用

1、子组件封装过程

(1)、建立组件的模板,把架子搭起来,并设计组件的基本逻辑。

(2)、定义Props里面的数据、类型。其中width是渲染区域的宽度,height是渲染区域的高度,modelUrl是模型的名字,默认是tree2.glb。

props:{  
    width:{type:Number}, 
    height:{type:Number},
    modelUrl:{type:String,default:'tree2.glb'}
    },

(3)、export default 向外暴露的成员。在一个模块中,export default 只允许向外暴露一次。

2、父组件调用过程

(1)、导入子组件。

 import ModelScale from './components/ModelScale.vue'
 
 export default{
 	...
    components:{ModelScale},
    ...
 }

(2)、 通过this.$route.query获取url中参数数据,然后监听数据的变化。我们这里只获取了模型名字modelnamet,渲染区域的宽度width和高度height我们已定义好。实际中,定义参数数据个数可以根据自己需要进行操作即可。

computed:{
    key(){
        this.modelname = this.$route.query.name;
        return this.modelname;           
    }
},

(3)、自定义组件标签,将监听到的数据返回给标签中定义的变量。

    

(4)、子组件就可以对数据进行接收和使用了。

三、完整代码

子组件 BoxSwitch1.vue






父组件 index.vue



你可能感兴趣的:(three.js学习)