在threejs中有一个为我们提供了可以实现火焰和烟雾效果的包,我们可以直接引用这个包,通过设置某些参数实现需要的效果。
第一步引入fire包,可在工程文件夹下的example文件夹中找到
<script type="text/javascript" src="js/objects/Fire.js" ></script>
第二步,新建任意一个geometry对象作为fire的载体
构造器Fire(geometry,option)
//var plane=new THREE.PlaneBufferGeometry(20,20,1);var cube=new THREE.BoxBufferGeometry(30,30,30);fire=new THREE.Fire(cube,{textureWidth:512,textureHeight:512,debug:false});fire.position.z=-2;scene.add(fire);
最后,添加资源就有了效果
fire.addSource(0.5,0.1,0.1,1.0,0.0,1.0);
也可以使用canvas贴图实现文字火焰效果,画好了canvas,注意需要声明更新材质
Text:function(){//文字火焰效果var text="Three JS";var color='#ff0040';var canvas=document.createElement("canvas");canvas.width=1024;canvas.height=1024;var ctx=canvas.getContext('2d');ctx.strokeStyle="black";ctx.strokeRect(0,0,canvas.width,canvas.height);ctx.textAlign='center';ctx.textBaseline='middle'; ctx.font='180pt Arial';ctx.lineWidth=5;ctx.strokeStyle=color;ctx.strokeText(text,canvas.width/2,canvas.height*0.75);var texture=new THREE.Texture(canvas);texture.needsUpdate=true;fire.setSourceMap(texture);}
常用方法:
- clearSources()
清除资源 - addSource(u, v, radius, density, windX, windY);
添加资源 - setSourceMap(texture)
设置贴图
可选属性参数:
var params={//基本火焰参数设置color1:'#ffffff',//内焰color2:'#ffa000',//外焰color3:'#000000',//烟雾colorBias:0.8,//颜色偏差burnRate:0.35,//燃烧率diffuse:1.33,//扩散viscosity:0.25,//粘度expansion:-0.25,//膨胀swirl:50.0,//旋转drag:0.35,//拖拽airSpeed:12.0,//空气速度windX:0.0,//风向XwindY:0.75,//风向Yspeed:500.0,//火焰速度massConservation:false,//质量守恒}
源码示例:
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"><title>火焰和烟雾效果</title><script type="text/javascript" src="js/WebGL.js" ></script><script type="text/javascript" src="js/three.js" ></script><script type="text/javascript" src="js/controls/OrbitControls.js" ></script><script type="text/javascript" src="js/libs/stats.min.js" ></script><script type="text/javascript" src="js/libs/dat.gui.min.js" ></script><script type="text/javascript" src="js/objects/Fire.js" ></script><style>body{padding: 0;margin: 0;overflow: hidden;}</style></head><body><script>if(WEBGL.isWebGLAvailable()===false)document.body.appendChild(WEBGL.getWebGLErrorMessage());var scene,renderer,camera,controls,stats;function init(){scene=new THREE.Scene();scene.background=new THREE.Color(0x000000);renderer=new THREE.WebGLRenderer({antialias:true,alpha:true});renderer.setSize(window.innerWidth,window.innerHeight);renderer.setPixelRatio(window.devicePixelRatio);document.body.appendChild(renderer.domElement);camera=new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);camera.position.set(0,20,50);controls=new THREE.OrbitControls(camera,renderer.domElement);controls.enableDamping=true;controls.minDistance=1;controls.maxDistance=500;stats=new Stats();document.body.appendChild(stats.domElement);scene.add(new THREE.AmbientLight(0XCCCCCC,0.4));var pointLight=new THREE.PointLight(0xffffff,0.8);scene.add(pointLight);}var axes;var fire;function initModel(){axes=new THREE.AxesHelper(30);scene.add(axes);axes.visible=false;//var plane=new THREE.PlaneBufferGeometry(20,20,1);var cube=new THREE.BoxBufferGeometry(30,30,30);fire=new THREE.Fire(cube,{textureWidth:512,textureHeight:512,debug:false});fire.position.z=-2;scene.add(fire);}var mouse=new THREE.Vector2();var raycaster=new THREE.Raycaster();function rayEvent(event){if(event.touches){var touchE=event.touches[0];mouse.x=(touchE.pageX/window.innerWidth)*2-1;mouse.y=-(touchE.pageY/window.innerHeight)*2+1;}else{mouse.x=(event.clientX/window.innerWidth)*2-1;mouse.y=-(event.clientY/window.innerHeight)*2+1;}raycaster.setFromCamera(mouse,camera);var intersects=raycaster.intersectObjects(scene.children,true);if(intersects.length>0){intersects[0].object.material.color.set(0xff0000);}else{console.log("未检测到物体!");}}var settings;function initGui(){
/* settings={axesVisible:false}*/var params={//基本火焰参数设置color1:'#ffffff',//内焰color2:'#ffa000',//外焰color3:'#000000',//烟雾colorBias:0.8,//颜色偏差burnRate:0.35,//燃烧率diffuse:1.33,//扩散viscosity:0.25,//粘度expansion:-0.25,//膨胀swirl:50.0,//旋转drag:0.35,//拖拽airSpeed:12.0,//空气速度windX:0.0,//风向XwindY:0.75,//风向Yspeed:500.0,//火焰速度massConservation:false,//质量守恒//基本效果Single:function(){//单焰效果fire.clearSources();fire.addSource(0.5,0.1,0.1,1.0,0.0,1.0);},Multiple:function(){//多焰效果fire.clearSources();fire.addSource(0.1,0.1,0.1,0.5,0.0,1.0);fire.addSource(0.4,0.1,0.1,0.5,0.0,1.0);fire.addSource(0.7,0.1,0.1,0.5,0.0,1.0);},Text:function(){//文字火焰效果var text="Three JS";var color='#ff0040';var canvas=document.createElement("canvas");canvas.width=1024;canvas.height=1024;var ctx=canvas.getContext('2d');ctx.strokeStyle="black";ctx.strokeRect(0,0,canvas.width,canvas.height);ctx.textAlign='center';ctx.textBaseline='middle'; ctx.font='180pt Arial';ctx.lineWidth=5;ctx.strokeStyle=color;ctx.strokeText(text,canvas.width/2,canvas.height*0.75);var texture=new THREE.Texture(canvas);texture.needsUpdate=true;fire.setSourceMap(texture);},//参数效果Candle:function(){//蜡烛var paraArr=[0xffffff,0xffa000,0x000000,0.0,0.5,0.3,1.6,1.33,1.33,0.0,0.0,0.0,8.0,500.0,false];updateAll(paraArr);},Torch:function(){//火炬var paraArr=[0xffdcaa,0xffa000,0x000000,0.0,0.75,0.9,1.0,1.33,0.25,0.0,50.0,0.35,10.0,500.0,false];updateAll(paraArr);},Campfire:function(){//篝火var paraArr=[0xffffff,0xffa000,0x000000,0.0,0.75,0.8,0.3,1.33,0.25,-0.25,50.0,0.35,12.0,500.0,false];updateAll(paraArr);},Fireball:function(){//火球var paraArr=[0xffffff,0xffa000,0x000000,0.0,0.75,0.8,1.2,3.0,0.0,0.0,6.0,0.0,20.0,500.0,false];updateAll(paraArr);},Iceball:function(){//冰球var paraArr=[0x00bdf7,0x1b3fb6,0x001869,0.0,-0.25,0.25,2.6,5.0,0.5,0.75,30.0,0.0,40.0,500.0,false];updateAll(paraArr);},Smoke:function(){//浓烟var paraArr=[0xd2d2d2,0xd7d7d7,0x000000,-0.05,0.15,0.95,0.0,1.5,0.25,0.2,3.75,0.4,18.0,500.0,false];updateAll(paraArr);},Cigar:function(){//香烟的烟var paraArr=[0xc5c5c5,0x787878,0x000000,0.0,0.3,0.55,0.0,1.3,0.05,-0.05,3.7,0.6,6.0,500.0,false];updateAll(paraArr);}}function updateAll(arr){fire.color1.set(arr[0]);fire.color2.set(arr[1]);fire.color3.set(arr[2]);fire.windVector.x=arr[3];fire.windVector.y=arr[4];fire.colorBias=arr[5];fire.burnRate=arr[6];fire.diffuse=arr[7];fire.viscosity=arr[8];fire.expansion=arr[9];fire.swirl=arr[10];fire.drag=arr[11];fire.airSpeed=arr[12];fire.speed=arr[13];fire.massConservation=arr[14];var i=0;for(var index in gui.__controllers){gui.__controllers[index].setValue(arr[i]);i++;}}var gui=new dat.GUI();
/* gui.add(settings,"axesVisible").onChange(function(e){axes.visible=e;});*/var g1=gui.addFolder("基本效果");g1.add(params,"Single").name("单焰效果");g1.add(params,"Multiple").name('多焰效果');g1.add(params,"Text").name("文本火焰");g1.open();var g2=gui.addFolder("参数效果");g2.add(params,'Candle').name("蜡烛火焰");g2.add(params,'Torch').name("火炬火焰");g2.add(params,'Campfire').name("篝火火焰");g2.add(params,'Fireball').name("火球火焰");g2.add(params,'Iceball').name("冰球火焰");g2.add(params,'Smoke').name("浓烟");g2.add(params,'Cigar').name("香烟的烟");g2.open();gui.addColor(params,"color1").onChange(function(e){fire.color1.set(e);});gui.addColor(params,"color2").onChange(function(e){fire.color2.set(e);});gui.addColor(params,"color3").onChange(function(e){fire.color3.set(e);});gui.add(params,"windX",-5,5).step(0.1).onChange(function(e){fire.windVector.x=e;});gui.add(params,"windY",-5,5).step(0.1).onChange(function(e){fire.windVector.y=e;});gui.add(params,"colorBias",0.0,1.0).onChange(function(e){fire.colorBias=e;});gui.add(params,"burnRate",0.0,10.0).onChange(function(e){fire.burnRate=e;});gui.add(params,"diffuse",0.0,5.0).step(0.1).onChange(function(e){fire.diffuse=e;});gui.add(params,"viscosity",0.0,5.0).step(0.1).onChange(function(e){fire.viscosity=e;});gui.add(params,"expansion",-1.0,1.0).step(0.01).onChange(function(e){fire.expansion=e;});gui.add(params,"swirl",0.0,50.0).onChange(function(e){fire.swirl=e;});gui.add(params,"drag",0.0,1.0).step(0.01).onChange(function(e){fire.drag=e;});gui.add(params,"airSpeed",0.0,50.0).onChange(function(e){fire.airSpeed=e;});gui.add(params,"speed",0,1000).onChange(function(e){fire.speed=e;});gui.add(params,"massConservation").onChange(function(e){fire.massConservation=e;});params.Single();}function onWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);}function render(){renderer.render(scene,camera);}function animate(){render();stats.update();controls.update();window.onresize=onWindowResize();requestAnimationFrame(animate);}(function threeStart(){init();initModel();initGui();animate();//window.addEventListener("click",rayEvent,false);//window.addEventListener("touchstart",rayEvent,false);}());</script></body>
</html>