Есть вот такая абстракция
знаю что через canvas такое анимируется, но не силен в данной области, может кто видел или знает как анимировать?
Примерная анимация на Three.js
var planeVertShader = `
#define PI 3.1415926
uniform float time;
uniform float amplitude;
uniform float waveLength;
uniform vec3 pos;
uniform float timeSpeed;
uniform float planeHeight;
uniform float initRotation;
uniform float speedRotation;
varying vec3 varPos;
void main() {
vec3 p = position + pos + vec3(0., .1, 0.);
float wLength = 1. / waveLength;
float heightNormal = position.y / planeHeight;
float oneRound = heightNormal * PI * 4.;
//вращение
p.y += sin(p.x * wLength + time) * cos(p.z * wLength + time) * amplitude;
p.x = cos(-time * speedRotation + oneRound + initRotation) * position.x;
p.z = sin(-time * speedRotation + oneRound + initRotation) * position.x;
//скручивание
p.x += cos(-time * speedRotation + oneRound) * heightNormal * 5.;
p.z += sin(-time * speedRotation + oneRound) * heightNormal * 5.;
p += pos + vec3(0., .1, 0.);
varPos = position;
vec4 mvPosition = modelViewMatrix * vec4( p, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
`;
var planeFragShader = `
void main() {
gl_FragColor = vec4(0.366,0.048,0.515,1.000);
}
`;
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 25, 150);
camera.rotation.set(0, 0, 1.57);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0x000000);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', function () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}, false);
// plane
var planes = [];
var planeHeight = 125;
var planeWidth = 15;
var planeGeom = new THREE.PlaneBufferGeometry(planeWidth, planeHeight, 15, 100);
planeGeom.translate(4, 0, 0);
for (let i = 0; i < 2; i++) {
let pos = new THREE.Vector3(0, 10, 110);
let plane = new THREE.LineSegments(planeGeom, new THREE.ShaderMaterial({
uniforms: {
time: {
value: 0
},
amplitude: {
value: 5
},
waveLength: {
value: Math.PI * 5
},
pos: {
value: pos
},
timeSpeed: {
value: THREE.Math.randFloat(Math.PI * .5, Math.PI)
},
planeHeight: {
value: planeHeight
},
initRotation: {
value: THREE.Math.randFloat(0, Math.PI)
},
speedRotation: {
value: THREE.Math.randFloat(Math.PI * 0.5, Math.PI)
}
},
vertexShader: planeVertShader,
fragmentShader: planeFragShader
}));
scene.add(plane);
planes.push(plane)
}
var clock = new THREE.Clock();
var t = 0;
var delta = 0;
render();
function render() {
requestAnimationFrame(render);
delta = clock.getDelta();
t += delta;
planes.forEach(sw => {
sw.material.uniforms.time.value = t
});
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>
<div></div>
WebGL. Поверхность задана при помощи signed distance
, на нее наложен математический шум, который сдвигается со временем. Поверхность находится при помощи raymarch
, все это дело вычисляется во фрагментном шейдере.
let canvas = document.querySelector('canvas');
let gl = canvas.getContext('webgl');
let pid = gl.createProgram();
shader(`
attribute vec2 coords;
void main(void) {
gl_Position = vec4(coords.xy, 0.0, 1.0);
}
`, gl.VERTEX_SHADER);
shader(`
precision highp float;
uniform vec4 mr;
uniform float time;
#define rot(a) mat2(cos(a),-sin(a),sin(a),cos(a))
#define hash31(p) fract(sin(dot(p,vec3(127.1,311.7, 74.7)))*43758.5453123)
float noise3(vec3 p) {
vec3 i = floor(p);
vec3 f = fract(p); f = f*f*(3.-2.*f);
return mix( mix( mix(hash31(i+vec3(0,0,0)),
hash31(i+vec3(1,0,0)),f.x),
mix(hash31(i+vec3(0,1,0)),
hash31(i+vec3(1,1,0)),f.x), f.y),
mix( mix(hash31(i+vec3(0,0,1)),
hash31(i+vec3(1,0,1)),f.x),
mix(hash31(i+vec3(0,1,1)),
hash31(i+vec3(1,1,1)),f.x), f.y), f.z);
}
float fbm3(vec3 p) {
float v = 0., a = .5;
mat2 R = rot(.37);
for (int i = 0; i < 2; i++) {
p *= 2.;
a /= 2.;
p.xy *= R;
p.yz *= R;
v += a * noise3(p);
}
return v;
}
float map( in vec3 pos ){
return pos.y + fbm3(vec3(pos.x+time,pos.yz));
}
float rayMarch( in vec3 ro, in vec3 rd, float tmax ){
float t = 0.0;
float h = (1.0-ro.y)/rd.y;
for( int i=0; i<10; i++ ){
vec3 pos = ro + t*rd;
float h = map( pos );
if( h<0.001 || t>tmax ) break;
t += h;
}
return t;
}
vec3 render( in vec3 ro, in vec3 rd ) {
vec3 col = vec3(0.);
float t = rayMarch( ro, rd, 10. );
vec3 pos = ro + t*rd;
vec2 scp = sin(23.*pos.xz);
col += 2.0*exp(-5.0*abs(scp.x));
col += 2.0*exp(-5.0*abs(scp.y));
return col*0.5*exp(-0.1*t*t);
}
mat3 setCamera( in vec3 ro, in vec3 rt, in float cr ) {
vec3 cw = normalize(rt-ro);
vec3 cp = vec3(sin(cr), cos(cr),0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = normalize( cross(cu,cw) );
return mat3( cu, cv, -cw );
}
void main(void) {
vec2 uv = gl_FragCoord.xy/mr.zw;
vec2 p = uv-0.5;
float an = time*0.5 + 6.0*mr.x/mr.z;
vec3 ro = vec3( 2.0*cos(an), 1.0, 2.0*sin(an) );
vec3 rt = vec3( 1.0, 0.0, 0.0 );
mat3 cam = setCamera( ro, rt, 0.35 );
vec3 rd = normalize( cam * vec3( p, -1.0) );
vec3 c = render( ro, rd )*vec3( 0.3, 0.4, 0.8 );
gl_FragColor = vec4(c, 1.0 );
}
`, gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);
let array = new Float32Array([-1, 3, -1, -1, 3, -1]);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
let coords = gl.getAttribLocation(pid, "coords");
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);
let mr = gl.getUniformLocation(pid, 'mr');
let time = gl.getUniformLocation(pid, 'time');
let x = 0, y = 0;
let changeCenter = e => {
e = e.touches ? e.touches[0] : e;
let z = window.getComputedStyle(canvas).zoom || 1;
let d = document.documentElement;
x = (e.clientX + d.scrollLeft - canvas.offsetLeft*z) / z;
y = (e.clientY + d.scrollTop - canvas.offsetTop*z) / z
}
window.addEventListener('mousemove', e => changeCenter(e));
window.addEventListener('touchmove', e => changeCenter(e));
window.addEventListener('resize', resize);
resize();
function draw(t) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 0);
gl.uniform4f(mr, x, y, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.uniform1f(time, t/1000);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(draw)
}
function shader(src, type) {
let sid = gl.createShader(type);
gl.shaderSource(sid, src);
gl.compileShader(sid);
var message = gl.getShaderInfoLog(sid);
gl.attachShader(pid, sid);
if (message.length > 0) {
console.log(src.split('\n').map(function (str, i) {
return ("" + (1 + i)).padStart(4, "0") + ": " + str
}).join('\n'));
throw message;
}
}
function resize(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
draw();
}
<body style="margin:0; overflow:hidden"><canvas/></body>
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Может есть какие то идеи, почему unshift добавляем в конец массива, а не в начало? И сортировка что то не помогает