教你实现超级炫酷的粒子光,超级简单

1,992 阅读3分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

背景

最近写了一些关于threejs 的文章,大家很感兴趣,浏览量很高,因为threejs 的可玩性很高,但是对于小白用户操作就没有那么容易上手,毕竟threejs 还是有一定的学习门槛的,为了降低大家对threejs的学习门槛,也方便大家炫技,我在这介绍一个超级炫酷的粒子光插件(three.proton.js)给大家看看,下面是效果:

动画1.gif

介绍

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…

实现

准备

  1. three.js: drawcall.github.io/three.proto…
  2. three.proton.js: drawcall.github.io/three.proto…
  3. stats.js: drawcall.github.io/three.proto…
  4. TrackballControls.js: drawcall.github.io/three.proto…
  5. 光的图片,如下:drawcall.github.io/three.proto…

image.png

开始

html 代码

创建一个容器

<div id="container"></div>

css 代码

 body {
    font-family: Monospace;
    background-color: #fff;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

js 代码

  1. 引入插件和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>
  1. 初始化
// 粒子光初始化
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();
  1. 新建一个场景
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);
    }
  1. 添加控制
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;
    }
  1. 添加灯光
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);
}
  1. 添加性能检测
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);
    }
  1. 添加背景小星星
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);
}
  1. 添加粒子光
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));

}
  1. 创建粒子光函数
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;
}
  1. 粒子光贴图
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);
}
  1. 动画
function animate() {
    stats.begin();
    requestAnimationFrame(animate);
    animateEmitter();
    render();
    stats.end();
}
  1. 渲染
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);
}
  1. 粒子光动画
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);
}
  1. 窗口自调节
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    render();
    renderer.setSize(window.innerWidth, window.innerHeight);
}
  1. 看效果

动画1.gif

相关文章

教你用3步代码实现360度全景图,超简单

vue3.0 + ts + threejs 实现3D 文字(hello juejin)和demo详解

用 threejs 实现旋转的掘金logo

vue3.0 + ts + threejs 实现简单的demo