const W = 800;
const H = 800;
const GRID_SIZE = 150;
const GRID_R = 3;
const NUM_LINE = 15;
let COLS;
let ROWS;
let palette = [];
let gridPoints = [];
let innerAngles = [];
function setup() {
createCanvas(W, H, WEBGL);
palette = colorArray[2].colors;
background(palette[0]);
frameRate(60);
COLS = floor(W / GRID_SIZE) + 1;
ROWS = floor(H / GRID_SIZE) + 1;
}
function draw() {
orbitControl();
background(palette[0]);
for (let i = 0; i < COLS; i++) {
gridPoints[i] = [];
for (let j = 0; j < ROWS; j++) {
let freq = 0.1;
push();
let angle = frameCount * noise(i * 0.1, j * 0.1) * freq;
let x = GRID_SIZE * i + (cos(angle) * GRID_SIZE) / GRID_R;
let y = GRID_SIZE * j + (sin(angle) * GRID_SIZE) / GRID_R;
let z = (sin(angle + i + j) * GRID_SIZE) / GRID_R;
gridPoints[i][j] = createVector(x, y, z);
pop();
}
}
for (let i = 0; i < COLS - 1; i++) {
innerAngles[i] = [];
for (let j = 0; j < ROWS - 1; j++) {
let P1 = gridPoints[i][j];
let P2 = gridPoints[i][j + 1];
let P3 = gridPoints[i + 1][j + 1];
let P4 = gridPoints[i + 1][j];
innerAngles[i][j] = {
points: [P1, P2, P3, P4],
angles: calculateAngles(P1, P2, P3, P4),
};
}
}
// 壁の位置
for (let n = 0; n < 5; n++) {
push();
if (n == 0) {
translate(-W / 2, -H / 2, 0);
rotateY(TAU / 4);
} else if (n == 1) {
translate(-W / 2, -H / 2, 0);
rotateY(TAU / 4);
rotateX(TAU / 4);
} else if (n == 2) {
translate(W / 2, -H / 2, 0);
rotateY(TAU / 4);
} else if (n == 3) {
translate(-W / 2, H / 2, 0);
rotateX(-TAU / 4);
} else if (n == 4) {
translate(-W / 2, -H / 2, -W);
}
//vertex描画
push();
stroke(palette[4]);
noFill();
for (let i = 0; i < COLS - 1; i++) {
for (let j = 0; j < ROWS - 1; j++) {
beginShape();
for (let k = 0; k < 4; k++) {
// 元の頂点座標
let p = innerAngles[i][j].points[k];
vertex(p.x, p.y, p.z);
}
endShape(CLOSE);
for (let k = 0; k < 4; k++) {
drawLine(i, j, k + 1);
}
}
}
pop();
pop();
}
// noLoop();
}
function calculateAngles(p1, p2, p3, p4) {
let angles = [];
// P1: (P1 -> P4) と (P1 -> P2) の角度
let V_P1_to_P4 = p5.Vector.sub(p4, p1);
let V_P1_to_P2 = p5.Vector.sub(p2, p1);
angles[0] = V_P1_to_P4.angleBetween(V_P1_to_P2);
// P2: (P2 -> P1) と (P2 -> P3) の角度
let V_P2_to_P1 = p5.Vector.sub(p1, p2);
let V_P2_to_P3 = p5.Vector.sub(p3, p2);
angles[1] = V_P2_to_P1.angleBetween(V_P2_to_P3);
// P3: (P3 -> P2) と (P3 -> P4) の角度
let V_P3_to_P2 = p5.Vector.sub(p2, p3);
let V_P3_to_P4 = p5.Vector.sub(p4, p3);
angles[2] = V_P3_to_P2.angleBetween(V_P3_to_P4);
// P4: (P4 -> P3) と (P4 -> P1) の角度
let V_P4_to_P3 = p5.Vector.sub(p3, p4);
let V_P4_to_P1 = p5.Vector.sub(p1, p4);
angles[3] = V_P4_to_P3.angleBetween(V_P4_to_P1);
return angles; // 180以上になることを考慮してない angles.map((a) => abs(a))
}
function drawLine(i, j, index) {
let p = innerAngles[i][j];
let pp = p.points[index - 1];
let pa = p.angles[index - 1];
push();
// 60度以下でラインを引く
const ninetyDegrees = TAU / 6;
if (pa <= ninetyDegrees) {
const vertices = p.points;
push();
const prevIdx = (index + 2) % 4;
const nextIdx = index % 4;
let subV1 = p5.Vector.sub(vertices[prevIdx], pp);
let subV2 = p5.Vector.sub(vertices[nextIdx], pp);
translate(pp.x, pp.y, pp.z);
for (let i = 0; i < NUM_LINE; i++) {
let direction1 = subV1
.copy()
.normalize()
.mult(10 * (i + 1));
let direction2 = subV2
.copy()
.normalize()
.mult(10 * (i + 1));
// directionの長さをsubVまで制限
let maxLen1 = subV1.mag();
let maxLen2 = subV2.mag();
if (direction1.mag() > maxLen1) {
direction1.setMag(maxLen1);
}
if (direction2.mag() > maxLen2) {
direction2.setMag(maxLen2);
}
line(
direction1.x,
direction1.y,
direction1.z,
direction2.x,
direction2.y,
direction2.z
);
}
pop();
}
// デバック用
// push();
// translate(pp.x, pp.y - index * 15, 0);
// text(`P${index}`, 0, 0);
// pop();
// push();
// translate(pp.x + 25, pp.y - index * 15, 0);
// text(`${degrees(pa).toFixed(1)}°`, 0, 0);
// pop();
pop();
}
const colorArray = [
{
id: 0,
colors: ["#253276", "#dfdad3", "#ffffff", "#000000"],
},
{
id: 1,
colors: ["#2E5400", "#dfdad3", "#ffffff", "#000000"],
},
{
id: 2,
colors: ["#253276", "#f9d3cc", "#f07433", "#437800", "#dfdad3"],
},
];