這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 我的需求是使用uniapp寫微信小程式,在小程式中使用threeJs就行了,目前暫不考慮相容app什麼的。 1.引入小程式版的threejs庫實現 2.使用webview實現(推薦) 重點 我的建議是使用這個庫https://git ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
前言
我的需求是使用uniapp寫微信小程式,在小程式中使用threeJs就行了,目前暫不考慮相容app什麼的。 1.引入小程式版的threejs庫實現 2.使用webview實現(推薦)
重點
我的建議是使用這個庫
https://github.com/deepkolos/three-platformize
為什麼?我試了uniapp推薦的和threejs-miniprogram這個小程式官方庫,都載入不出來我的obj模型。所有我推薦不要用obj模型最好,挺多都支持GLTF模型的,但是我不能改。
使用three-platformize載入obj模型的案例:
核心代碼:
html: <canvas type="webgl" id="webgl" style="width: 100vw; height: 100vh;" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" /> script: <script> import * as THREE from 'three-platformize'; import { WechatPlatform } from 'three-platformize/src/WechatPlatform'; import { OBJLoader } from 'three-platformize/examples/jsm/loaders/OBJLoader'; import { GLTFLoader } from 'three-platformize/examples/jsm/loaders/GLTFLoader'; import {OrbitControls} from 'three-platformize/examples/jsm/controls/OrbitControls'; export default { data() { return { canvas:null, camera:null, scene:null, renderer:null, model:null, controls:null, loopIndex:null } }, onLoad() { }, methods: { async init() { const { canvas }= await this.getCanvas(); this.canvas = canvas; const platform = new WechatPlatform(canvas); // webgl canvas platform.enableDeviceOrientation('game'); // 開啟DeviceOrientation THREE.PLATFORM.set(platform); this.platform = platform; this.renderModel(); }, //獲取畫布 async getCanvas(delay = 200) { return new Promise((resolve, reject) => { const t = setTimeout(() => { clearTimeout(t); uni.createSelectorQuery().in(this) .select('#webgl') .fields({ node: true }) .exec((res) => { console.log('res',res) if (res && res[0] && res[0].node) { const canvas = res[0].node; resolve({ canvas }); } else { reject("獲取canvas失敗"); } }); }, delay); }); }, renderModel () { this.camera = new THREE.PerspectiveCamera(45, this.canvas.width / this.canvas.height, 0.25, 100); this.camera.position.set(- 5, 3, 10); this.camera.lookAt(new THREE.Vector3(0, 2, 0)); this.scene = new THREE.Scene(); this.scene.background = new THREE.Color(0xe0e0e0); this.scene.fog = new THREE.Fog(0xe0e0e0, 20, 100); this.clock = new THREE.Clock(); // lights var light = new THREE.HemisphereLight(0xffffff, 0x444444); light.position.set(0, 20, 0); this.scene.add(light); // 改變外殼顏色 var AmbientLight = new THREE.AmbientLight(0x815800); // 環境光 this.scene.add(AmbientLight); // 平行光 light = new THREE.DirectionalLight(0xffffff); light.position.set(0, 20, 10); this.scene.add(light); // // ground // var mesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(2000, 2000), new THREE.MeshPhongMaterial({ color: 0x999999, depthWrite: false })); // mesh.rotation.x = - Math.PI / 2; // this.scene.add(mesh); // var grid = new THREE.GridHelper(200, 40, 0x000000, 0x000000); // grid.material.opacity = 0.6; // grid.material.transparent = true; // this.scene.add(grid); // model var loader = new OBJLoader(); loader.load('http://localhost:8888/obj3/file.obj', (obj) => { console.log("obj+=") console.log(obj) // console.log(this.model) obj.position.set(0, -2, 0);//模型擺放的位置 obj.scale.set(0.2, 0.2, 0.2); // this.model = obj; this.scene.add(obj); }, undefined, function (e) { console.log("模型載入錯誤") console.error(e); }); // var loader = new GLTFLoader(); // loader.load('https://dtmall-tel.alicdn.com/edgeComputingConfig/upload_models/1591673169101/RobotExpressive.glb', (gltf) => { // this.model = gltf.scene; // this.scene.add(this.model); // }, undefined, function (e) { // console.error(e); // }); // var geometry = new THREE.BoxGeometry( 5, 5, 5 ); // var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} ); // var mesh = new THREE.Mesh( geometry, material ); // this.scene.add(mesh); this.renderer = new THREE.WebGLRenderer({antialias: true }); this.renderer.setPixelRatio(wx.getSystemInfoSync().pixelRatio); this.renderer.setSize(this.canvas.width, this.canvas.height); //this.renderer.outputEncoding = true; this.renderer.gammaFactor = 2.2; this.controls = new OrbitControls(this.camera, this.renderer.domElement ); this.camera.position.set( 5, 5, 10 ); this.animate(); }, animate() { this.loopIndex = this.canvas.requestAnimationFrame(this.animate); this.renderer.render(this.scene, this.camera); this.controls.update(); }, touchStart(e) { this.platform.dispatchTouchEvent(e); }, touchMove(e) { this.platform.dispatchTouchEvent(e); }, touchEnd(e) { this.platform.dispatchTouchEvent(e); } }, mounted() { this.$nextTick(()=> { this.init(); }); } } </script>
上面的案例中使用了兩個模型,一個obj模型,obj模型的地址是自己寫的本地伺服器地址,需要自己配置,GLTF模型地址是網路地址,可以把註釋解開查看。
註意點
1.載入外部模型與threeJs官網api是一致的
2.使用此方法載入外部模型,可能在真機調試時遇到模型不展示,或者微信閃退的情況(原因未知)
webview實現引入threejs庫
效果圖
實現:
1.使用vue實現threejs導入obj模型(pc端可完美實現),
2.在webview中引入相應的模型展示地址,
完結,就這兩步即可,但是我是動態載入,所以在載入模型的時候,你需要在小程式端傳值給pc端,讓pc端載入相應的模型,這裡就只需要用get在地址欄中傳參就行了。
以下兩個方法可能會用到:
1.模型大小自適應
setScaleToFitSize (obj) { const boxHelper = new THREE.BoxHelper(obj); boxHelper.geometry.computeBoundingBox(); const box = boxHelper.geometry.boundingBox; const maxDiameter = Math.max((box.max.x - box.min.x), (box.max.y - box.min.y), (box.max.z - box.min.z)); const scaleValue = camera.position.z / maxDiameter; obj.position.set(0, -10, 0);//模型擺放的位置 obj.scale.set(scaleValue, scaleValue, scaleValue); scene.add(obj); },
2.禁止小程式展示webview時候向下拉動:
在mounted
中添加:
document.body.addEventListener('touchmove', function (e) { e.preventDefault(); }, { passive: false });