解决问题:有个小程序项目中需要用到3D烟雾效果,前端做3D效果常用的技术是threejs,但是常用的threejs有以下两个问题
1、threejs会操作DOM,但是小程序里面没有DOM
2、threejs会绑定window对象,但是小程序里面 没有window
网上对这一块有一些解决方案,有一个大佬自己开发了一个适配小程序的 threejs.miniprogram,基本上大部分的功能是都可以用的 还有的人针对 小游戏 里面的 weapp-adapter 做了二次开发,主要是将浏览器中的 DOM 和 window 对象进行模拟 这两个方案毕竟都是民间的,得不到稳定的维护,后来我发现微信官方出了一个 threejs-miniprogram,官方出品的,把 threejs 里面的大部分功能适配过来了,但是也有很多不足的地方,比如 Controls 这一块没有适配过来,可能小程序上需要实现的 3D 效果不需要很多的原因吧
引入方式:
第一步:安装threejs-miniprogram插件
npm install --save threejs-miniprogram
第二步:页面布局使用canvas
<canvas class="canvas-webgl" canvas-id="webgl" type="webgl" id="webgl" :style="{height:config.canvasH+'px',width:config.canvasW+'px'}"></canvas>
第三步:逻辑实现烟雾效果,建议实现方法放在onReady方法中,以防渲染失败
import {createScopedThreejs} from 'threejs-miniprogram';
let w = this.config.canvasW,
h = this.config.canvasH;
var clock, camera, scene, renderer, geometry, material, mesh;
var cubeSineDriver, light, smokeTexture, smokeMaterial, smokeGeo, smokeParticles;
wx.createSelectorQuery()
.select('#webgl')
.node()
.exec((res) => {
const canvas = res[0].node;
// 创建一个与 canvas 绑定的 three.js
const THREE = createScopedThreejs(canvas);
// 传递并使用 THREE 变量
//THREE.global.registerCanvas(canvas);
clock = new THREE.Clock();
renderer = new THREE.WebGLRenderer({ antialias: true,alpha:true });
renderer.setSize( w, h);
renderer.setClearColor(0xffffff, 0);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, w / h, 1, 10000 );
camera.position.z = 1000;
scene.add( camera );
geometry = new THREE.CubeGeometry( 200, 200, 200 );
material = new THREE.MeshLambertMaterial( { color: 0xffffff, opacity: 0.3, wireframe: false } );
mesh = new THREE.Mesh( geometry, material );
//scene.add( mesh );
cubeSineDriver = 0;
light = new THREE.DirectionalLight(0xffffff,0.5,0);
light.position.set(-1,-0.9,1);
scene.add(light);
smokeTexture = THREE.ImageUtils.loadTexture('../../static/imgs/fog-el.png');
smokeMaterial = new THREE.MeshBasicMaterial({color: 0xffffff, opacity: 0.5, map: smokeTexture, transparent: true});
smokeGeo = new THREE.PlaneGeometry(300,300);
smokeParticles = [];
for (let p = 0; p < 50; p++) {
var particle = new THREE.Mesh(smokeGeo,smokeMaterial);
particle.position.set(Math.random()*500-250,Math.random()*500-250,Math.random()*1000-100);
particle.rotation.z = Math.random() * 360;
scene.add(particle);
smokeParticles.push(particle);
}
function evolveSmoke(delta) {
var sp = smokeParticles.length;
while(sp--) {
smokeParticles[sp].rotation.z += (delta * 0.5);
}
}
function render() {
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
cubeSineDriver += .01;
mesh.position.z = 100 + (Math.sin(cubeSineDriver) * 500);
renderer.render( scene, camera );
}
function animate() {
let delta = clock.getDelta();
canvas.requestAnimationFrame(animate);
evolveSmoke(delta);
render();
}
animate();
})
|