用threejs实现火焰,超级简单

6,607 阅读2分钟

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

背景

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

动画.gif

介绍

three.proton 是一个使用three.js的神奇 3D 粒子引擎。它基于质子引擎库Proton。它继承了 Proton 最多的 Api,而且非常简单非常好用。

文档

官网:drawcall.github.io/three.proto…

github:github.com/drawcall/th…

npmjs: www.npmjs.com/package/thr…

实现

因为threejs更新很快,有些属性有所不一样,所以最好用官网给的版本,这样就不会出现错误了!(或者直接用我给的链接也可以)。

准备

  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 库

<script src="../lib/stats.min.js"></script>
<script src="../lib/three.min.js"></script>
<script src="../build/three.proton.min.js"></script>
<script src="./js/lib/TrackballControls.js"></script>

js 代码

  1. 变量初始化
var proton, emitter;
  1. 创建粒子对象
proton = new Proton();
  1. 创建火焰
function createEmitter() {
        emitter = new Proton.Emitter();
        emitter.rate = new Proton.Rate(new Proton.Span(10, 15), new Proton.Span(.05, .1));
        emitter.addInitialize(new Proton.Body(createSprite()));
        emitter.addInitialize(new Proton.Mass(1));
        emitter.addInitialize(new Proton.Life(1, 3));
        emitter.addInitialize(new Proton.Position(new Proton.SphereZone(20)));
        emitter.addInitialize(new Proton.V(new Proton.Span(500, 800), new Proton.Vector3D(0, 1, 0), 30));
        emitter.addBehaviour(new Proton.RandomDrift(10, 10, 10, .05));
        //emitter.addBehaviour(new Proton.Alpha(1, 0.1));
        emitter.addBehaviour(new Proton.Scale(new Proton.Span(2, 3.5), 0));
        emitter.addBehaviour(new Proton.G(6));
        emitter.addBehaviour(new Proton.Color('#FF0026', ['#ffff00', '#ffff11'], Infinity, Proton.easeOutSine));
        emitter.p.x = 0;
        emitter.p.y = -150;
        emitter.emit();
        return emitter;
    }
  1. 创建火苗轨迹
function addInteraction() {
        window.addEventListener('mousemove', onMouseMove, false);
        var pos = {
            x: 0,
            y: 0
        };

        function onMouseMove(event) {
            pos.x = event.clientX;
            pos.y = event.clientY;
            var target = Proton.THREEUtil.toSpacePos(pos, camera, renderer.domElement);
            emitter.p.x += (target.x - emitter.p.x) / 10;
            emitter.p.y += (target.y - emitter.p.y) / 10;
            emitter.p.z += (target.z - emitter.p.z) / 10;
        }
    }
  1. 给火苗贴图
function createSprite() {
        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. 渲染火焰
proton.addEmitter(createEmitter());
proton.addRender(new Proton.SpriteRender(scene));
  1. 页面渲染
function render() {
    proton.update(clock.getDelta());
    renderer.render(scene, camera);
    controls.update();

    Proton.Debug.renderInfo(proton, 3);
}
  1. 添加动画
function animate() {
    stats.begin();
    requestAnimationFrame(animate);
    render();
    stats.end();
 }

threejs 初始化

  1. 变量初始化
var camera, scene, renderer, clock, spring, controls;
  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);

    clock = new THREE.Clock();

    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
}
  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.gif

总结

本文写的很简单,有些坑,大家可以去官网上查看,上面有粒子和完整的代码,大家可以直接下载查看,效果很好看,实现也很容易,大家可以自己动手操作一遍。最后谢谢大家的观看!