1.场景演示
小程序集成Three.js,使用粒子系统模拟雨雪天气
2.源码
(1)导入库文件
import * as THREE from '../../libs/three.weapp.js'
import {
OrbitControls
} from '../../jsm/controls/OrbitControls'
const app = getApp()
(2)雨天场景源码
//初始化雨天场景
initScene() {
wx.createSelectorQuery()
.select('#webgl')
.node()
.exec((res) => {
let canvasId = String(res[0].node.id)
const canvas = THREE.global.registerCanvas(canvasId, res[0].node)
this.setData({
canvasId: canvasId
})
//相机
const camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 1, 1000);
//场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
const renderer = new THREE.WebGLRenderer({
antialias: true
});
camera.position.set(30, 40, 50);
//控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.update();
//声明创建雨点的函数
function createPointCloud(size, transparent, opacity, sizeAttenuation, color) {
//这里加载的纹理贴图是一张雨滴的贴图
var texture = new THREE.TextureLoader().load("/pages/image/raindrop-3.png");
var geom = new THREE.Geometry();
var material = new THREE.PointsMaterial({
size: size,
transparent: transparent,
opacity: opacity,
map: texture,
blending: THREE.AdditiveBlending,
sizeAttenuation: sizeAttenuation,
color: color
});
var range = 100;
for (var i = 0; i < 1500; i++) {
var particle = new THREE.Vector3(
Math.random() * range - range / 2,
Math.random() * range * 1.5,
1 + (i / 50)
)
particle.velocityY = 0.1 + Math.random() / 5;
particle.velocityX = (Math.random() - 0.5) / 3;
geom.vertices.push(particle);
}
cloud = new THREE.Points(geom, material);
cloud.sortParticles = true;
cloud.name = "particles1"
scene.add(cloud);
}
createPointCloud(3, true, 0.6, true, 0xffffff)
//创建平面
const planeGeometry = new THREE.PlaneGeometry(200, 150, 20, 20);
const planeMaterial = new THREE.MeshBasicMaterial({
color: 0xc7c7c7,
});
planeMaterial.side = THREE.DoubleSide;
const plane = new THREE.Mesh(planeGeometry, planeMaterial)
plane.rotation.x = Math.PI / 2
plane.position.y = -10
scene.add(plane)
//辅助线
const axesHelper = new THREE.AxesHelper(500);
scene.add(axesHelper)
renderer.setPixelRatio(wx.getSystemInfoSync().pixelRatio);
renderer.setSize(canvas.width, canvas.height);
function render() {
var vertices = cloud.geometry.vertices;
vertices.forEach(function (v) {
v.y = v.y - (v.velocityY);
v.x = v.x - (v.velocityX);
if (v.y <= 0) v.y = 60;
if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1;
});
cloud.geometry.verticesNeedUpdate = true;
canvas.requestAnimationFrame(render);
//更新控制器
controls.update();
renderer.render(scene, camera);
}
render()
})
},
(3)雪天场景源码
//雪天场景源码
initScene() {
wx.createSelectorQuery()
.select('#webgl')
.node()
.exec((res) => {
let canvasId = String(res[0].node.id)
const canvas = THREE.global.registerCanvas(canvasId, res[0].node)
this.setData({
canvasId: canvasId
})
//相机
const camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 1, 1000);
//场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
const renderer = new THREE.WebGLRenderer({
antialias: true
});
camera.position.set(30, 40, 50);
//控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.update();
function createPointCloud(name, texture, size, transparent, opacity, sizeAttenuation, color) {
var geom = new THREE.Geometry();
var color = new THREE.Color(color);
color.setHSL(color.getHSL().h,
color.getHSL().s,
(Math.random()) * color.getHSL().l);
var material = new THREE.PointsMaterial({
size: size,
transparent: transparent,
opacity: opacity,
map: texture,
blending: THREE.AdditiveBlending,
depthWrite: false,
sizeAttenuation: sizeAttenuation,
color: color
});
var range = 100;
for (var i = 0; i < 150; i++) {
var particle = new THREE.Vector3(
Math.random() * range - range / 2,
Math.random() * range * 1.5,
Math.random() * range - range / 2);
particle.velocityY = 0.1 + Math.random() / 5;
particle.velocityX = (Math.random() - 0.5) / 3;
particle.velocityZ = (Math.random() - 0.5) / 3;
geom.vertices.push(particle);
}
var system = new THREE.Points(geom, material);
system.name = name;
return system;
}
function createPointInstances(size, transparent, opacity, sizeAttenuation, color) {
var loader = new THREE.TextureLoader();
// 这里加载了4个不同雪片的贴图
var texture1 = loader.load("/pages/image/snowflake1_t.png");
var texture2 = loader.load("/pages/image/snowflake2_t.png");
var texture3 = loader.load("/pages/image/snowflake3_t.png");
var texture4 = loader.load("/pages/image/snowflake5_t.png");
scene.add(createPointCloud("system1", texture1, size, transparent, opacity, sizeAttenuation, color));
scene.add(createPointCloud("system2", texture2, size, transparent, opacity, sizeAttenuation, color));
scene.add(createPointCloud("system3", texture3, size, transparent, opacity, sizeAttenuation, color));
scene.add(createPointCloud("system4", texture4, size, transparent, opacity, sizeAttenuation, color));
}
createPointInstances(10, true, 0.6, true, 0xffffff)
//平面
const planeGeometry = new THREE.PlaneGeometry(200, 150, 20, 20);
const planeMaterial = new THREE.MeshBasicMaterial({
color: 0xc7c7c7
});
planeMaterial.side = THREE.DoubleSide;
const plane = new THREE.Mesh(planeGeometry, planeMaterial)
plane.rotation.x = Math.PI / 2
plane.position.y = -10
scene.add(plane)
//辅助线
const axesHelper = new THREE.AxesHelper(500);
scene.add(axesHelper)
renderer.setPixelRatio(wx.getSystemInfoSync().pixelRatio);
renderer.setSize(canvas.width, canvas.height);
function render() {
//这里通过变更雪片的位置,创造出下雪的效果
scene.children.forEach(function (child) {
if (child instanceof THREE.Points) {
var vertices = child.geometry.vertices;
vertices.forEach(function (v) {
v.y = v.y - (v.velocityY);
v.x = v.x - (v.velocityX);
v.z = v.z - (v.velocityZ);
if (v.y <= 0) v.y = 60;
if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1;
if (v.z <= -20 || v.z >= 20) v.velocityZ = v.velocityZ * -1;
});
child.geometry.verticesNeedUpdate = true;
}
});
canvas.requestAnimationFrame(render);
//更新控制器
controls.update();
renderer.render(scene, camera);
}
render()
})
},
(4)源码说明
雪天和雨天场景的创建几乎是一样的,区别在于雪天加载了4张不同的雪花纹理图片,创造出更逼真的效果。
动画的实现是在渲染函数中,当渲染下一帧时,遍历scene下的所有子对象,如果是THREE.Points的实例,则对其坐标通过算法进行修改,从而实现雪花飘落的效果。