VUE Three.js 加载FBX模型并根据模型大小定位摄像机初始位置并可以全屏并可以有测量长度功能....并封装成组件

知识点:1.VUE 的 three.js 安装 直接cnpm install three 就好

至于FBX导入 相机控制 就单独引入就好比如:

import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader'         

import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'

2.FBX模型加载 

 var loader = new FBXLoader();
        // modelsrc为模型路径
	loader.load(this.modelsrc,geometry =>{
    this.scene.add (geometry) }

3.根据模型大小定位摄像机初始位置

var boxHelper = new THREE.BoxHelper();
var camera = new THREE.PerspectiveCamera( 50, 1, 1, 100000 );
boxHelper.setFromObject(mod);
var center = boxHelper.geometry.boundingSphere.center;
var radius = boxHelper.geometry.boundingSphere.radius;
var cameraPos = new THREE.Vector3(center.x+mod.position.x,center.y+mod.position.y,radius * 2.2 + center.z + mod.position.z);
var lookPos = new THREE.Vector3(center.x+mod.position.x,center.y+mod.position.y,center.z+mod.position.z);
camera.position.copy(cameraPos);
//这里有个需要注意的地方:如果使用了THREE.OrbitControls进行鼠标控制,那么一定要加上controls.target = lookPos;并在OrbitControls创建了之后加上camera.lookAt(lookPos);

var controls = new THREE.OrbitControls( camera, domElement );
controls.target = lookPos;
camera.lookAt(lookPos);

4 .raycaster 的偏移问题 

raycaster就是鼠标的点击事件可以获得位置 两点确定一条线 再求长度就是测距离了 但有时会偏移 所以用这个方法最好能规避

let container = document.getElementById('container3d');
        var mouse = new Three.Vector2();
        var raycaster = new Three.Raycaster();

        let getBoundingClientRect = container.getBoundingClientRect()
        let x = ((event.clientX - getBoundingClientRect .left) / container.offsetWidth) * 2 - 1;// 标准设备横坐标
        let y = -((event.clientY - getBoundingClientRect .top) / container.offsetHeight) * 2 + 1;// 标准设备纵坐标
        let standardVector = new Three.Vector3(x, y, 1);// 标准设备坐标
        // 标准设备坐标转世界坐标
        let worldVector = standardVector.unproject(this.camera);
        // 射线投射方向单位向量(worldVector坐标减相机位置坐标)
        let ray = worldVector.sub(this.camera.position).normalize();
        // 创建射线投射器对象
        let rayCaster = new Three.Raycaster(this.camera.position, ray);
        // 返回射线选中的对象 第二个参数如果不填 默认是false
        let intersects = rayCaster.intersectObjects(this.modelmesh.children, true);

5.全屏事件  但要注意要再加个检测事件 可以初始化所做的操作  (因为我是封装成组件 弹窗是个小窗口)

fillwindow(){
                let element = document.getElementById('fullcontent')
                let content = document.getElementById('container3d')
                // document.getElementById('container3d').innerHTML = "";
                if (this.fullscreen) {
                    // content.style.height = "500px"
                    if (document.exitFullscreen) {
                        document.exitFullscreen();
                    } else if (document.webkitCancelFullScreen) {
                        document.webkitCancelFullScreen();
                    } else if (document.mozCancelFullScreen) {
                        document.mozCancelFullScreen();
                    } else if (document.msExitFullscreen) {
                        document.msExitFullscreen();
                    }
                } else {
                    // content.style.height = "94vh"
                    console.log(element.style.width)
                    if (element.requestFullscreen) {
                        element.requestFullscreen();
                    } else if (element.webkitRequestFullScreen) {
                        element.webkitRequestFullScreen();
                    } else if (element.mozRequestFullScreen) {
                        element.mozRequestFullScreen();
                    } else if (element.msRequestFullscreen) {
                        // IE11
                        element.msRequestFullscreen();
                    }
                }
               


      },
mounted() {
    var that = this
    window.onresize = function(){
      if(that.modelopen==true){
        console.log('eeeeessssccc')
         document.getElementById('container3d').innerHTML = "";
          setTimeout(function()  {
  
              that.init3d()
          
            }, 1000);
            
            
                setTimeout(function()  {
                
                    that.animate3d()
                
                }, 1000);
          that.fullscreen = !that.fullscreen;
          if (that.fullscreen==true) {
            document.getElementById('container3d').style.height = "94vh";
          }else{
            document.getElementById('container3d').style.height = "500px";
          }
      }    
    };
},

 6.画线 两点确认一条线 就可以画线了 并获得两点距离换算成毫米

drawLine( p1, p2) {
 
        var directionVector = new Three.Vector3();
        var p3 = new Three.Vector3();
        directionVector.x = p2.x - p1.x;
        directionVector.y = p2.y - p1.y;
        directionVector.z = p2.z - p1.z;
        //两点距离换算成毫米
        var length = Math.sqrt( directionVector.x * directionVector.x
            + directionVector.y * directionVector.y
            + directionVector.z * directionVector.z);
        var text = Math.round( length*10 ) + "";
        var geometry = new Three.Geometry();
        var material = new Three.LineBasicMaterial( { opacity:1,color:0x00ff00 } );
        geometry.vertices.push(p1);
        geometry.vertices.push(p1);
        geometry.vertices.push(p2);
        var geo = new Three.Line(geometry, material)
        this.alllinearr.push(geo)
        this.scene.add(geo)
        p3.x = (p1.x+p2.x)/2
        p3.y = (p1.y+p2.y)/2
        p3.z = (p1.z+p2.z)/2
        console.log(p3)
        this.initText( text, p3 );
 
        
 
    },

7.根据 线条长度加上文字标注 要引用import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'

然后再定义个渲染器再init 初始化的时候

// 标签render

                    this.labelRenderer = new CSS2DRenderer();

                    this.labelRenderer.setSize( container.clientWidth,container.clientHeight );

                    this.labelRenderer.domElement.style.position = 'absolute';

                    this.labelRenderer.domElement.style.top = '0px';

                    container.appendChild( this.labelRenderer.domElement );

animate上也要加上this.labelRenderer.render(this.scene,this.camera)

initText( wordFont, p1){
      
        var font = this.makeTextSprite(wordFont,{
          fontsize: 30,
          borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
          backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
        });
        font.center = new Three.Vector2(0,0)
        
        // console.log(font)
        font.position.copy( p1 );
        this.scene.add(font)
        this.alltextarr.push(font)


 
    },
    makeTextSprite(message, parameters) {

        if ( parameters === undefined ) parameters = {};

        var fontface = parameters.hasOwnProperty("fontface") ?
            parameters["fontface"] : "Arial";

        /* 字体大小 */
        var fontsize = parameters.hasOwnProperty("fontsize") ?
            parameters["fontsize"] : 16;

        /* 边框厚度 */
        var borderThickness = parameters.hasOwnProperty("borderThickness") ?
            parameters["borderThickness"] : 3;

        /* 边框颜色 */
        var borderColor = parameters.hasOwnProperty("borderColor") ?
            parameters["borderColor"] : { r:0, g:0, b:0, a:1.0 };

        /* 背景颜色 */
        var backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
            parameters["backgroundColor"] : { r:255, g:255, b:255, a:1.0 };

        /* 创建画布 */
        var canvas = document.createElement('canvas');
        var context = canvas.getContext('2d');

        /* 字体加粗 */
        context.font = "Bold " + fontsize + "px " + fontface;

        /* 获取文字的大小数据,高度取决于文字的大小 */
        var metrics = context.measureText( message );
        var textWidth = metrics.width;

        /* 背景颜色 */
        context.fillStyle   = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
            + backgroundColor.b + "," + backgroundColor.a + ")";

        /* 边框的颜色 */
        context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
            + borderColor.b + "," + borderColor.a + ")";
        context.lineWidth = borderThickness;

        /* 绘制圆角矩形 */
        this.roundRect(context, 150/2, 125/2, textWidth + 50,  50,1);
        // this.roundRect(context, borderThickness/2, borderThickness/2, textWidth + borderThickness, fontsize * 1.4 + borderThickness,1);

        /* 字体颜色 */
        context.fillStyle = "rgba(0, 0, 0, 1.0)";
        console.log(borderThickness)
        console.log(fontsize + borderThickness)
        context.fillText( message, 100, 100);
        // console.log(context)
        // 创建标签
        
        
				var moonLabel = new CSS2DObject( canvas );
				return moonLabel



    },

    roundRect(ctx, x, y, w, h, r) {

        ctx.beginPath();
        ctx.moveTo(x+r, y);
        ctx.lineTo(x+w-r, y);
        ctx.quadraticCurveTo(x+w, y, x+w, y+r);
        ctx.lineTo(x+w, y+h-r);
        ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h);
        ctx.lineTo(x+r, y+h);
        ctx.quadraticCurveTo(x, y+h, x, y+h-r);
        ctx.lineTo(x, y+r);
        ctx.quadraticCurveTo(x, y, x+r, y);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();

    },

 8.画线区分直线模式和非直线  直线第第二个三维向量点与第一个三维向量点相减就正 哪个最大就是朝哪个位置 

var xx = Math.abs(this.points[0].x - intersects[ 0 ].point.x)
                  var yy = Math.abs(this.points[0].y - intersects[ 0 ].point.y)
                  var zz = Math.abs(this.points[0].z - intersects[ 0 ].point.z)
                  
                  if (xx>yy&&xx>zz) {
                    var location = new Three.Vector3(intersects[ 0 ].point.x, this.points[0].y,this.points[0].z)
                    
                  }else if (yy>xx&&yy>zz) {
                    var location = new Three.Vector3(this.points[0].x,intersects[ 0 ].point.y, this.points[0].z)
                    
                  }
                  else if (zz>xx&&zz>yy) {
                    var location = new Three.Vector3(this.points[0].x,this.points[0].y,intersects[ 0 ].point.z)
                    
                  }

9.组件化 父子组件调用 不BB了

全部代码 懵B的话 就问我吧 



  
   

你可能感兴趣的:(前端,js,webgl,定位,3d,vue)