欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

3D炫酷雪花背景的实现

程序员文章站 2022-05-26 19:46:44
...

    3D炫酷雪花背景,并且雪的大小还会随时间变化。目前已经开源到码云上,源码下载地址:https://gitee.com/hj1991/snowFalling 。

效果展示(微信截动态变化背景图,效果不太好。另外,由于不会P图,雪花用的图片就是一个白色的圆,特别是近镜头的时候,效果有点搓哈,囧囧囧~,会p图的同学可以将ParticleSmoke.png P成无背景的雪花图片,要是能把P好的图片给我的话就太谢谢了!):

3D炫酷雪花背景的实现

代码讲解:

index.html

<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">

<meta name="viewport" content="width=device-width,hight=device-hight,minimum-scale=1.0,maximum-scale=1.0,ser-scalable=none">
<title>开始下雪了</title>
<link type="text/css" rel="stylesheet" href="">

<style>
*{margin: 0;padding: 0;overflow: hidden;}
body{
	background-image:url('images/background.jpg');
	background-size:cover;
	background-repeat: no-repeat;
	position: relative;
	width:100%;
}

</style>
</head>

<body>
<audio autoplay="autoplay" loop="loop"><source src="js/网络歌手-冰海.mp3" type="audio/ogg"></audio>
</body>
<script type="text/javascript" src="./js/ThreeCanvas.js"></script>
<script src="http://www.jq22.com/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="./js/Snow.js"></script>
<script type="text/javascript" src="./js/snowFall.js"></script>
<script type="text/javascript" src="./js/snowFalling.js"></script>
<script>
	$.snowFalling({
		//初始雪花粒子数量,密度
		particleNo:0,
		//粒子下拉速度
		particleSpeed:50,
		//粒子在垂直(Y轴)方向运动范围
		particleY_Range:window.innerWidth,
		//粒子在垂直(X轴)方向运动范围
		particleX_Range:window.innerHeight,
	    //相机离Z轴原点距离
	    zIndex:600,
	  //摄像机视野角度
	    angle:55,
	    wind_weight:10 //风速:大于0,雪花向右飘;小于0,雪花向左飘;等于0,无风。
		});
</script>


</html>

index.html除了设置下雪的参数,加个背景音乐外,没有其他的了。

snowFalling.js

 //创建snowFall对象
var snowFall=new snowFall(window.innerWidth,window.innerHeight,true,20);
//容器
var container;

//绑定jquery方法
jQuery.extend({
	snowFalling:function(options){
		 var defaults = {     
			//创建粒子数量,密度
			particleNo: 500,
			//粒子下拉速度
			particleSpeed:15,
			//粒子在垂直(Y轴)方向运动范围
			particleY_Range:1300,
			//粒子在垂直(X轴)方向运动范围
			particleX_Range:1000,
		    //相机离Z轴原点距离
		    zIndex:600,
		    //风力强度,正值向右,负值向左
		    wind_weight:0,
		    //摄像机视野角度
		    angle:55
		  };  
		  
		var particleImage = new Image();
		particleImage.src = "images/ParticleSmoke.png";
		var opts = $.extend(defaults, options);
		opts.particleImage=particleImage;
		opts.screenWidth=window.innerWidth;
		opts.screenHeight=window.innerHeight;
		//初始化下雪厂景
		snowFall.init(opts);
		
		container = document.createElement('div');
		document.body.appendChild(container);
		container.appendChild(snowFall.renderer.domElement );
		
		//雪景变化
		snowFall.snowFallChange();
	}
});

snowFalling.js主要做了三件事:1、获取index.html中设置的参数;2、new 一个snowFall对象,并进行初始化;3、调用snowFall.snowFallChange()函数;


snowFall.js

function snowFall(screenWidth,screenHeight,flag,parameter){
	this.screenWidth=screenWidth;
	this.screenHeight=screenHeight;
	this.flag=flag;
	this.parameter=parameter;
}
snowFall.prototype.init=function(opts){
		snowFall.options=opts;
//		透视相机,物体大小随距离摄像机远近改变,对比投影相机
//		相机的上方向为Y轴,右方向为X轴,沿着Z轴垂直朝里(视野角:fov; 纵横比:aspect; 相机离视最近的距离:near; 相机离视体积最远距离:far)		
		snowFall.camera = new THREE.PerspectiveCamera( opts.angle, snowFall.screenWidth / snowFall.screenHeight, 1, 10000 );
		//设置摄像机z坐标位置距离原点向外距离
		snowFall.camera.position.z = snowFall.options.zIndex;
		//创建场景
		snowFall.scene = new THREE.Scene();
		snowFall.scene.add(snowFall.camera);
		//创建渲染器
		snowFall.renderer = new THREE.CanvasRenderer();
		snowFall.renderer.setSize(snowFall.screenWidth, snowFall.screenHeight);
		//创建材料
		snowFall.material = new THREE.ParticleBasicMaterial( { map: new THREE.Texture(snowFall.options.particleImage) } );
		
		snowFall.particles = []; 
		
		for (var i = 0; i < snowFall.options.particleNo; i++) {
			snowFall.addparticle(); 
		}
}
snowFall.prototype.loop=function(){
	for(var i = 0; i<snowFall.particles.length; i++){
		snowFall.particle = snowFall.particles[i]; 
		snowFall.particle.updatePhysics(); 
		with(snowFall.particle.position){
			if(y<-snowFall.options.particleY_Range/2){
				y+=snowFall.options.particleY_Range;
			} 
//			Z轴位置不变
			if(x>snowFall.options.screenWidth/2){
				x-=snowFall.options.screenWidth;
			}else if(x<-snowFall.options.screenWidth/2){
				x+=snowFall.options.screenWidth;
			} 
			//风力偏向效果
			x+=snowFall.options.wind_weight;
		}				
	}
	snowFall.camera.lookAt(snowFall.scene.position); 
	snowFall.renderer.render( snowFall.scene, snowFall.camera );
}

snowFall.prototype.addParticle=function(){
	snowFall.particle = new Snow(snowFall.material);
	snowFall.particle.position.x = Math.random() * snowFall.options.screenWidth *2- snowFall.options.screenWidth/2;
	snowFall.particle.position.y = Math.random() * snowFall.options.screenHeight * 2 - snowFall.options.screenHeight;
	snowFall.particle.position.z = Math.random() * snowFall.options.zIndex * 2 - snowFall.options.zIndex*1;
	snowFall.particle.scale.x = snowFall.particle.scale.y =  1;
	snowFall.scene.add( snowFall.particle );		
	snowFall.particles.push(snowFall.particle); 
}

snowFall.prototype.removeParticle=function(){
	snowFall.particle=snowFall.particles.pop();
	snowFall.scene.remove( snowFall.particle ); 
}

snowFall.prototype.parameterChange=function(){
	if(snowFall.particles.length>=500){
		snowFall.parameter=500;
	}else if(snowFall.particles.length>=200&&snowFall.particles.length<500){
		snowFall.parameter=300;
	}else if(snowFall.particles.length>=100&&snowFall.particles.length<200){
		snowFall.parameter=100;
	}else if(snowFall.particles.length>=50&&snowFall.particles.length<100){
		snowFall.parameter=50;
	}else{
		snowFall.parameter=20;
	}
}

snowFall.prototype.particlesCountChange=function(){
	snowFall.parameterChange(snowFall.particles);
	if(snowFall.flag){
		for(var j=0;j<parseInt(snowFall.parameter*Math.random());j++){
			if(snowFall.particles.length>=1500){
				snowFall.flag=false;
				return snowFall.flag;
			}
			snowFall.addParticle();
		}
	}else{
		for(var j=0;j<parseInt(snowFall.parameter*Math.random());j++){
			if(snowFall.particles.length>0){
				snowFall.removeParticle();
			}else{
				snowFall.flag=true;
			}
		}
	}
}

snowFall.prototype.snowFallChange=function(){
	var time1=setInterval( snowFall.loop, snowFall.options.particleSpeed );
		setInterval(function(){
			snowFall.options.particleNo+=parseInt(10*Math.random());
			window.clearInterval(time1); 
			snowFall.particlesCountChange();
			time1=setInterval( snowFall.loop, snowFall.options.particleSpeed);
		},3000);
}

snowFall.js主要是已Prototype/Constructor杂合方式创建了一个snowFall类。

function snowFall() 构造函数;

snowFall.init() 初始化,主要实现包括三维相机、场景、渲染器、材料的初始化,以及开始雪花粒子数量的设置;

snowFall.snowFallChange() 雪景的变化,包括雪花粒子数量的变化以及雪花移动位置的动态变化;

snowFall.particlesCountChange() 雪花粒子数量的变化,雪花粒子数量一开始是默认增加,当达到1500的时候,雪花粒子数量                                         就会减小;雪花粒子每次循环增加/减小的数量是随机的,但增加/减少的雪花粒子速

                                        率 和当前雪花粒子数量正相关。

snowFall.loop() 雪花粒子位置的变化;

snowFall.parameterChange() 雪花粒子增加/减少速度变化;

snowFall.addParticle() 增加雪花粒子;

snowFall.removeParticle() 移除雪花粒子;


Snow.js

Snow=function(material){
	THREE.Particle.call(this,material);
	this.velocity=new THREE.Vector3(0,-8,0);//速度;
	//this.velocity.rotateX(2);//旋转;
	this.gravity=new THREE.Vector3(0,0,0);//加速度;
	this.drag=1;//速度相乘系数;
};
//Particle:粒子;
//prototype:原形;
Snow.prototype=new THREE.Particle();
Snow.prototype.constructor=Snow;//构造函数
Snow.prototype.updatePhysics=function(){
	this.velocity.multiplyScalar(this.drag);//矢量相乘函数
	this.velocity.addSelf(this.gravity);//矢量相加函数
	this.position.addSelf(this.velocity);//矢量相加函数
}
var TO_RADIANS=Math.PI/180;//角度向弧度转换系数*
THREE.Vector3.prototype.rotateY=function(angle){
	//绕Y轴顺时针旋转angle;
	cosRY=Math.cos(angle*TO_RADIANS);
	sinRY=Math.sin(angle*TO_RADIANS);
	var tempz=this.z;
	var tempx=this.x;
	this.x=(tempx*cosRY)+(tempz*sinRY);
	this.z=(tempx*-sinRY)+(tempz*cosRY);
}
THREE.Vector3.prototype.rotateX=function(angle){
	//绕X轴顺时针旋转angle;
	cosRY=Math.cos(angle*TO_RADIANS);
	sinRY=Math.sin(angle*TO_RADIANS);
	var tempz=this.z;;
	var tempy=this.y;
	this.y=(tempy*cosRY)+(tempz*sinRY);
	this.z=(tempy*-sinRY)+(tempz*cosRY);
}
THREE.Vector3.prototype.rotateZ=function(angle){
	//绕Z轴顺时针旋转angle;
	cosRY=Math.cos(angle*TO_RADIANS);
	sinRY=Math.sin(angle*TO_RADIANS);
	var tempx=this.x;;
	var tempy=this.y;
	this.y=(tempy*cosRY)+(tempx*sinRY);
	this.x=(tempy*-sinRY)+(tempx*cosRY);
}

snow.js 主要是对ThreeCanvas.js的应用,想学的可以去了解一下three.js和ThreeCanvas.js