·场景搭建
使用npm或者其他获取安装three,就像npm i three,之后在需要演示模型的vue组件内import * as THREE from 'three',此时我们就可以创建场景scene、灯光light、镜头、几何体等等开始渲染循环了
镜头控制是必要的,我们不会加载一个3D模型只为了看一面的剪影,从官网可以找到许多种控制器,本项目使用的是npm i three-orbitcontrols
import OrbitControls from 'three-orbitcontrols'
1 create(){ //创建场景 2 this.renderer = new THREE.WebGLRenderer(); 3 4 this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 5000 ) 5 this.camera.position.z = 160 6 this.camera.position.x = 0 7 this.camera.position.y = 0 8 9 this.scene = new THREE.Scene(); 10 this.scene.add(this.camera) 11 12 //鼠标控制镜头 13 this.controls = new OrbitControls(this.camera) 14 15 //创建一个环境灯光 16 var ambientLight = new THREE.AmbientLight( 0xffffff, 0.4 ); 17 this.scene.add( ambientLight ); 18 19 //创建一个点灯光 20 var pointLight = new THREE.PointLight( 0xffffff, 0.5 ); 21 22 //给相机添加光源 23 this.camera.add( pointLight ); 24 25 //渲染器样式 26 this.renderer.setClearColor(new THREE.Color('black')); 27 this.renderer.setSize(window.innerWidth, window.innerHeight); 28 this.renderer.domElement.setAttribute("style"," height:100%; 100%;") 29 30 },
现在有了一个有灯光和控制器但没有模型的场景,而且没有挂载到页面
·引入加载器
显然,我们无法使用代码建立所有的模型,尽管three提供了建立多种几何体的强大功能让我们可以以纯代码开发三维场景,但项目中仍需要three提供的多种3D模型文件的Loader.js来帮助我们将建模软件生产的模型加载成可以添加到scene的object
你可能需要展示stl|obj|3ds|3mf|....等等文件类型,我们可以在已安装的three路径 “ ode_modules hreeexamplesjsloaders” 下找到所有已支持的类型加载器,如果你找到了3MFLoader.js但没有看到3DSLoader.js,可以到threejs的官方示例下查找使用样例,页面右下角查看源代码就会发现3ds加载器叫TDSLoader.js ;P
官方样例统统使用head写法引入js,这不适合vue,除非你的网站就只有这一个组件演示这一类模型(要知道vue大都是单页面网站),按照不同文件类型按需加载对应的加载器js才是效率的使用方式,那么。。使用ES6提供的import()实现运行时加载
例如objloader.js,将文件从node_modules中移到用户可以获取到的路径下(比如static),就可以按如下方式使用了
1 somefunction:(path){//模型文件url 2 ...... 3 import('@/static/OBJLoader.js').then(module => { 4 5 let Loader = new THREE.OBJLoader(); 6 7 that.loadermashs(Loader,path) //入口 8 9 }).catch(err => { 10 11 this.message = "加载器获取失败:"+err; 12 }); 13 } 14 15 16 onProgress( xhr ) { 17 18 if ( xhr.lengthComputable ) { 19 20 var percentComplete = xhr.loaded / xhr.total * 100; 21 22 //message承接加载进度 23 this.message = Math.round(percentComplete, 2) + '% 已加载' ; 24 } 25 }, 26 27 28 onError( xhr ) { 29 30 this.message = xhr; 31 }, 32 33 34 loadermashs(Loader,path){ 35 36 let that = this; 37 38 Loader.setPath(path); 39 40 Loader.load('', function(object) { 41 42 that.scene.add(object); //前面的函数准备好后最终在这里用到 43 44 }, that.onProgress, that.onError); 45 }, 46
注意:需要手动在OBJLoader.js中首行加入:var THREE = require('three')
e.g 编译时warning:"export 'OBJLoader' (imported as 'THREE') was not found in 'three',是因为THREE.OBJLoader()关系是运行时建立的,怎么消除这个warning我也不知道。。·挂载与卸载
1 start(){//挂载到页面开始循环 2 document.getElementById("hello").appendChild(this.renderer.domElement) 3 this.running = true; 4 5 this.animate() 6 }, 7 8 animate() { 9 10 this.renderer.render(this.scene, this.camera) 11 12 if(this.running) 13 requestAnimationFrame(this.animate)//再次调用animate 14 }
running作为关闭标识
webGL中,手动卸载是有必要的,按照开发者原意,系统判断哪些资源可以废弃是不可能的:用户可能在某一帧放弃使用某个模型,也可能在下一帧重新启用,因此自动丢弃不被使用的资源是不合理的,而不做手动处理的后果是当你多次打开演示后:
Error: WebGL: Exceeded 16 live WebGL contexts for this principal, losing the least recently used one on...
所以请在关闭演示之前卸载他们:相关api
1 if(this.running){ 2 3 let canvas = document.getElementsByTagName('canvas')[0]; 4 5 if(canvas){ 6 let gl = canvas.getContext('webgl'); 7 8 canvas.addEventListener('webglcontextlost', function(e) { 9 //console.log(e); 10 }, false); 11 12 gl.getExtension('WEBGL_lose_context').loseContext(); 13 } 14 this.running = false 15 16 this.renderer.dispose(); 17 18 this.scene.dispose(); 19 20 this.controls.dispose(); 21 }
·其他
网页应用的dialog中展示某obj模型,最终演示效果:
此外还有材质加载、贴图、stl格式jzip问题等等。。有的坑我还没踩只是远远的望了一下,如果同为初学者,那么希望能帮到你
如有见解还请大佬指教:D