代码是网上找的代码,通过调参、修改、封装实现的。

代码:

/**
* 火焰
*/ import * as THREE from '../build/three.module.js'; let MyFire3 = function () { let fireVertexShader = `
attribute vec4 orientation;
attribute vec3 offset;
attribute vec2 scale;
attribute float life;
attribute float random; varying vec2 vUv;
varying float vRandom;
varying float vAlpha; float range(float oldValue, float oldMin, float oldMax, float newMin, float newMax) {
float oldRange = oldMax - oldMin;
float newRange = newMax - newMin;
return (((oldValue - oldMin) * newRange) / oldRange) + newMin;
} // From Inigo Quilez http://www.iquilezles.org/www/articles/functions/functions.htm
float pcurve(float x, float a, float b) {
float k = pow(a + b, a + b) / (pow(a, a) * pow(b, b));
return k * pow(x, a) * pow(1.0 - x, b);
} void main() {
vUv = uv;
vRandom = random; vAlpha = pcurve(life, 1.0, 2.0); vec3 pos = position; pos.xy *= scale * vec2(range(pow(life, 1.5), 0.0, 1.0, 1.0, 0.6), range(pow(life, 1.5), 0.0, 1.0, 0.6, 1.2)); vec4 or = orientation;
vec3 vcV = cross(or.xyz, pos);
pos = vcV * (2.0 * or.w) + (cross(or.xyz, vcV) * 2.0 + pos); gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`; let fireFragmentShader = `
uniform sampler2D uMap;
uniform vec3 uColor1;
uniform vec3 uColor2;
uniform float uTime; varying vec2 vUv;
varying float vAlpha;
varying float vRandom; void main() {
vec2 uv = vUv; float spriteLength = 10.0;
uv.x /= spriteLength;
float spriteIndex = mod(uTime * 0.1 + vRandom * 2.0, 1.0);
uv.x += floor(spriteIndex * spriteLength) / spriteLength; vec4 map = texture2D(uMap, uv); gl_FragColor.rgb = mix(uColor2, uColor1, map.r);
gl_FragColor.a = vAlpha * map.a;
}
`; let embersVertexShader = `
attribute float size;
attribute float life;
attribute vec3 offset; varying float vAlpha; // From Inigo Quilez http://www.iquilezles.org/www/articles/functions/functions.htm
float impulse(float k, float x) {
float h = k * x;
return h * exp(1.0 - h);
} void main() {
vAlpha = impulse(6.28, life); vec3 pos = position;
pos += offset * vec3(life * 0.7 + 0.3, life * 0.9 + 0.1, life * 0.7 + 0.3); vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
gl_PointSize = size * (80.0 / length(mvPosition.xyz));
gl_Position = projectionMatrix * mvPosition;
}
`; let embersFragmentShader = `
uniform sampler2D uMap;
uniform vec3 uColor; varying float vAlpha; void main() {
vec2 uv = vec2(gl_PointCoord.x, 1.0 - gl_PointCoord.y);
vec4 mask = texture2D(uMap, uv); gl_FragColor.rgb = uColor;
gl_FragColor.a = mask.a * vAlpha * 0.8;
}
`; let hazeVertexShader = `
attribute vec3 base;
attribute vec3 offset;
attribute vec4 orientation;
attribute vec2 scale;
attribute float life; varying float vAlpha;
varying vec2 vUv; // From Inigo Quilez http://www.iquilezles.org/www/articles/functions/functions.htm
float impulse(float k, float x) {
float h = k * x;
return h * exp(1.0 - h);
} float pcurve(float x, float a, float b) {
float k = pow(a + b, a + b) / (pow(a, a) * pow(b, b));
return k * pow(x, a) * pow(1.0 - x, b);
} void main() {
vUv = uv;
vAlpha = pcurve(life, 1.0, 2.0); vec3 pos = position; pos.xy *= scale * (life * 0.7 + 0.3); vec4 or = orientation;
vec3 vcV = cross(or.xyz, pos);
pos = vcV * (2.0 * or.w) + (cross(or.xyz, vcV) * 2.0 + pos); pos += base;
pos += offset * vec3(life * 0.7 + 0.3, life * 0.9 + 0.1, life * 0.7 + 0.3); gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);;
}
`; let hazeFragmentShader = `
uniform sampler2D uMap;
uniform sampler2D uMask;
uniform vec2 uResolution; varying float vAlpha;
varying vec2 vUv; void main() {
vec2 uv = gl_FragCoord.xy / uResolution;
vec2 mask = texture2D(uMask, vUv).ra - vec2(0.5);
uv -= mask * 0.1;
vec4 tex = texture2D(uMap, uv); gl_FragColor.rgb = tex.rgb;
gl_FragColor.a = vAlpha * 0.5;
}
`; function random(min, max, precision) {
var p = Math.pow(10, precision);
return Math.round((min + Math.random() * (max - min)) * p) / p;
} let _scene;
let _renderer;
let _camera;
let _controls;
let _rtt;
let _fire;
let _width;
let _height; this.objs = []; let _self = this; this._isShow = false; let _pos_x;
let _pos_y;
let _pos_z; this.config = function (scene_, renderer_, camera_, controls_) {
_width = 1920;
_height = 1040; _renderer = renderer_;
_scene = scene_;
_camera = camera_;
_controls = controls_; var _parameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false
};
_rtt = new THREE.WebGLRenderTarget(_width * 0.5, _height * 0.5, _parameters);
} this.setPosition = function name(x, y, z) {
_pos_x = x;
_pos_y = y;
_pos_z = z;
} this.showFire = function () {
initFire();
initEmbers();
initHaze();
this._isShow = true;
} this.refresh = function () {
_self.loop();
_self.loop2();
_self.loop3();
} this.isShow = function () {
return this._isShow;
} this.hide = function () {
_self.objs.map(obj => {
_scene.remove(obj);
});
this._isShow = false;
} this.show = function () {
_self.objs.map(obj => {
_scene.add(obj);
});
this._isShow = true;
} //=====// Fire //========================================// function initFire() {
var _geometry, _shader, _mesh, _group;
var _num = 50; var _x = new THREE.Vector3(1, 0, 0);
var _y = new THREE.Vector3(0, 1, 0);
var _z = new THREE.Vector3(0, 0, 1); var _tipTarget = new THREE.Vector3();
var _tip = new THREE.Vector3();
var _diff = new THREE.Vector3(); var _quat = new THREE.Quaternion();
var _quat2 = new THREE.Quaternion(); (function () {
initGeometry();
initInstances();
initShader();
initMesh();
})(); function initGeometry() {
_geometry = new THREE.InstancedBufferGeometry();
_geometry.maxInstancedCount = _num; var shape = new THREE.PlaneBufferGeometry(500, 500);
shape.translate(0, 0.4, 0);
var data = shape.attributes; _geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(data.position.array), 3));
_geometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(data.uv.array), 2));
_geometry.addAttribute('normal', new THREE.BufferAttribute(new Float32Array(data.normal.array), 3));
_geometry.setIndex(new THREE.BufferAttribute(new Uint16Array(shape.index.array), 1));
shape.dispose();
} function initInstances() {
var orientation = new THREE.InstancedBufferAttribute(new Float32Array(_num * 4), 4);
var randoms = new THREE.InstancedBufferAttribute(new Float32Array(_num), 1);
var scale = new THREE.InstancedBufferAttribute(new Float32Array(_num * 2), 2);
var life = new THREE.InstancedBufferAttribute(new Float32Array(_num), 1); for (let i = 0; i < _num; i++) {
orientation.setXYZW(i, 0, 0, 0, 1);
life.setX(i, i / _num + 1);
} _geometry.addAttribute('orientation', orientation);
_geometry.addAttribute('scale', scale);
_geometry.addAttribute('life', life);
_geometry.addAttribute('random', randoms);
} function initShader() {
var uniforms = {
uMap: {
type: 't',
value: null
},
uColor1: {
type: 'c',
value: new THREE.Color(0x961800)
}, // red
uColor2: {
type: 'c',
value: new THREE.Color(0x4b5828)
}, // yellow
uTime: {
type: 'f',
value: 0
},
}; _shader = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: fireVertexShader,
fragmentShader: fireFragmentShader,
blending: THREE.AdditiveBlending,
transparent: true,
depthTest: false,
side: THREE.DoubleSide,
}); var textureLoader = new THREE.TextureLoader();
textureLoader.load('images/myFire3/flame.png', t => _shader.uniforms.uMap.value = t);
} function initMesh() {
_group = new THREE.Group();
_mesh = new THREE.Mesh(_geometry, _shader);
_mesh.frustumCulled = false;
_group.add(_mesh);
_scene.add(_group);
_self.objs.push(_group);
_fire = _group;
} _self.loop = function () {
let e = 100;
_shader.uniforms.uTime.value = e * 0.001; var life = _geometry.attributes.life;
var orientation = _geometry.attributes.orientation;
var scale = _geometry.attributes.scale;
var randoms = _geometry.attributes.random; for (let i = 0; i < _num; i++) {
var value = life.array[i];
value += 0.04; if (value > 1) {
value -= 1; _quat.setFromAxisAngle(_y, random(0, 3.14, 3));
_quat2.setFromAxisAngle(_x, random(-1, 1, 2) * 0.1);
_quat.multiply(_quat2);
_quat2.setFromAxisAngle(_z, random(-1, 1, 2) * 0.3);
_quat.multiply(_quat2);
orientation.setXYZW(i, _quat.x, _quat.y, _quat.z, _quat.w); scale.setXY(i, random(0.8, 1.2, 3), random(0.8, 1.2, 3));
randoms.setX(i, random(0, 1, 3));
} life.setX(i, value);
}
life.needsUpdate = true;
orientation.needsUpdate = true;
scale.needsUpdate = true;
randoms.needsUpdate = true; _group.position.x = _pos_x; //Math.sin(e * 0.002) * 1.4;
_group.position.y = _pos_y + 150; //Math.cos(e * 0.0014) * 0.2;
_group.position.z = _pos_z; //Math.cos(e * 0.0014) * 0.5; let tipOffset = 0.4;
_tipTarget.copy(_group.position);
_tipTarget.y += tipOffset;
_tip.lerp(_tipTarget, 0.1); _diff.copy(_tip);
_diff.sub(_group.position);
let length = _diff.length();
//_group.scale.y = (length / tipOffset - 1) * 0.4 + 1; _group.quaternion.setFromUnitVectors(_y, _diff.normalize());
}
} //=====// Embers //========================================// function initEmbers() {
var _geometry, _shader, _points;
var _num = 8; (function () {
initGeometry();
initShader();
initMesh();
})(); function initGeometry() {
_geometry = new THREE.BufferGeometry();
_geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(_num * 3), 3));
_geometry.addAttribute('offset', new THREE.BufferAttribute(new Float32Array(_num * 3), 3));
_geometry.addAttribute('size', new THREE.BufferAttribute(new Float32Array(_num), 1));
_geometry.addAttribute('life', new THREE.BufferAttribute(new Float32Array(_num), 1));
var scale = new THREE.InstancedBufferAttribute(new Float32Array(_num * 2), 2);
_geometry.addAttribute('scale', scale); for (var i = 0; i < _num; i++) {
_geometry.attributes.life.setX(i, random(0, 1, 3) + 1);
}
} function initShader() {
var uniforms = {
uMap: {
type: 't',
value: null
},
uColor: {
type: 'c',
value: new THREE.Color(0xffe61e)
},
}; _shader = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: embersVertexShader,
fragmentShader: embersFragmentShader,
blending: THREE.AdditiveBlending,
transparent: true,
depthTest: false,
}); var textureLoader = new THREE.TextureLoader();
textureLoader.load('images/myFire3/ember.png', t => _shader.uniforms.uMap.value = t);
} function initMesh() {
_points = new THREE.Points(_geometry, _shader);
_points.frustumCulled = false;
_scene.add(_points);
_self.objs.push(_points);
} _self.loop2 = function () {
var life = _geometry.attributes.life;
var position = _geometry.attributes.position;
var size = _geometry.attributes.size;
var offset = _geometry.attributes.offset;
var scale = _geometry.attributes.scale;
for (let i = 0; i < _num; i++) {
var value = life.array[i];
value += 0.02; if (value > 1) {
value -= 1; position.setXYZ(i, _pos_x, _pos_y + 0.1, _pos_z);
offset.setXYZ(i,
random(-200, 200, 3),
random(200, 600, 3),
random(-100, 100, 3)
);
size.setX(i, random(20, 200, 3)); scale.setXY(i, 50, 50);
} life.setX(i, value);
} life.needsUpdate = true;
position.needsUpdate = true;
size.needsUpdate = true;
offset.needsUpdate = true;
}
} //=====// Haze //========================================// function initHaze() {
var _geometry, _shader, _mesh; var _num = 4; var _z = new THREE.Vector3(0, 0, 1);
var _quat = new THREE.Quaternion();
var _quat2 = new THREE.Quaternion(); (function () {
initGeometry();
initInstances();
initShader();
initMesh();
window.addEventListener('resize', resizeHaze, false);
resizeHaze();
})(); function initGeometry() {
_geometry = new THREE.InstancedBufferGeometry();
_geometry.maxInstancedCount = _num; var shape = new THREE.PlaneBufferGeometry(0.1, 0.1);
var data = shape.attributes; _geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(data.position.array), 3));
_geometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(data.uv.array), 2));
_geometry.addAttribute('normal', new THREE.BufferAttribute(new Float32Array(data.normal.array), 3));
_geometry.setIndex(new THREE.BufferAttribute(new Uint16Array(shape.index.array), 1));
shape.dispose();
} function initInstances() {
var base = new THREE.InstancedBufferAttribute(new Float32Array(_num * 3), 3);
var offset = new THREE.InstancedBufferAttribute(new Float32Array(_num * 3), 3);
var orientation = new THREE.InstancedBufferAttribute(new Float32Array(_num * 4), 4);
var scale = new THREE.InstancedBufferAttribute(new Float32Array(_num * 2), 2);
var rotation = new THREE.InstancedBufferAttribute(new Float32Array(_num), 1);
var life = new THREE.InstancedBufferAttribute(new Float32Array(_num), 1); for (let i = 0; i < _num; i++) {
orientation.setXYZW(i, 0, 0, 0, 1);
life.setX(i, i / _num + 1);
} _geometry.addAttribute('base', base);
_geometry.addAttribute('offset', offset);
_geometry.addAttribute('orientation', orientation);
_geometry.addAttribute('scale', scale);
_geometry.addAttribute('rotation', rotation);
_geometry.addAttribute('life', life);
} function initShader() {
let dpr = _renderer.getPixelRatio();
var uniforms = {
uMap: {
type: 't',
value: null
},
uMask: {
type: 't',
value: null
},
uResolution: {
type: 'v2',
value: new THREE.Vector2(_width * dpr, _height * dpr)
},
}; _shader = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: hazeVertexShader,
fragmentShader: hazeFragmentShader,
transparent: true,
depthTest: false,
}); var textureLoader = new THREE.TextureLoader();
textureLoader.load('images/myFire3/haze.png', t => _shader.uniforms.uMask.value = t);
} function initMesh() {
_mesh = new THREE.Mesh(_geometry, _shader);
_mesh.frustumCulled = false;
_scene.add(_mesh);
_self.objs.push(_mesh);
} function resizeHaze() {
let dpr = _renderer.getPixelRatio();
_shader.uniforms.uMap.value = _rtt.texture;
_shader.uniforms.uResolution.value.set(_width * dpr, _height * dpr);
} _self.loop3 = function () { let e = 100;
_mesh.visible = false;
//_renderer.render(_scene, _camera, _rtt);
_mesh.visible = true; var life = _geometry.attributes.life;
var base = _geometry.attributes.base;
var offset = _geometry.attributes.offset;
var scale = _geometry.attributes.scale;
var orientation = _geometry.attributes.orientation;
var rotation = _geometry.attributes.rotation;
for (let i = 0; i < _num; i++) {
var value = life.array[i];
value += 0.008; if (value > 1) {
value -= 1; rotation.setX(i, random(0, 3.14, 3)); base.setXYZ(i, _pos_x, _pos_y + 0.1, _pos_z);
offset.setXYZ(i,
random(-220, 220, 3),
random(300, 600, 3),
0
);
//scale.setXY(i, random(0.6, 1.2, 3), random(0.6, 1.2, 3));
scale.setXY(i, 50, 50);
} _quat.copy(_camera.quaternion);
_quat2.setFromAxisAngle(_z, rotation.array[i]);
_quat.multiply(_quat2);
orientation.setXYZW(i, _quat.x, _quat.y, _quat.z, _quat.w); life.setX(i, value);
} life.needsUpdate = true;
base.needsUpdate = true;
scale.needsUpdate = true;
offset.needsUpdate = true;
orientation.needsUpdate = true;
}
} } MyFire3.prototype.constructor = MyFire3; export { MyFire3 }

如何使用(部分代码):

import { MyFire3 } from '../js.my/MyFire3.js';

let myFire3;

if (!myFire3) {
myFire3 = new MyFire3();
myFire3.config(scene, renderer, camera, controls);
myFire3.setPosition(417, 0, 1134);
myFire3.showFire();
} else {
if (myFire3.isShow()) {
myFire3.hide();
} else {
myFire3.show();
}
} function renderLoop() {
requestAnimationFrame(renderLoop); myFire3 && myFire3.refresh && myFire3.refresh();
} renderLoop();

说明:myFire3.config的参数中的controls未用到,scene、renderer、camera分别是three.js的Scene、WebGLRenderer和PerspectiveCamera对象

three.js 火焰效果的更多相关文章

  1. Three.js 火焰效果实现艾尔登法环动态logo 🔥

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 <艾尔登法环>是最近比较火的一款游戏,观察可以发现它的 Log ...

  2. Three.js 实现3D开放世界小游戏:阿狸的多元宇宙 🦊

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 2545光年之外的开普勒1028星系,有一颗色彩斑斓的宜居星球 ,星际移民 ...

  3. Three.js 打造缤纷夏日3D梦中情岛 🌊

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 深居内陆的人们,大概每个人都有过大海之梦吧.夏日傍晚在沙滩漫步奔跑:或是在 ...

  4. 使用Three.js实现炫酷的赛博朋克风格3D数字地球大屏 🌐

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 近期工作有涉及到数字大屏的需求,于是利用业余时间,结合 Three.js ...

  5. 使用CSS实现《声生不息》节目Logo

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 <声生不息> 是芒果TV.香港电视广播有限公司和湖南卫视联合推 ...

  6. 使用CSS实现多种Noise噪点效果

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 在插画中添加噪点肌理可以营造出一种自然的氛围.噪点肌理可以用于塑造阴影.高 ...

  7. 纯Shading Language绘制飞机火焰效果

    上篇<纯Shading Language绘制HTML5时钟>体现了GLSL可编程性特点,但没有体现GLSL可编程出各种酷炫效果的特点,今天我们将用纯Shading Language绘制火焰 ...

  8. css简单实现火焰效果

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  9. Vue.js 和 MVVM 小细节

    MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自 ...

  10. js学习笔记:操作iframe

    iframe可以说是比较老得话题了,而且网上也基本上在说少用iframe,其原因大致为:堵塞页面加载.安全问题.兼容性问题.搜索引擎抓取不到等等,不过相对于这些缺点,iframe的优点更牛,跨域请求. ...

随机推荐

  1. AdaBoost算法解密:从基础到应用的全面解析

    本文全面而深入地探讨了AdaBoost算法,从其基础概念和原理到Python实战应用.文章不仅详细解析了AdaBoost的优缺点,还通过实例展示了如何在Python中实现该算法. 关注TechLead ...

  2. Reflect API:每个 JavaScript 开发人员都需要的瑞士军刀

    前言 您是否曾经希望拥有一个神奇的工具包,可以让您像超级英雄一样控制 JavaScript 对象?向ReflectAPI 打个招呼吧,它是 ES6 中引入的一个新的全局对象 ,它能够处理简单的代码操作 ...

  3. java.util.List如何用

    起因是这样,我在学习Javaweb,然后就突然有很多类似的语句 这是什么意思呢?让我们一起来解决看看吧! List有序集合(也成为序列),用户可以精确控制列表中每个元素的插入位置.用户可以通过整数索引 ...

  4. java中的try-with-resource语法

    java的世界千奇百怪...当我甩出如下代码段,不知阁下如何应对? try(A a=new A()){ 和a变量无关的业务代码块 } 没错,这就是"臭名昭著"的try-with-r ...

  5. 利用Jdk动态代理模拟MyBatis的Mapper功能

    本文将先介绍jdk动态代理的基本用法,并对其原理和注意事项予以说明.之后将以两个最常见的应用场景为例,进行代码实操.这两个应用场景分别是拦截器和声明性接口,它们在许多开发框架中广泛使用.比如在spri ...

  6. 学习tinyriscv(1):安装tinyriscv的工具链

    因为毕设是CPU的低功耗设计,所以开始看cpu,打算还是先从这个tinyriscv学起,昨天把环境下好了,第一步是用git去clone代码,这个首先要下载git,然后在目标文件夹鼠标右键,选择&quo ...

  7. 聊一聊 C# 线程切换后上下文都去了哪里

    一:背景 1. 讲故事 总会有一些朋友是不是问一个问题,在 Windows 中线程做了上下文切换,请问被切的线程他的寄存器上下文都去了哪里?能不能给我挖出来?这个问题其实比较底层,如果对操作系统没有个 ...

  8. C++ Qt开发:QSqlDatabase数据库组件

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QSqlDat ...

  9. JavaImprove--Lesson02--Object类,Objects工具类,封装类

    一.Object类 Java中的Object类是所有类的超类,它是Java类层次结构的根类.这意味着所有的类都直接或间接地继承自Object类 equals(Object obj): 用于比较两个对象 ...

  10. 2023-06-30:给你一个 rows * cols 大小的矩形披萨和一个整数 k, 矩形包含两种字符: ‘A‘ (表示苹果)和 ‘.‘ (表示空白格子), 你需要切披萨 k-1 次,得到 k 块披

    2023-06-30:给你一个 rows * cols 大小的矩形披萨和一个整数 k, 矩形包含两种字符: 'A' (表示苹果)和 '.' (表示空白格子), 你需要切披萨 k-1 次,得到 k 块披 ...