动画处理中的正弦波 [英] animating sine waves in processing
问题描述
如何使以下代码中的正弦线动画化以沿 y 轴移动,以某种方式看起来更像移动的水波?
-如果您取出速度和加速度代码,您将看到我尝试使用的内容
float scaleVal = 6.0;浮动角度公司 = 0.19;浮动速度=0.0;浮动加速度=0.01;无效设置(){大小(750,750);行程(255);}无效绘制(){背景 (0);浮动角度=0.0;for (int offset = -10; offset
尝试使用 sin()
来更改 y 位置而不是 x.x 位置可以简单地增加.
数学可能令人生畏,但一旦掌握了它,它就会变得有趣.想象一下在笛卡尔坐标系中绕半径为 1.0 的圆(0 为中心,x 和 y 向右和向下增加,向左和向上减少):
- 假设您从顶部开始,即最高值,即圆的长度半径 (1.0).
- 当你减小角度时,x 向左移动,但 y 将向中心移动(0.0)
- 那么 x 会随着它靠近中心而增加,而 y 会下降到圆的底部 (-1.0)
- 然后x会一直增加直到到达圆的右边缘,y值会增加并到达垂直中心(0.0)
- 最后 x 将减小直到到达水平中心,y 将增加并返回到圆的顶部 (1.0)
这张图很好地解释了它:
本质上它就像一个转换器:你插入一个从 0 到 360 度的角度或 TWO_PI
弧度(因为 sin 与弧度的角度一起工作),你会得到一个介于 -1.0 和 1.0 之间的值.
如果要绘制正弦波,必须绘制多个点:
- x 位置会直接增加值
- y 位置会增加角度,但使用
sin()
函数的结果来获得一个向上和向下的值.
最后要做的是将 sin()
函数的结果乘以一个更大的数字,以将正弦波(从 -1.0 到 1.0)缩放到更适合屏幕的大小.
这是一个快速评论的演示,您可以使用鼠标位置来玩:
function setup(){创建画布(640,100);}函数绘制(){背景(255);var numberOfPoints = 1+(mouseX/2);//这些点间隔多久var widthPerPoint = 宽度/numberOfPoints;//从一点到另一点的角度会改变多少var anglePerPoint = TWO_PI/numberOfPoints;var waveHeight = 25;for(var i = 0; i
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
它的要点是这一行:
var y = sin(anglePerPoint * i) * waveHeight;
可以分解为:
//增加角度var incrementedAngle = anglePerPoint * i;//计算正弦(-1.0,1.0)var sine = sin(增量角度);//缩放正弦结果var waveY = sine * waveHeight;
一旦您可以绘制静态正弦波,就很容易制作动画:为每个点的角度增量添加一个递增值.这会增加角度并基本上为您绕圆 (TWO_PI
).
您可以创建自己的变量以按您自己的速率增加或您可以轻松地使用基于时间(millis()
)或帧(frameCount
)的递增值,您可以按比例缩小(除以大数......或更好)乘以小数):
function setup(){创建画布(640,100);}函数绘制(){背景(255);var numberOfPoints = 1+(mouseX/2);//这些点间隔多久var widthPerPoint = 宽度/numberOfPoints;//从一点到另一点的角度会改变多少var anglePerPoint = TWO_PI/numberOfPoints;var waveHeight = 25;for(var i = 0; i
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
希望上面的动画和简单的演示有助于说明这一点.更简单地说,这有点像一种错觉:您绘制的点只能上下移动,但每个点都使用沿圆递增的角度.
看看
(我建议查看整个 PopTech 演讲:它很鼓舞人心)
您还应该查看处理正弦波示例.
这是一个更复杂的将概念封装在一个可重用函数中以绘制多个波以暗示大气视角的方法:
int numWaves = 5;无效设置(){大小(400,400);noStroke();}无效绘制(){背景(255);for(int i = 0 ; i
你也可以在下面运行:
var numWaves = 5;功能设置(){创建画布(400,400);noStroke();}函数绘制(){背景(255);for(var i = 0 ; i
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
在渲染方面,我唯一的其他建议是使用 beginShape().不必担心在何处绘制每条线,只需在 beginShape()
/ 之间传递一堆点(通过
调用并让 Processing 为您连接点.vertex(x,y)
)endShape()
how do I animate the sin lines in the following code to move along the y-axis, to somehow look more like moving water waves?
-if you take out the velocity and acceleration codes you will see what I was trying to work with
float scaleVal = 6.0;
float angleInc = 0.19;
float velocity=0.0;
float acceleration=0.01;
void setup(){
size(750,750);
stroke(255);
}
void draw(){
background (0);
float angle=0.0;
for (int offset = -10; offset < width+10; offset += 10) {
for (int y = 1; y <= height; y += 3) {
float x = offset + (sin(angle) * scaleVal);
line(x, y, x, y+2);
angle += angleInc;
velocity += acceleration;
y += velocity;
}
angle += PI;
}
}
Try using sin()
to change the y position instead of x.
The x position can simply increment.
The math may be daunting, but it gets fun once you get the hang of it. Imagine going around a circle with the radius of 1.0 in a cartesian coordinate system (0 is centre , x and y increase to the right and down and decrease towards left and top):
- Let's say you start at the top, the highest value, the length radius of your circle (1.0).
- As you decrease the angle, the x move to the left, but the y will go towards the centre( 0.0 )
- then x will increase as it gets close to the centre and y will drop to bottom of the circle (-1.0)
- then x will keep increasing until it reaches the right edge of the circle and the y value will increase and reach the vertical centre (0.0)
- finally the x will decrease until it reaches the horizontal centre and y will increase and reach back to the top of the circle (1.0)
This image explains it pretty well:
Essentially it's like a converter: you plug in an angle from 0 to 360 degrees or TWO_PI
radians (as sin works with angles in radians) and you get back a value between -1.0 and 1.0.
If you want to draw a sine wave, you have to draw multiple points:
- the x position will increase value directly
- the y position will increase the angle, but use the result of the
sin()
function to obtain a value that goes up and down.
The last thing to do is multiple the result of the sin()
function by a larger number to essentially scale the sine wave (from -1.0 to 1.0) to a size more appropate for the screen.
Here's a quick commented demo you can use the mouse position to play with:
function setup(){
createCanvas(640,100);
}
function draw(){
background(255);
var numberOfPoints = 1+(mouseX/2);
//how often apart will the points be
var widthPerPoint = width / numberOfPoints;
//how much will the angle change from one point to another
var anglePerPoint = TWO_PI/numberOfPoints;
var waveHeight = 25;
for(var i = 0; i < numberOfPoints; i++){
var x = i * widthPerPoint;
var y = sin(anglePerPoint * i) * waveHeight;
ellipse(x,50 + y,5,5);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
The gist of it is this line:
var y = sin(anglePerPoint * i) * waveHeight;
which can be broken down to:
//increment the angle
var incrementedAngle = anglePerPoint * i;
//compute sine (-1.0,1.0)
var sine = sin(incrementedAngle);
//scale sine result
var waveY = sine * waveHeight;
Once you can draw a static sine wave, it's pretty easy to animate: to the angle increment at each point you add an increasing value. This increases the angle and essentially goes around the circle (TWO_PI
) for you.
You can create your own variable to increase at your own rate or you
can easily use an increasing value based on time(millis()
) or frame(frameCount
) which you can scale down (divide by a large number...or better yet multiple by a small fractional number):
function setup(){
createCanvas(640,100);
}
function draw(){
background(255);
var numberOfPoints = 1+(mouseX/2);
//how often apart will the points be
var widthPerPoint = width / numberOfPoints;
//how much will the angle change from one point to another
var anglePerPoint = TWO_PI/numberOfPoints;
var waveHeight = 25;
for(var i = 0; i < numberOfPoints; i++){
var x = i * widthPerPoint;
var y = sin(anglePerPoint * i + frameCount * 0.01) * waveHeight;
ellipse(x,50 + y,5,5);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
Hopefully the animation and simple demos above help illustrate the point. In even simpler terms, it's a bit of an illustion: you draw points that only move up and down, but each point use an increasing angle along the circle.
Have a look at Reuben Margolin's kinectic sculpture system demo:
(I recommend checking out the whole PopTech talk: it's inspiring)
You should have a look at the Processing SineWave example as well.
Here's a more complex encapsulating the notions in a resuable function to draw multiple waves to hint at an atmospheric perspective:
int numWaves = 5;
void setup(){
size(400,400);
noStroke();
}
void draw(){
background(255);
for(int i = 0 ; i < numWaves; i++){
fill(30,120,180,map(i,0,numWaves-1,192,32));
drawSineWave(HALF_PI,0.00025 * (i+1),50 + (10 * i),8,width,mouseY);
}
fill(255);
text("drag mouse x to change number of waves",10,height-10);
}
/*
* radians - how often does the wave cycle (larges values = more peaks)
* speed - how fast is the wave moving
* amplitude - how high is the wave (from centre point)
* detail - how many points are used to draw the wave (small=angled, many = smooth)
* y - y centre of the wave
*/
void drawSineWave(float radians,float speed,float amplitude,int detail,float size,float y){
beginShape();
vertex(0,height);//fix to bottom
//compute the distance between each point
float xoffset = size / detail;
//compute angle offset between each point
float angleIncrement = radians / detail;
//for each point
for(int i = 0 ; i <= detail; i++){
//compute x position
float px = xoffset * i;
//use sine function compute y
//millis() * speed is like an ever increasing angle
//to which we add the angle increment for each point (so the the angle changes as we traverse x
//the result of sine is a value between -1.0 and 1.0 which we multiply to the amplitude (height of the wave)
//finally add the y offset
float py = y + (sin((millis() * speed) + angleIncrement * i) * amplitude);
//add the point
vertex(px,py);
}
vertex(size,height);//fix to bottom
endShape();
}
void mouseDragged(){
numWaves = 1+(int)mouseX/40;
}
Which you can also run bellow:
var numWaves = 5;
function setup(){
createCanvas(400,400);
noStroke();
}
function draw(){
background(255);
for(var i = 0 ; i < numWaves; i++){
fill(30,120,180,map(i,0,numWaves-1,192,32));
drawSineWave(HALF_PI,0.00025 * (i+1),50 + (10 * i),8,width,mouseY);
}
fill(255);
text("drag mouse x to change number of waves",10,height-10);
}
/*
* radians - how often does the wave cycle (larges values = more peaks)
* speed - how fast is the wave moving
* amplitude - how high is the wave (from centre point)
* detail - how many points are used to draw the wave (small=angled, many = smooth)
* y - y centre of the wave
*/
function drawSineWave(radians,speed,amplitude,detail,size,y){
beginShape();
vertex(0,height);//fix to bottom
//compute the distance between each point
var xoffset = size / detail;
var angleIncrement = radians / detail;
for(var i = 0 ; i <= detail; i++){
var px = xoffset * i;
var py = y + (sin((millis() * speed) + angleIncrement * i) * amplitude);
vertex(px,py);
}
vertex(size,height);//fix to bottom
endShape();
}
function mouseDragged(){
numWaves = ceil(mouseX/40);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
The only other suggestion I have, in terms of rendering, it to have play with beginShape(). Rather than having to worry about where to draw each line, simply pass a bunch of points(via vertex(x,y)
) in between beginShape()
/endShape()
calls and let Processing connect the dots for you.
这篇关于动画处理中的正弦波的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!