html5 css3 粒子波

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>粒子波</title>
<style>
html,body {
height:100%;
background:#000;
}
body {
margin:0;
}
canvas {
display:block;
}
.waves {
position:absolute;
left:0;
top:0;
right:0;
bottom:0;
}
</style>
</head>
<body>
<div class="waves"></div>
<script>
class ShaderProgram {
constructor( holder, options = {} ) {
options = Object.assign( {
antialias: false,
depthTest: false,
mousemove: false,
autosize: true,
side: 'front',
vertex: `
precision highp float;
attribute vec4 a_position;
attribute vec4 a_color;
uniform float u_time;
uniform vec2 u_resolution;
uniform vec2 u_mousemove;
uniform mat4 u_projection;
varying vec4 v_color;
void main() {
gl_Position = u_projection * a_position;
gl_PointSize = (10.0 / gl_Position.w) * 100.0;
v_color = a_color;
}`,
fragment: `
precision highp float;
uniform sampler2D u_texture;
uniform int u_hasTexture;
varying vec4 v_color;
void main() {
if ( u_hasTexture == 1 ) {
gl_FragColor = v_color * texture2D(u_texture, gl_PointCoord);
} else {
gl_FragColor = v_color;
}
}`,
uniforms: {},
buffers: {},
camera: {},
texture: null,
onUpdate: ( () => {} ),
onResize: ( () => {} ),
}, options )
const uniforms = Object.assign( {
time: { type: 'float', value: 0 },
hasTexture: { type: 'int', value: 0 },
resolution: { type: 'vec2', value: [ 0, 0 ] },
mousemove: { type: 'vec2', value: [ 0, 0 ] },
projection: { type: 'mat4', value: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] },
}, options.uniforms )
const buffers = Object.assign( {
position: { size: 3, data: [] },
color: { size: 4, data: [] },
}, options.buffers )
const camera = Object.assign( {
fov: 60,
near: 1,
far: 10000,
aspect: 1,
z: 100,
perspective: true,
}, options.camera )
const canvas = document.createElement( 'canvas' )
const gl = canvas.getContext( 'webgl', { antialias: options.antialias } )
if ( ! gl ) return false
this.count = 0
this.gl = gl
this.canvas = canvas
this.camera = camera
this.holder = holder
this.onUpdate = options.onUpdate
this.onResize = options.onResize
this.data = {}
holder.appendChild( canvas )
this.createProgram( options.vertex, options.fragment )
this.createBuffers( buffers )
this.createUniforms( uniforms )
this.updateBuffers()
this.updateUniforms()
this.createTexture( options.texture )
gl.enable( gl.BLEND )
gl.enable( gl.CULL_FACE )
gl.blendFunc( gl.SRC_ALPHA, gl.ONE )
gl[ options.depthTest ? 'enable' : 'disable' ]( gl.DEPTH_TEST )
if ( options.autosize )
window.addEventListener( 'resize', e => this.resize( e ), false )
if ( options.mousemove )
window.addEventListener( 'mousemove', e => this.mousemove( e ), false )
this.resize()
this.update = this.update.bind( this )
this.time = { start: performance.now(), old: performance.now() }
this.update()
}
mousemove( e ) {
let x = e.pageX / this.width * 2 - 1
let y = e.pageY / this.height * 2 - 1
this.uniforms.mousemove = [ x, y ]
}
resize( e ) {
const holder = this.holder
const canvas = this.canvas
const gl = this.gl
const width = this.width = holder.offsetWidth
const height = this.height = holder.offsetHeight
const aspect = this.aspect = width / height
const dpi = this.dpi = devicePixelRatio
canvas.width = width * dpi
canvas.height = height * dpi
canvas.style.width = width + 'px'
canvas.style.height = height + 'px'
gl.viewport( 0, 0, width * dpi, height * dpi )
gl.clearColor( 0, 0, 0, 0 )
this.uniforms.resolution = [ width, height ]
this.uniforms.projection = this.setProjection( aspect )
this.onResize( width, height, dpi )
}
setProjection( aspect ) {
const camera = this.camera
if ( camera.perspective ) {
camera.aspect = aspect
const fovRad = camera.fov * ( Math.PI / 180 )
const f = Math.tan( Math.PI * 0.5 - 0.5 * fovRad )
const rangeInv = 1.0 / ( camera.near - camera.far )
const matrix = [
f / camera.aspect, 0, 0, 0,
0, f, 0, 0,
0, 0, (camera.near + camera.far) * rangeInv, -1,
0, 0, camera.near * camera.far * rangeInv * 2, 0
]
matrix[ 14 ] += camera.z
matrix[ 15 ] += camera.z
return matrix
} else {
return [
2 / this.width, 0, 0, 0,
0, -2 / this.height, 0, 0,
0, 0, 1, 0,
-1, 1, 0, 1,
]
}
}
createShader( type, source ) {
const gl = this.gl
const shader = gl.createShader( type )
gl.shaderSource( shader, source )
gl.compileShader( shader )
if ( gl.getShaderParameter (shader, gl.COMPILE_STATUS ) ) {
return shader
} else {
console.log( gl.getShaderInfoLog( shader ) )
gl.deleteShader( shader )
}
}
createProgram( vertex, fragment ) {
const gl = this.gl
const vertexShader = this.createShader( gl.VERTEX_SHADER, vertex )
const fragmentShader = this.createShader( gl.FRAGMENT_SHADER, fragment )
const program = gl.createProgram()
gl.attachShader( program, vertexShader )
gl.attachShader( program, fragmentShader )
gl.linkProgram( program )
if ( gl.getProgramParameter( program, gl.LINK_STATUS ) ) {
gl.useProgram( program )
this.program = program
} else {
console.log( gl.getProgramInfoLog( program ) )
gl.deleteProgram( program )
}
}
createUniforms( data ) {
const gl = this.gl
const uniforms = this.data.uniforms = data
const values = this.uniforms = {}
Object.keys( uniforms ).forEach( name => {
const uniform = uniforms[ name ]
uniform.location = gl.getUniformLocation( this.program, 'u_' + name )
Object.defineProperty( values, name, {
set: value => {
uniforms[ name ].value = value
this.setUniform( name, value )
},
get: () => uniforms[ name ].value
} )
} )
}
setUniform( name, value ) {
const gl = this.gl
const uniform = this.data.uniforms[ name ]
uniform.value = value
switch ( uniform.type ) {
case 'int': {
gl.uniform1i( uniform.location, value )
break
}
case 'float': {
gl.uniform1f( uniform.location, value )
break
}
case 'vec2': {
gl.uniform2f( uniform.location, ...value )
break
}
case 'vec3': {
gl.uniform3f( uniform.location, ...value )
break
}
case 'vec4': {
gl.uniform4f( uniform.location, ...value )
break
}
case 'mat2': {
gl.uniformMatrix2fv( uniform.location, false, value )
break
}
case 'mat3': {
gl.uniformMatrix3fv( uniform.location, false, value )
break
}
case 'mat4': {
gl.uniformMatrix4fv( uniform.location, false, value )
break
}
}
// ivec2 : uniform2i,
// ivec3 : uniform3i,
// ivec4 : uniform4i,
// sampler2D : uniform1i,
// samplerCube : uniform1i,
// bool : uniform1i,
// bvec2 : uniform2i,
// bvec3 : uniform3i,
// bvec4 : uniform4i,
}
updateUniforms() {
const gl = this.gl
const uniforms = this.data.uniforms
Object.keys( uniforms ).forEach( name => {
const uniform = uniforms[ name ]
this.uniforms[ name ] = uniform.value
} )
}
createBuffers( data ) {
const gl = this.gl
const buffers = this.data.buffers = data
const values = this.buffers = {}
Object.keys( buffers ).forEach( name => {
const buffer = buffers[ name ]
buffer.buffer = this.createBuffer( 'a_' + name, buffer.size )
Object.defineProperty( values, name, {
set: data => {
buffers[ name ].data = data
this.setBuffer( name, data )
if ( name == 'position' )
this.count = buffers.position.data.length / 3
},
get: () => buffers[ name ].data
} )
} )
}
createBuffer( name, size ) {
const gl = this.gl
const program = this.program
const index = gl.getAttribLocation( program, name )
const buffer = gl.createBuffer()
gl.bindBuffer( gl.ARRAY_BUFFER, buffer )
gl.enableVertexAttribArray( index )
gl.vertexAttribPointer( index, size, gl.FLOAT, false, 0, 0 )
return buffer
}
setBuffer( name, data ) {
const gl = this.gl
const buffers = this.data.buffers
if ( name == null && ! gl.bindBuffer( gl.ARRAY_BUFFER, null ) ) return
gl.bindBuffer( gl.ARRAY_BUFFER, buffers[ name ].buffer )
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( data ), gl.STATIC_DRAW )
}
updateBuffers() {
const gl = this.gl
const buffers = this.buffers
Object.keys( buffers ).forEach( name =>
buffers[ name ] = buffer.data
)
this.setBuffer( null )
}
createTexture( src ) {
const gl = this.gl
const texture = gl.createTexture()
gl.bindTexture( gl.TEXTURE_2D, texture )
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array( [ 0, 0, 0, 0 ] ) )
this.texture = texture
if ( src ) {
this.uniforms.hasTexture = 1
this.loadTexture( src )
}
}
loadTexture( src ) {
const gl = this.gl
const texture = this.texture
const textureImage = new Image()
textureImage.onload = () => {
gl.bindTexture( gl.TEXTURE_2D, texture )
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImage )
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR )
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR )
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
// gl.generateMipmap( gl.TEXTURE_2D )
}
textureImage.src = src
}
update() {
const gl = this.gl
const now = performance.now()
const elapsed = ( now - this.time.start ) / 5000
const delta = now - this.time.old
this.time.old = now
this.uniforms.time = elapsed
if ( this.count > 0 ) {
gl.clear( gl.COLORBUFFERBIT )
gl.drawArrays( gl.POINTS, 0, this.count )
}
this.onUpdate( delta )
requestAnimationFrame( this.update )
}
}
const pointSize = 2.5
const waves = new ShaderProgram( document.querySelector( '.waves' ), {
texture: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAb1BMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8v0wLRAAAAJHRSTlMAC/goGvDhmwcExrVjWzrm29TRqqSKenRXVklANSIUE8mRkGpv+HOfAAABCElEQVQ4y4VT13LDMAwLrUHteO+R9f/fWMfO6dLaPeKVEECRxOULWsEGpS9nULDwia2Y+ALqUNbAWeg775zv+sA4/FFRMxt8U2FZFCVWjR/YrH4/H9sarclSKdPMWKzb8VsEeHB3m0shkhVCyNzeXeAQ9Xl4opEieX2QCGnwGbj6GMyjw9t1K0fK9YZunPXeAGsfJtYjwzxaBnozGGorYz0ypK2HzQSYx1y8DgSRo2ewOiyh2QWOEk1Y9OrQV0a8TiBM1a8eMHWYnRMy7CZ4t1CmyRkhSUvP3gRXyHOCLBxNoC3IJv//ZrJ/kxxUHPUB+6jJZZHrpg6GOjnqaOmzp4NDR48OLxn/H27SRQ08S0ZJAAAAAElFTkSuQmCC',
uniforms: {
size: { type: 'float', value: pointSize },
field: { type: 'vec3', value: [ 0, 0, 0 ] },
speed: { type: 'float', value: 5 },
},
vertex: `
#define M_PI 3.1415926535897932384626433832795
precision highp float;
attribute vec4 a_position;
attribute vec4 a_color;
uniform float u_time;
uniform float u_size;
uniform float u_speed;
uniform vec3 u_field;
uniform mat4 u_projection;
varying vec4 v_color;
void main() {
vec3 pos = a_position.xyz;
pos.y += (
cos(pos.x / u_field.x * M_PI * 8.0 + u_time * u_speed) +
sin(pos.z / u_field.z * M_PI * 8.0 + u_time * u_speed)
) * u_field.y;
gl_Position = u_projection * vec4( pos.xyz, a_position.w );
gl_PointSize = ( u_size / gl_Position.w ) * 100.0;
v_color = a_color;
}`,
fragment: `
precision highp float;
uniform sampler2D u_texture;
varying vec4 v_color;
void main() {
gl_FragColor = v_color * texture2D(u_texture, gl_PointCoord);
}`,
onResize( w, h, dpi ) {
const position = [], color = []
const width = 400 * ( w / h )
const depth = 400
const height = 3
const distance = 5
for ( let x = 0; x < width; x += distance ) {
for ( let z = 0; z < depth; z+= distance ) {
position.push( - width / 2 + x, -30, -depth / 2 + z )
color.push( 0, 1 - ( x / width ) * 1, 0.5 + x / width * 0.5, z / depth )
}
}
this.uniforms.field = [ width, height, depth ]
this.buffers.position = position
this.buffers.color = color
this.uniforms.size = ( h / 400) * pointSize * dpi
},
} )</script>
</body>
</html>
二:粒子波浪

<html><head>
<meta charset="utf-8">
<title>粒子波浪</title>
<style>
html,body {
padding:0;
margin:0
}
canvas {
display:block
}
</style>
</head>
<body>
<canvas width="1277" height="930"></canvas>
<script>
'use strict';
var FastRandom = function()
{
this.getNextFloat = function()
{
return Math.random();
};
};
var ParticleWave = function()
{
var me = this;
var config = {
colors : {
background : 0x000000,
particle : 0x477cc2
},
alpha : {
particle : 1
},
particleCount : 30000
};
var TAU = Math.PI * 2;
var random = new FastRandom();
var particle;
var particleFillStyle;
var particleColorRGB = new Float32Array(3);
var smoothGradient;
var waterGradient;
var canvas;
var engine;
var width;
var height;
var particleWaveWalker = 0;
var randomWalker = 0;
var requestTick = function()
{
window.requestAnimationFrame(tick);
};
var initParticle = function()
{
particle = new Float32Array(config.particleCount * 2);
eachParticle(function(x, z) {
particle[x] = random.getNextFloat();
particle[z] = random.getNextFloat();
});
};
var initCanvas = function()
{
var cs = document.getElementsByTagName('canvas');
canvas = cs[0];
engine = canvas.getContext('2d');
width = window.innerWidth;
height = window.innerHeight;
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
};
var initParticleColor = function()
{
particleColorRGB[0] = config.colors.particle >> 16 & 0xff;
particleColorRGB[1] = config.colors.particle >> 8 & 0xff;
particleColorRGB[2] = config.colors.particle & 0xff;
particleFillStyle = 'rgb(' + particleColorRGB[0] + ',' + particleColorRGB[1] + ',' + particleColorRGB[2] + ')';
};
var initSmoothGradient = function()
{
smoothGradient = engine.createLinearGradient(
width / 2,
0,
width / 2,
height
);
smoothGradient.addColorStop(0.25, 'rgba(0, 0, 0, 0)');
smoothGradient.addColorStop(0.45, 'rgba(0, 0, 0, 0.9)');
smoothGradient.addColorStop(0.5 , 'rgba(0, 0, 0, 1)');
smoothGradient.addColorStop(0.55, 'rgba(0, 0, 0, 0.9)');
smoothGradient.addColorStop(0.75, 'rgba(0, 0, 0, 0)');
};
var initWaterGradient = function()
{
waterGradient = engine.createLinearGradient(
width / 2,
height / 2,
width / 2,
height
);
waterGradient.addColorStop(0, 'rgba(0, 0, 30, 0)');
waterGradient.addColorStop(1, 'rgba(30, 0, 60, 0.5)');
};
var init = function()
{
initCanvas();
initParticle();
initParticleColor();
initSmoothGradient();
initWaterGradient();
};
var eachParticle = function(cb)
{
for (var i = 0; i < particle.length; i += 2) {
cb(i, i + 1);
}
};
var renderParticle = function()
{
randomWalker += (Math.random() - 0.5) * 0.1;
particleWaveWalker += 0.03;
var radius = {
min : 1,
add : 5
};
var midY = height / 2;
var midX = width / 2;
var spreadX = 5;
var spreadZ = 0.0;
var modZ = 0.0;
var addX = 0;
var addY = 0;
var p = {
x : 0.0,
y : 0.0,
r : 0.0
};
engine.fillStyle = particleFillStyle;
// engine.beginPath();
var waveControl = 10;
for (var i = 0, xIndex, zIndex; i < particle.length; i += 2) {
xIndex = i;
zIndex = i + 1;
particle[zIndex] += 0.003;
if (particle[zIndex] > 1) {
particle[zIndex] = 0;
particle[xIndex] = random.getNextFloat();
}
if (particle[zIndex] < 0.3) {
continue;
}
modZ = Math.pow(particle[zIndex], 2);
spreadZ = 1 + (spreadX - 1) * modZ;
//bottom
addX = (0.5 - particle[xIndex]) * width * spreadZ;
addY = midY * modZ * (1 + 3 / waveControl);
p.x = midX + addX;
p.y = midY + addY;
p.r = radius.min + modZ * radius.add;
p.y += Math.sin(particle[xIndex] * 50 + particleWaveWalker) * addY / waveControl;
p.y += Math.cos(particle[zIndex] * 10 + particleWaveWalker) * addY / waveControl;
p.y -= Math.cos(particle[zIndex] + particle[xIndex] * 10 + particleWaveWalker) * addY / waveControl;
p.y -= Math.cos(particle[xIndex] * 50 + particleWaveWalker) * addY / waveControl;
p.y -= Math.sin(particle[zIndex] * 10 + particleWaveWalker) * addY / waveControl;
if (p.x < 0 || p.x > width) {
continue;
}
engine.fillRect(p.x, p.y, p.r, p.r);
// engine.moveTo(p.x, p.y);
// engine.arc(p.x, p.y, p.r, 0, TAU);
//top
// p.y = height - p.y;
//
// engine.moveTo(p.x, p.y);
// engine.arc(p.x, p.y, p.r, 0, TAU);
}
engine.fillStyle = particleFillStyle;
// engine.closePath();
// engine.fill();
};
var colorIntToHexString = function(color)
{
var s = color.toString(16);
return '0'.repeat(6 - s.length) + s;
};
var clear = function()
{
engine.fillStyle = '#' + colorIntToHexString(config.colors.background);
engine.fillRect(0, 0, width, height);
};
var drawSmooth = function()
{
engine.fillStyle = smoothGradient;
engine.fillRect(0, 0, width, height);
};
var drawWater = function()
{
engine.fillStyle = waterGradient;
engine.fillRect(0, height / 2, width, height / 2);
};
var tick = function()
{
clear();
drawWater();
renderParticle();
drawSmooth();
requestTick();
};
this.run = function()
{
init();
tick();
};
};
var pw = new ParticleWave();
pw.run();</script>
</body></html>

2949

被折叠的 条评论
为什么被折叠?



