在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);
}
常用方法:
可选属性参数:
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,//风向X
windY:0.75,//风向Y
speed: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,//风向X
windY:0.75,//风向Y
speed: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>