炫酷的粒子效果

炫酷的粒子效果

源码地址:https://codepen.io/zadvorsky/pen/PNXbGo
在这里插入图片描述
代码已经整理好了,非常炫酷,可以单击并拖动以控制动画,但好像只能放两张图片(我自己尝试过可能自己技术不行吧),喜欢的话可以复制粘贴拿去~

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.min.js"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
		<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/175711/bas.js"></script>
		<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/175711/OrbitControls-2.js"></script>	
	</head>
	<style>
		body {
			margin: 0;
			overflow: hidden;
		}
		
		canvas {
			background-image: radial-gradient(#666, #333);
		}
		
		#instructions {
			position: absolute;
			color: #fff;
			bottom: 0;
			padding-bottom: 6px;
			font-family: sans-serif;
			width: 100%;
			text-align: center;
			pointer-events: none;
		}
	</style>
	<body>
		<div id="three-container"></div>
		
		<div id="instructions">
			click and drag to control the animation
		</div>
	</body>
	<script>
		window.onload = init;
		console.ward = function() {}; // what warnings?
		
		function init() {
		  var root = new THREERoot({
		    createCameraControls: !true,
		    antialias: (window.devicePixelRatio === 1),
		    fov: 80
		  });
		
		  root.renderer.setClearColor(0x000000, 0);
		  root.renderer.setPixelRatio(window.devicePixelRatio || 1);
		  root.camera.position.set(0, 0, 60);
		
		  var width = 100;
		  var height = 60;
		  
		  var slide = new Slide(width, height, 'out');
			var l1 = new THREE.ImageLoader();
			l1.setCrossOrigin('Anonymous');
			l1.load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/175711/winter.jpg', function(img) {
			  slide.setImage(img);
			})
		  root.scene.add(slide);
		
		  var slide2 = new Slide(width, height, 'in');
		  var l2 = new THREE.ImageLoader();
			l2.setCrossOrigin('Anonymous');
			l2.load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/175711/spring.jpg', function(img) {
				slide2.setImage(img);
			})
			
		  root.scene.add(slide2);
		  
		
		  var tl = new TimelineMax({repeat:-1, repeatDelay:1.0, yoyo: true});
		
		  tl.add(slide.transition(), 0);
		  tl.add(slide2.transition(), 0);
		
		  createTweenScrubber(tl);
		
		  window.addEventListener('keyup', function(e) {
		    if (e.keyCode === 80) {
		      tl.paused(!tl.paused());
		    }
		  });
		}
		
		
		// CLASSES
		
		
		function Slide(width, height, animationPhase) {
		  var plane = new THREE.PlaneGeometry(width, height, width * 2, height * 2);
		
		  THREE.BAS.Utils.separateFaces(plane);
		
		  var geometry = new SlideGeometry(plane);
		
		  geometry.bufferUVs();
		
		  var aAnimation = geometry.createAttribute('aAnimation', 2);
		  var aStartPosition = geometry.createAttribute('aStartPosition', 3);
		  var aControl0 = geometry.createAttribute('aControl0', 3);
		  var aControl1 = geometry.createAttribute('aControl1', 3);
		  var aEndPosition = geometry.createAttribute('aEndPosition', 3);
		
		  var i, i2, i3, i4, v;
		
		  var minDuration = 0.8;
		  var maxDuration = 1.2;
		  var maxDelayX = 0.9;
		  var maxDelayY = 0.125;
		  var stretch = 0.11;
		
		  this.totalDuration = maxDuration + maxDelayX + maxDelayY + stretch;
		
		  var startPosition = new THREE.Vector3();
		  var control0 = new THREE.Vector3();
		  var control1 = new THREE.Vector3();
		  var endPosition = new THREE.Vector3();
		
		  var tempPoint = new THREE.Vector3();
		
		  function getControlPoint0(centroid) {
		    var signY = Math.sign(centroid.y);
		
		    tempPoint.x = THREE.Math.randFloat(0.1, 0.3) * 50;
		    tempPoint.y = signY * THREE.Math.randFloat(0.1, 0.3) * 70;
		    tempPoint.z = THREE.Math.randFloatSpread(20);
		
		    return tempPoint;
		  }
		
		  function getControlPoint1(centroid) {
		    var signY = Math.sign(centroid.y);
		
		    tempPoint.x = THREE.Math.randFloat(0.3, 0.6) * 50;
		    tempPoint.y = -signY * THREE.Math.randFloat(0.3, 0.6) * 70;
		    tempPoint.z = THREE.Math.randFloatSpread(20);
		
		    return tempPoint;
		  }
		
		  for (i = 0, i2 = 0, i3 = 0, i4 = 0; i < geometry.faceCount; i++, i2 += 6, i3 += 9, i4 += 12) {
		    var face = plane.faces[i];
		    var centroid = THREE.BAS.Utils.computeCentroid(plane, face);
		
		    // animation
		    var duration = THREE.Math.randFloat(minDuration, maxDuration);
		    var delayX = THREE.Math.mapLinear(centroid.x, -width * 0.5, width * 0.5, 0.0, maxDelayX);
		    var delayY;
		
		    if (animationPhase === 'in') {
		      delayY = THREE.Math.mapLinear(Math.abs(centroid.y), 0, height * 0.5, 0.0, maxDelayY)
		    }
		    else {
		      delayY = THREE.Math.mapLinear(Math.abs(centroid.y), 0, height * 0.5, maxDelayY, 0.0)
		    }
		
		    for (v = 0; v < 6; v += 2) {
		      aAnimation.array[i2 + v]     = delayX + delayY + (Math.random() * stretch * duration);
		      aAnimation.array[i2 + v + 1] = duration;
		    }
		
		    // positions
		
		    endPosition.copy(centroid);
		    startPosition.copy(centroid);
		
		    if (animationPhase === 'in') {
		      control0.copy(centroid).sub(getControlPoint0(centroid));
		      control1.copy(centroid).sub(getControlPoint1(centroid));
		    }
		    else { // out
		      control0.copy(centroid).add(getControlPoint0(centroid));
		      control1.copy(centroid).add(getControlPoint1(centroid));
		    }
		
		    for (v = 0; v < 9; v += 3) {
		      aStartPosition.array[i3 + v]     = startPosition.x;
		      aStartPosition.array[i3 + v + 1] = startPosition.y;
		      aStartPosition.array[i3 + v + 2] = startPosition.z;
		
		      aControl0.array[i3 + v]     = control0.x;
		      aControl0.array[i3 + v + 1] = control0.y;
		      aControl0.array[i3 + v + 2] = control0.z;
		
		      aControl1.array[i3 + v]     = control1.x;
		      aControl1.array[i3 + v + 1] = control1.y;
		      aControl1.array[i3 + v + 2] = control1.z;
		
		      aEndPosition.array[i3 + v]     = endPosition.x;
		      aEndPosition.array[i3 + v + 1] = endPosition.y;
		      aEndPosition.array[i3 + v + 2] = endPosition.z;
		    }
		  }
		
		  var material = new THREE.BAS.BasicAnimationMaterial(
		    {
		      shading: THREE.FlatShading,
		      side: THREE.DoubleSide,
		      uniforms: {
		        uTime: {type: 'f', value: 0}
		      },
		      shaderFunctions: [
		        THREE.BAS.ShaderChunk['cubic_bezier'],
		        //THREE.BAS.ShaderChunk[(animationPhase === 'in' ? 'ease_out_cubic' : 'ease_in_cubic')],
		        THREE.BAS.ShaderChunk['ease_in_out_cubic'],
		        THREE.BAS.ShaderChunk['quaternion_rotation']
		      ],
		      shaderParameters: [
		        'uniform float uTime;',
		        'attribute vec2 aAnimation;',
		        'attribute vec3 aStartPosition;',
		        'attribute vec3 aControl0;',
		        'attribute vec3 aControl1;',
		        'attribute vec3 aEndPosition;',
		      ],
		      shaderVertexInit: [
		        'float tDelay = aAnimation.x;',
		        'float tDuration = aAnimation.y;',
		        'float tTime = clamp(uTime - tDelay, 0.0, tDuration);',
		        'float tProgress = ease(tTime, 0.0, 1.0, tDuration);'
		        //'float tProgress = tTime / tDuration;'
		      ],
		      shaderTransformPosition: [
		        (animationPhase === 'in' ? 'transformed *= tProgress;' : 'transformed *= 1.0 - tProgress;'),
		        'transformed += cubicBezier(aStartPosition, aControl0, aControl1, aEndPosition, tProgress);'
		      ]
		    },
		    {
		      map: new THREE.Texture(),
		    }
		  );
		
		  THREE.Mesh.call(this, geometry, material);
		
		  this.frustumCulled = false;
		}
		Slide.prototype = Object.create(THREE.Mesh.prototype);
		Slide.prototype.constructor = Slide;
		Object.defineProperty(Slide.prototype, 'time', {
		  get: function () {
		    return this.material.uniforms['uTime'].value;
		  },
		  set: function (v) {
		    this.material.uniforms['uTime'].value = v;
		  }
		});
		
		Slide.prototype.setImage = function(image) {
		  this.material.uniforms.map.value.image = image;
		  this.material.uniforms.map.value.needsUpdate = true;
		};
		
		Slide.prototype.transition = function() {
		  return TweenMax.fromTo(this, 3.0, {time:0.0}, {time:this.totalDuration, ease:Power0.easeInOut});
		};
		
		
		function SlideGeometry(model) {
		  THREE.BAS.ModelBufferGeometry.call(this, model);
		}
		SlideGeometry.prototype = Object.create(THREE.BAS.ModelBufferGeometry.prototype);
		SlideGeometry.prototype.constructor = SlideGeometry;
		SlideGeometry.prototype.bufferPositions = function () {
		  var positionBuffer = this.createAttribute('position', 3).array;
		
		  for (var i = 0; i < this.faceCount; i++) {
		    var face = this.modelGeometry.faces[i];
		    var centroid = THREE.BAS.Utils.computeCentroid(this.modelGeometry, face);
		
		    var a = this.modelGeometry.vertices[face.a];
		    var b = this.modelGeometry.vertices[face.b];
		    var c = this.modelGeometry.vertices[face.c];
		
		    positionBuffer[face.a * 3]     = a.x - centroid.x;
		    positionBuffer[face.a * 3 + 1] = a.y - centroid.y;
		    positionBuffer[face.a * 3 + 2] = a.z - centroid.z;
		
		    positionBuffer[face.b * 3]     = b.x - centroid.x;
		    positionBuffer[face.b * 3 + 1] = b.y - centroid.y;
		    positionBuffer[face.b * 3 + 2] = b.z - centroid.z;
		
		    positionBuffer[face.c * 3]     = c.x - centroid.x;
		    positionBuffer[face.c * 3 + 1] = c.y - centroid.y;
		    positionBuffer[face.c * 3 + 2] = c.z - centroid.z;
		  }
		};
		
		
		function THREERoot(params) {
		  params = utils.extend({
		    fov: 60,
		    zNear: 10,
		    zFar: 100000,
		
		    createCameraControls: true
		  }, params);
		
		  this.renderer = new THREE.WebGLRenderer({
		    antialias: params.antialias,
		    alpha: true
		  });
		  this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1));
		  document.getElementById('three-container').appendChild(this.renderer.domElement);
		
		  this.camera = new THREE.PerspectiveCamera(
		    params.fov,
		    window.innerWidth / window.innerHeight,
		    params.zNear,
		    params.zfar
		  );
		
		  this.scene = new THREE.Scene();
		
		  if (params.createCameraControls) {
		    this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
		  }
		
		  this.resize = this.resize.bind(this);
		  this.tick = this.tick.bind(this);
		
		  this.resize();
		  this.tick();
		
		  window.addEventListener('resize', this.resize, false);
		}
		THREERoot.prototype = {
		  tick: function () {
		    this.update();
		    this.render();
		    requestAnimationFrame(this.tick);
		  },
		  update: function () {
		    this.controls && this.controls.update();
		  },
		  render: function () {
		    this.renderer.render(this.scene, this.camera);
		  },
		  resize: function () {
		    this.camera.aspect = window.innerWidth / window.innerHeight;
		    this.camera.updateProjectionMatrix();
		
		    this.renderer.setSize(window.innerWidth, window.innerHeight);
		  }
		};
		
		
		// UTILS
		
		
		var utils = {
		  extend: function (dst, src) {
		    for (var key in src) {
		      dst[key] = src[key];
		    }
		
		    return dst;
		  },
		  randSign: function () {
		    return Math.random() > 0.5 ? 1 : -1;
		  },
		  ease: function (ease, t, b, c, d) {
		    return b + ease.getRatio(t / d) * c;
		  },
		  fibSpherePoint: (function () {
		    var vec = {x: 0, y: 0, z: 0};
		    var G = Math.PI * (3 - Math.sqrt(5));
		
		    return function (i, n, radius) {
		      var step = 2.0 / n;
		      var r, phi;
		
		      vec.y = i * step - 1 + (step * 0.5);
		      r = Math.sqrt(1 - vec.y * vec.y);
		      phi = i * G;
		      vec.x = Math.cos(phi) * r;
		      vec.z = Math.sin(phi) * r;
		
		      radius = radius || 1;
		
		      vec.x *= radius;
		      vec.y *= radius;
		      vec.z *= radius;
		
		      return vec;
		    }
		  })(),
		  spherePoint: (function () {
		    return function (u, v) {
		      u === undefined && (u = Math.random());
		      v === undefined && (v = Math.random());
		
		      var theta = 2 * Math.PI * u;
		      var phi = Math.acos(2 * v - 1);
		
		      var vec = {};
		      vec.x = (Math.sin(phi) * Math.cos(theta));
		      vec.y = (Math.sin(phi) * Math.sin(theta));
		      vec.z = (Math.cos(phi));
		
		      return vec;
		    }
		  })()
		};
		
		function createTweenScrubber(tween, seekSpeed) {
		  seekSpeed = seekSpeed || 0.001;
		
		  function stop() {
		    TweenMax.to(tween, 1, {timeScale:0});
		  }
		
		  function resume() {
		    TweenMax.to(tween, 1, {timeScale:1});
		  }
		
		  function seek(dx) {
		    var progress = tween.progress();
		    var p = THREE.Math.clamp((progress + (dx * seekSpeed)), 0, 1);
		
		    tween.progress(p);
		  }
		
		  var _cx = 0;
		
		  // desktop
		  var mouseDown = false;
		  document.body.style.cursor = 'pointer';
		
		  window.addEventListener('mousedown', function(e) {
		    mouseDown = true;
		    document.body.style.cursor = 'ew-resize';
		    _cx = e.clientX;
		    stop();
		  });
		  window.addEventListener('mouseup', function(e) {
		    mouseDown = false;
		    document.body.style.cursor = 'pointer';
		    resume();
		  });
		  window.addEventListener('mousemove', function(e) {
		    if (mouseDown === true) {
		      var cx = e.clientX;
		      var dx = cx - _cx;
		      _cx = cx;
		
		      seek(dx);
		    }
		  });
		  // mobile
		  window.addEventListener('touchstart', function(e) {
		    _cx = e.touches[0].clientX;
		    stop();
		    e.preventDefault();
		  });
		  window.addEventListener('touchend', function(e) {
		    resume();
		    e.preventDefault();
		  });
		  window.addEventListener('touchmove', function(e) {
		    var cx = e.touches[0].clientX;
		    var dx = cx - _cx;
		    _cx = cx;
		
		    seek(dx);
		    e.preventDefault();
		  });
		}

	</script>
</html>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值