目标是用 p5.js 在 2D 或 3D 网格上的每个点上用箭头(即尖端带有人字形的线段)来说明矢量场。原因是我看到很多生成艺术都在使用它,而且流场(?)看起来很酷,所以为什么不使用它们来描绘有或没有运动的物理矢量场。
我对 p5.js 一无所知,但快速在线搜索告诉我,我可以生成从左上角开始的位置向量,以及将原点连接到它们的终点或从一个位置向量到另一个:
function setup() {
createCanvas(500, 500);
}
function draw() {
background(0);
let vec1 = createVector(100,100);
let vec2 = createVector(30,150);
//First vector
strokeWeight(10);
stroke(250,250,250);
line(0,0,vec1.x,vec1.y);
//Second vector
strokeWeight(10);
stroke(250,0,250);
line(0,0,vec2.x,vec2.y);
//Difference vector
strokeWeight(5);
stroke(0,250,250);
line(vec1.x,vec1.y,vec2.x,vec2.y);
}
现在我想添加箭头并使它们更漂亮。理想的、长期的完美是 3Blue1Brown 中的 Material :
最佳答案
我找到了答案 here ,例如,它允许在两点(或两个位置向量的末端)之间绘制一个向量:
function setup() {
createCanvas(500, 500);
}
function draw() {
background(240);
let v0 = createVector(250,250); //Beginning point at center canvas.
let v1 = createVector(50,50); //Ending point at the tip of this positional vec.
drawArrow(v0, v1, 'red'); //Function that draws a red vector from vec0 to vec1.
}
// draw an arrow for a vector at a given base position
function drawArrow(base, vec, myColor) {
stroke(myColor);
strokeWeight(4);
fill(myColor);
translate(base.x, base.y); //Will transport the object line (below) to the tip of the positional vector v1
line(0, 0, vec.x, vec.y); //The line from the O to the tip of v1
rotate(vec.heading()); //Rotates the following triangle the angle of v1
let arrowSize = 7; // Determines size of the vector arrowhead (triangle).
translate(vec.mag() - arrowSize, 0); //Will translate a triangle below by the modulus of v1
triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
}
或者这里是从 Canvas 中心到鼠标尖端的矢量:
function setup() {
createCanvas(500, 500);
}
function draw() {
background(240);
let v0 = createVector(250,250);
let v1 = createVector(mouseX - 250, mouseY - 250);
drawArrow(v0, v1, 'red');
}
// draw an arrow for a vector at a given base position
function drawArrow(base, vec, myColor) {
stroke(myColor);
strokeWeight(4);
fill(myColor);
translate(base.x, base.y);
line(0, 0, vec.x, vec.y);
rotate(vec.heading());
let arrowSize = 7;
translate(vec.mag() - arrowSize, 0);
triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
}
这不仅仅是一个向量,而是一个实际的(随机)向量场,它是用上面的代码调整行 here 创建的丹尼尔希夫曼:
var inc = 0.1;
scl = 35;
var cols,rows;
function setup() {
createCanvas(500,500);
cols = floor(width/scl);
rows = floor(height/scl);
}
function draw() {
background(255);
var yoff = 0;
loadPixels();
for (var y = 0; y < rows; y++) {
var xoff = 0;
for (var x = 0; x < cols; x++) {
var index = (x + y * width)*4;
var angle = noise(xoff,yoff) * TWO_PI;
var v = p5.Vector.fromAngle(angle);
xoff +- inc;
fill('blue');
stroke('blue');
push();
translate(x*scl,y*scl);
rotate(v.heading());
line(0,0,0.5*scl,0);
let arrowSize = 7;
translate(0.5*scl - arrowSize, 0);
triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
pop();
}
yoff += inc;
}
}
不幸的是,左上角的原点使物理场在数学上的表达相当具有误导性,传达了场逆时针流动的直觉:
var inc = 0.1;
scl = 35;
var cols,rows;
function setup() {
createCanvas(500,500);
cols = floor(width/scl);
rows = floor(height/scl);
}
function draw() {
background(255);
var yoff = 0;
loadPixels();
for (var y = 0; y < rows; y++) {
var xoff = 0;
for (var x = 0; x < cols; x++) {
var index = (x + y * width)*4;
var angle = noise(xoff,yoff) * TWO_PI;
//var v = createVector(sin(x)+cos(y),sin(x)*cos(y));
var v = createVector(y,-x);
xoff +- inc;
fill('blue');
stroke('blue');
push();
translate(x*scl,y*scl);
rotate(v.heading());
line(0,0,0.5*scl,0);
let arrowSize = 7;
translate(0.5*scl - arrowSize, 0);
triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
pop();
}
yoff += inc;
}
}
最常见的具有负值和正值以及四个象限的笛卡尔坐标将显示该场实际上是如何顺时针流动的:
但这似乎有一个几乎简单的修复方法,即通过将计数器重置为从减去行(和列)数到加上行(和列)数,而不是从零开始。另外,需要翻转y轴增加值的方向,原点需要平移到 Canvas 中间 (height/2,height/2)
if square :
var inc = 0.1;
scl = 35;
var cols,rows;
function setup() {
createCanvas(500,500);
cols = floor(width/scl);
rows = floor(height/scl);
}
function draw() {
translate(height/2, height/2); //moves the origin to bottom left
scale(1, -1); //flips the y values so y increases "up"
background(255);
var yoff = 0;
loadPixels();
for (var y = -rows; y < rows; y++) {
var xoff = 0;
for (var x =- cols; x < cols; x++) {
var index = (x + y * width)*4;
var angle = noise(xoff,yoff) * TWO_PI;
//var v = createVector(sin(x)+cos(y),sin(x)*cos(y));
var v = createVector(y,-x);
xoff +- inc;
fill('blue');
stroke('blue');
push();
translate(x*scl,y*scl);
rotate(v.heading());
line(0,0,0.5*scl,0);
let arrowSize = 7;
translate(0.5*scl - arrowSize, 0);
triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
pop();
}
yoff += inc;
}
}
关于javascript - p5.js 上每个点都有经典箭头的静态矢量场,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70596353/