×

超酷炫的canvas动画:粒子飞轮

作者:andy0012019.07.01来源:Web前端之家浏览:9374评论:0
关键词:canvas粒子

canvas动画系列6【粒子旋涡】

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>粒子旋涡</title>
<style>
html, body { margin: 0px; width: 100%; height: 100%; overflow: hidden; background: #000; }

#canvas { position: absolute; width: 100%; height: 100%; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
function project3D(x, y, z, vars) {
    var p, d;
    x -= vars.camX;
    y -= vars.camY - 8;
    z -= vars.camZ;
    p = Math.atan2(x, z);
    d = Math.sqrt(x * x + z * z);
    x = Math.sin(p - vars.yaw) * d;
    z = Math.cos(p - vars.yaw) * d;
    p = Math.atan2(y, z);
    d = Math.sqrt(y * y + z * z);
    y = Math.sin(p - vars.pitch) * d;
    z = Math.cos(p - vars.pitch) * d;
    var rx1 = -1000;
    var ry1 = 1;
    var rx2 = 1000;
    var ry2 = 1;
    var rx3 = 0;
    var ry3 = 0;
    var rx4 = x;
    var ry4 = z;
    var uc = (ry4 - ry3) * (rx2 - rx1) - (rx4 - rx3) * (ry2 - ry1);
    var ua = ((rx4 - rx3) * (ry1 - ry3) - (ry4 - ry3) * (rx1 - rx3)) / uc;
    var ub = ((rx2 - rx1) * (ry1 - ry3) - (ry2 - ry1) * (rx1 - rx3)) / uc;
    if (!z) z = 0.000000001;
    if (ua > 0 && ua < 1 && ub > 0 && ub < 1) {
        return {
            x: vars.cx + (rx1 + ua * (rx2 - rx1)) * vars.scale,
            y: vars.cy + y / z * vars.scale,
            d: (x * x + y * y + z * z)
        }
    } else {
        return {
            d: -1
        }
    }
}
function elevation(x, y, z) {
    var dist = Math.sqrt(x * x + y * y + z * z);
    if (dist && z / dist >= -1 && z / dist <= 1) return Math.acos(z / dist);
    return 0.00000001
}
function rgb(col) {
    col += 0.000001;
    var r = parseInt((0.5 + Math.sin(col) * 0.5) * 16);
    var g = parseInt((0.5 + Math.cos(col) * 0.5) * 16);
    var b = parseInt((0.5 - Math.sin(col) * 0.5) * 16);
    return "#" + r.toString(16) + g.toString(16) + b.toString(16)
}
function interpolateColors(RGB1, RGB2, degree) {
    var w2 = degree;
    var w1 = 1 - w2;
    return [w1 * RGB1[0] + w2 * RGB2[0], w1 * RGB1[1] + w2 * RGB2[1], w1 * RGB1[2] + w2 * RGB2[2]]}
function rgbArray(col) {
    col += 0.000001;
    var r = parseInt((0.5 + Math.sin(col) * 0.5) * 256);
    var g = parseInt((0.5 + Math.cos(col) * 0.5) * 256);
    var b = parseInt((0.5 - Math.sin(col) * 0.5) * 256);
    return [r, g, b]}
function colorString(arr) {
    var r = parseInt(arr[0]);
    var g = parseInt(arr[1]);
    var b = parseInt(arr[2]);
    return "#" + ("0" + r.toString(16)).slice( - 2) + ("0" + g.toString(16)).slice( - 2) + ("0" + b.toString(16)).slice( - 2)
}
function process(vars) {
    if (vars.points.length < vars.initParticles) for (var i = 0; i < 5; ++i) spawnParticle(vars);
    var p, d, t;
    p = Math.atan2(vars.camX, vars.camZ);
    d = Math.sqrt(vars.camX * vars.camX + vars.camZ * vars.camZ);
    d -= Math.sin(vars.frameNo / 80) / 25;
    t = Math.cos(vars.frameNo / 300) / 165;
    vars.camX = Math.sin(p + t) * d;
    vars.camZ = Math.cos(p + t) * d;
    vars.camY = -Math.sin(vars.frameNo / 220) * 15;
    vars.yaw = Math.PI + p + t;
    vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
    var t;
    for (var i = 0; i < vars.points.length; ++i) {
        x = vars.points[i].x;
        y = vars.points[i].y;
        z = vars.points[i].z;
        d = Math.sqrt(x * x + z * z) / 1.0075;
        t = .1 / (1 + d * d / 5);
        p = Math.atan2(x, z) + t;
        vars.points[i].x = Math.sin(p) * d;
        vars.points[i].z = Math.cos(p) * d;
        vars.points[i].y += vars.points[i].vy * t * ((Math.sqrt(vars.distributionRadius) - d) * 2);
        if (vars.points[i].y > vars.vortexHeight / 2 || d < .25) {
            vars.points.splice(i, 1);
            spawnParticle(vars)
        }
    }
}
function drawFloor(vars) {
    var x, y, z, d, point, a;
    for (var i = -25; i <= 25; i += 1) {
        for (var j = -25; j <= 25; j += 1) {
            x = i * 2;
            z = j * 2;
            y = vars.floor;
            d = Math.sqrt(x * x + z * z);
            point = project3D(x, y - d * d / 85, z, vars);
            if (point.d != -1) {
                size = 1 + 15000 / (1 + point.d);
                a = 0.15 - Math.pow(d / 50, 4) * 0.15;
                if (a > 0) {
                    vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(d / 26 - vars.frameNo / 40), [0, 128, 32], .5 + Math.sin(d / 6 - vars.frameNo / 8) / 2));
                    vars.ctx.globalAlpha = a;
                    vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size)
                }
            }
        }
    }
    vars.ctx.fillStyle = "#82f";
    for (var i = -25; i <= 25; i += 1) {
        for (var j = -25; j <= 25; j += 1) {
            x = i * 2;
            z = j * 2;
            y = -vars.floor;
            d = Math.sqrt(x * x + z * z);
            point = project3D(x, y + d * d / 85, z, vars);
            if (point.d != -1) {
                size = 1 + 15000 / (1 + point.d);
                a = 0.15 - Math.pow(d / 50, 4) * 0.15;
                if (a > 0) {
                    vars.ctx.fillStyle = colorString(interpolateColors(rgbArray( - d / 26 - vars.frameNo / 40), [32, 0, 128], .5 + Math.sin( - d / 6 - vars.frameNo / 8) / 2));
                    vars.ctx.globalAlpha = a;
                    vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size)
                }
            }
        }
    }
}
function sortFunction(a, b) {
    return b.dist - a.dist
}
function draw(vars) {
    vars.ctx.globalAlpha = .15;
    vars.ctx.fillStyle = "#000";
    vars.ctx.fillRect(0, 0, canvas.width, canvas.height);
    drawFloor(vars);
    var point, x, y, z, a;
    for (var i = 0; i < vars.points.length; ++i) {
        x = vars.points[i].x;
        y = vars.points[i].y;
        z = vars.points[i].z;
        point = project3D(x, y, z, vars);
        if (point.d != -1) {
            vars.points[i].dist = point.d;
            size = 1 + vars.points[i].radius / (1 + point.d);
            d = Math.abs(vars.points[i].y);
            a = .8 - Math.pow(d / (vars.vortexHeight / 2), 1000) * .8;
            vars.ctx.globalAlpha = a >= 0 && a <= 1 ? a: 0;
            vars.ctx.fillStyle = rgb(vars.points[i].color);
            if (point.x > -1 && point.x < vars.canvas.width && point.y > -1 && point.y < vars.canvas.height) vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size)
        }
    }
    vars.points.sort(sortFunction)
}
function spawnParticle(vars) {
    var p, ls;
    pt = {};
    p = Math.PI * 2 * Math.random();
    ls = Math.sqrt(Math.random() * vars.distributionRadius);
    pt.x = Math.sin(p) * ls;
    pt.y = -vars.vortexHeight / 2;
    pt.vy = vars.initV / 20 + Math.random() * vars.initV;
    pt.z = Math.cos(p) * ls;
    pt.radius = 200 + 800 * Math.random();
    pt.color = pt.radius / 1000 + vars.frameNo / 250;
    vars.points.push(pt)
}
function frame(vars) {
    if (vars === undefined) {
        var vars = {};
        vars.canvas = document.querySelector("canvas");
        vars.ctx = vars.canvas.getContext("2d");
        vars.canvas.width = document.body.clientWidth;
        vars.canvas.height = document.body.clientHeight;
        window.addEventListener("resize",
        function() {
            vars.canvas.width = document.body.clientWidth;
            vars.canvas.height = document.body.clientHeight;
            vars.cx = vars.canvas.width / 2;
            vars.cy = vars.canvas.height / 2
        },
        true);
        vars.frameNo = 0;
        vars.camX = 0;
        vars.camY = 0;
        vars.camZ = -14;
        vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2;
        vars.yaw = 0;
        vars.cx = vars.canvas.width / 2;
        vars.cy = vars.canvas.height / 2;
        vars.bounding = 10;
        vars.scale = 500;
        vars.floor = 26.5;
        vars.points = [];
        vars.initParticles = 1000;
        vars.initV = .01;
        vars.distributionRadius = 800;
        vars.vortexHeight = 25
    }
    vars.frameNo++;
    requestAnimationFrame(function() {
        frame(vars)
    });
    process(vars);
    draw(vars)
}
frame();</script>
</body>
</html>

去预览下效果吧。

您的支持是我们创作的动力!
温馨提示:本文作者系 ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://jiangweishan.com/article/can823049823etipoeit.html

网友评论文明上网理性发言 已有0人参与

发表评论: