「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」
背景
最近写了一些关于threejs
的文章,大家很感兴趣,浏览量很高,因为threejs
的可玩性很高,但是对于小白用户操作就没有那么容易上手,毕竟threejs 还是有一定的学习门槛的,为了降低大家对threejs
的学习门槛,也方便大家炫技,我在这介绍一个超级炫酷的粒子光插件(three.proton.js
)给大家看看,下面是效果:
介绍
three.proton
是一个使用three.js
的神奇 3D 粒子引擎。它基于质子引擎库Proton。它继承了 Proton
最多的 Api
,而且非常简单非常好用。
我认为是最简单的three.js
粒子引擎。
文档
官网:drawcall.github.io/three.proto…
github:github.com/drawcall/th…
npmjs: www.npmjs.com/package/thr…
实现
准备
- three.js: drawcall.github.io/three.proto…
- three.proton.js: drawcall.github.io/three.proto…
- stats.js: drawcall.github.io/three.proto…
- TrackballControls.js: drawcall.github.io/three.proto…
- 光的图片,如下:drawcall.github.io/three.proto…
开始
html 代码
创建一个容器
<div id="container"></div>
css 代码
body {
font-family: Monospace;
background-color: #fff;
margin: 0;
padding: 0;
overflow: hidden;
}
js 代码
- 引入插件和js库 因为我是本地,你也可以直接引用我给的链接
<script src="../lib/stats.min.js"></script>
<script src="../lib/three.min.js"></script>
<script src="../lib/three.proton.min.js"></script>
<script src="./js/lib/TrackballControls.js"></script>
- 初始化
// 粒子光初始化
var proton, emitter1, emitter2, R;
// threejs初始化
var camera, scene, renderer, stats, clock, spring, controls;
// threejs初始化函数
function init() {
addScene();
addControls();
addLights();
addStars();
addProton();
addStats();
animate();
}
// 执行函数
init();
- 新建一个场景
function addScene() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 500;
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xffffff, 1, 10000);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false);
}
- 添加控制
function addControls() {
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
}
- 添加灯光
function addLights() {
var ambientLight = new THREE.AmbientLight(0x101010);
scene.add(ambientLight);
var pointLight = new THREE.PointLight(0xffffff, 2, 1000, 1);
pointLight.position.set(0, 200, 200);
scene.add(pointLight);
}
- 添加性能检测
function addStats() {
stats = new Stats();
stats.showPanel(0);
stats.dom.style.position = 'absolute';
stats.dom.style.left = '0px';
stats.dom.style.top = '0px';
container.appendChild(stats.dom);
}
- 添加背景小星星
function addStars() {
var geometry = new THREE.Geometry();
for (var i = 0; i < 10000; i++) {
var vertex = new THREE.Vector3();
vertex.x = THREE.Math.randFloatSpread(2000);
vertex.y = THREE.Math.randFloatSpread(2000);
vertex.z = THREE.Math.randFloatSpread(2000);
geometry.vertices.push(vertex);
}
var particles = new THREE.Points(geometry, new THREE.PointsMaterial({
color: 0x888888
}));
scene.add(particles);
}
- 添加粒子光
function addProton() {
proton = new Proton();
R = 70;
emitter1 = createEmitter(R, 0, '#4F1500', '#0029FF');
emitter2 = createEmitter(-R, 0, '#004CFE', '#6600FF');
proton.addEmitter(emitter1);
proton.addEmitter(emitter2);
proton.addRender(new Proton.SpriteRender(scene));
}
- 创建粒子光函数
function createEmitter(x, y, color1, color2) {
var emitter = new Proton.Emitter();
emitter.rate = new Proton.Rate(new Proton.Span(5, 7), new Proton.Span(.01, .02));
emitter.addInitialize(new Proton.Mass(1));
emitter.addInitialize(new Proton.Life(2));
emitter.addInitialize(new Proton.Body(createSprite()));
emitter.addInitialize(new Proton.Radius(80));
emitter.addInitialize(new Proton.V(200, new Proton.Vector3D(0, 0, -1), 0));
emitter.addBehaviour(new Proton.Alpha(1, 0));
emitter.addBehaviour(new Proton.Color(color1, color2));
emitter.addBehaviour(new Proton.Scale(1, 0.5));
emitter.addBehaviour(new Proton.CrossZone(new Proton.ScreenZone(camera, renderer), 'dead'));
emitter.addBehaviour(new Proton.Force(0, 0, -20));
emitter.p.y = y;
emitter.emit();
return emitter;
}
- 粒子光贴图
function createSprite() {
// var map = new THREE.TextureLoader().load("./img/dot.png");
var map = new THREE.TextureLoader().load("https://drawcall.github.io/three.proton/engine/example/img/dot.png");
var material = new THREE.SpriteMaterial({
map: map,
color: 0xff0000,
blending: THREE.AdditiveBlending,
fog: true
});
return new THREE.Sprite(material);
}
- 动画
function animate() {
stats.begin();
requestAnimationFrame(animate);
animateEmitter();
render();
stats.end();
}
- 渲染
var ctha = 0;
function render() {
proton.update();
renderer.render(scene, camera);
//controls.update();
camera.lookAt(scene.position);
ctha += .02;
camera.position.x = Math.sin(ctha) * 500;
camera.position.z = Math.cos(ctha) * 500;
camera.position.y = Math.sin(ctha) * 500;
Proton.Debug.renderInfo(proton, 3);
}
- 粒子光动画
var tha = 0;
function animateEmitter() {
tha += .13;
emitter1.p.x = R * Math.cos(tha);
emitter1.p.y = R * Math.sin(tha);
emitter2.p.x = R * Math.cos(tha + Math.PI / 2);
emitter2.p.y = R * Math.sin(tha + Math.PI / 2);
}
- 窗口自调节
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render();
renderer.setSize(window.innerWidth, window.innerHeight);
}
- 看效果