gpt4 book ai didi

javascript - 在 Canvas 中制作波浪并制作动画

转载 作者:太空狗 更新时间:2023-10-29 16:48:50 25 4
gpt4 key购买 nike

我正在寻找一种在 Canvas 中设计的形状中创建波浪的方法。经过大量研究,我发现了一些非常接近我想要的东西:

var c = document.getElementById('c'),
ctx = c.getContext('2d'),
cw = c.width = window.innerWidth,
ch = c.height = window.innerHeight,
points = [],
tick = 0,
opt = {
count: 5,
range: {
x: 20,
y: 80
},
duration: {
min: 20,
max: 40
},
thickness: 10,
strokeColor: '#444',
level: .35,
curved: true
},
rand = function(min, max) {
return Math.floor((Math.random() * (max - min + 1)) + min);
},
ease = function(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
return -c / 2 * ((--t) * (t - 2) - 1) + b;
};

ctx.lineJoin = 'round';
ctx.lineWidth = opt.thickness;
ctx.strokeStyle = opt.strokeColor;

var Point = function(config) {
this.anchorX = config.x;
this.anchorY = config.y;
this.x = config.x;
this.y = config.y;
this.setTarget();
};

Point.prototype.setTarget = function() {
this.initialX = this.x;
this.initialY = this.y;
this.targetX = this.anchorX + rand(0, opt.range.x * 2) - opt.range.x;
this.targetY = this.anchorY + rand(0, opt.range.y * 2) - opt.range.y;
this.tick = 0;
this.duration = rand(opt.duration.min, opt.duration.max);
}

Point.prototype.update = function() {
var dx = this.targetX - this.x;
var dy = this.targetY - this.y;
var dist = Math.sqrt(dx * dx + dy * dy);

if (Math.abs(dist) <= 0) {
this.setTarget();
} else {
var t = this.tick;
var b = this.initialY;
var c = this.targetY - this.initialY;
var d = this.duration;
this.y = ease(t, b, c, d);

b = this.initialX;
c = this.targetX - this.initialX;
d = this.duration;
this.x = ease(t, b, c, d);

this.tick++;
}
};

Point.prototype.render = function() {
ctx.beginPath();
ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false);
ctx.fillStyle = '#000';
ctx.fill();
};

var updatePoints = function() {
var i = points.length;
while (i--) {
points[i].update();
}
};

var renderPoints = function() {
var i = points.length;
while (i--) {
points[i].render();
}
};

var renderShape = function() {
ctx.beginPath();
var pointCount = points.length;
ctx.moveTo(points[0].x, points[0].y);
var i;
for (i = 0; i < pointCount - 1; i++) {
var c = (points[i].x + points[i + 1].x) / 2;
var d = (points[i].y + points[i + 1].y) / 2;
ctx.quadraticCurveTo(points[i].x, points[i].y, c, d);
}
ctx.lineTo(-opt.range.x - opt.thickness, ch + opt.thickness);
ctx.lineTo(cw + opt.range.x + opt.thickness, ch + opt.thickness);
ctx.closePath();
ctx.fillStyle = 'hsl(' + (tick / 2) + ', 80%, 60%)';
ctx.fill();
ctx.stroke();
};

var clear = function() {
ctx.clearRect(0, 0, cw, ch);
};

var loop = function() {
window.requestAnimFrame(loop, c);
tick++;
clear();
updatePoints();
renderShape();
//renderPoints();
};

var i = opt.count + 2;
var spacing = (cw + (opt.range.x * 2)) / (opt.count - 1);
while (i--) {
points.push(new Point({
x: (spacing * (i - 1)) - opt.range.x,
y: ch - (ch * opt.level)
}));
}

window.requestAnimFrame = function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(a) {
window.setTimeout(a, 1E3 / 60)
}
}();

loop();
canvas {
display: block;
}
<canvas id="c"></canvas>

http://codepen.io/jackrugile/pen/BvLHg

问题是波浪的运动看起来有点不真实。我想保留这种随机运动的概念,而不是通过从左向右移动来重复自己的形状,但是如果我找到一种方法来创建“逼真的”水运​​动(良好的流体动力学,碰撞这个波浪及其容器的边缘(自定义形状))。

我想我问了很多但是......一小部分研究可能会有所帮助:)

最佳答案

干扰

您可以使用干涉来制作更逼真的波浪。

  • 有一个大浪​​(涌浪)以大 Action 缓慢运行
  • 再运行一个或两个较小的正弦波(振荡器)
  • 全部具有随机振幅
  • 使用平均值水平混合波并计算各个点
  • 使用基数样条绘制结果(或者如果分辨率很高,您可以只在点之间绘制简单的线)。

使用各种参数,以便您可以实时调整它以找到一个好的组合。

您还可以添加振荡器来表示 z 轴,以使其更加逼真,以防您想要将波分层以制作伪 3D 波。

例子

我不能给你波浪碰撞、流体动力学——这对 SO 来说有点太宽泛了,但我可以给你一个流体波的例子(因为你有每个部分的点,你可以用它来进行碰撞检测) .

示例是创建一个振荡器对象,您可以在该对象上设置各种设置,例如振幅、旋转速度(相位)等。

然后有一个混频器功能,可以混合您使用的这些振荡器的结果。

Live demo here ( full-screen version here )

Demo snapshot

此演示中的振荡器对象如下所示:

function osc() {

/// various settings
this.variation = 0.4; /// how much variation between random and max
this.max = 100; /// max amplitude (radius)
this.speed = 0.02; /// rotation speed (for radians)

var me = this, /// keep reference to 'this' (getMax)
a = 0, /// current angle
max = getMax(); /// create a temp. current max

/// this will be called by mixer
this.getAmp = function() {

a += this.speed; /// add to rotation angle

if (a >= 2.0) { /// at break, reset (see note)
a = 0;
max = getMax();
}

/// calculate y position
return max * Math.sin(a * Math.PI) + this.horizon;
}

function getMax() {
return Math.random() * me.max * me.variation +
me.max * (1 - me.variation);
}

return this;
}

这会为我们完成所有设置和计算,我们需要做的就是调用 getAmp() 为每一帧获取一个新值。

我们可以使用“混合器”代替手动操作。这个混音器允许我们添加任意数量的振荡器到混音中:

function mixer() {

var d = arguments.length, /// number of arguments
i = d, /// initialize counter
sum = 0; /// sum of y-points

if (d < 1) return horizon; /// if none, return

while(i--) sum += arguments[i].getAmp(); /// call getAmp and sum

return sum / d + horizon; /// get average and add horizon
}

将其放入带有点记录器的循环中,点记录器会在一个方向上移动点,从而创建一个看起来很流畅的波浪。

上面的演示使用了三个振荡器。 (在这方面的一个技巧是保持旋转速度低于大浪,否则你会在上面遇到小颠簸。)

注意:我创建一个新的随机最大值的方式并不是最好的方式,因为我使用了一个断点(但对于演示目的来说很简单)。您可以用更好的东西代替它。

关于javascript - 在 Canvas 中制作波浪并制作动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19787775/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com