iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0
Modern Web

p5.js 的環形藝術系列 第 9

[Day 09] p5.js 實戰演練(三) –– 疊合公轉軸(三)

  • 分享至 

  • xImage
  •  

我們繼續上一個單元 p5.js 實戰演練(二) –– 疊合公轉軸(二) 的實驗。

若仔細思索就會發現,當我們繪製完其中一個小公轉軸,只依靠 rotate(-outer_orbit_speed); 是沒辦法完全把座標軸校正回來的。

因為繪製小公轉軸的所有動作:

	// 步驟 1-1:定位小公轉軸 1 的軸心
	rotate(outer_orbit_speed);
	translate(200, 0);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);

實際上包含了四次的座標轉換,分別是:

  • rotate(outer_orbit_speed);
  • translate(200, 0);
  • rotate(-outer_orbit_speed);
  • rotate(inner_orbit_speed);

那我們就必須分別對這四次的座標轉換反向校正回來。

我們可以用 p5.js 基礎教學(三) -- 繪製座標格線 的成果,繪製座標格線來實驗校正結果。

無校正版本

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

var gridSpacing = 50; // 設定每 50 px 就畫一條格線 

function createGrid() {
  for (var x = -width; x < width; x += gridSpacing) {
    for (var y = -height; y < height; y += gridSpacing) {
      stroke(200); // 設定線的顏色為灰色
      strokeWeight(1); // 設定線的寬度為1
      line(x, -height, x, height); // 畫出垂直線
      line(-width, y, width, y); // 畫出水平線
    }
  }
}

function draw() {
	background(100, 100);
	translate(width/2, height/2);
	
	var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
	var inner_orbit_speed = frameCount/60/3 * 2 * PI;
	
	// 步驟 1-1:定位小公轉軸 1 的軸心
	rotate(outer_orbit_speed);
	translate(200, 0);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 繪製格線
	createGrid();
}

Imgur

這是無校正版本,座標系統會同時繞著小公轉軸和大公轉軸旋轉。

只校正小公轉軸 rotate 函數的版本

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

var gridSpacing = 50; // 設定每 50 px 就畫一條格線 

function createGrid() {
  for (var x = -width; x < width; x += gridSpacing) {
    for (var y = -height; y < height; y += gridSpacing) {
      stroke(200); // 設定線的顏色為灰色
      strokeWeight(1); // 設定線的寬度為1
      line(x, -height, x, height); // 畫出垂直線
      line(-width, y, width, y); // 畫出水平線
    }
  }
}

function draw() {
	background(100, 100);
	translate(width/2, height/2);
	
	var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
	var inner_orbit_speed = frameCount/60/3 * 2 * PI;
	
	// 步驟 1-1:定位小公轉軸 1 的軸心
	rotate(outer_orbit_speed);
	translate(200, 0);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 只校正小公轉軸 rotate 函數
	rotate(-inner_orbit_speed);
	
	// 繪製格線
	createGrid();
}

Imgur

這版本的座標網格已經校正了小公轉軸的變化,但依然繞著大公轉軸旋轉。

加上大公轉軸 translate 函數校正版本

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

var gridSpacing = 50; // 設定每 50 px 就畫一條格線 

function createGrid() {
  for (var x = -width; x < width; x += gridSpacing) {
    for (var y = -height; y < height; y += gridSpacing) {
      stroke(200); // 設定線的顏色為灰色
      strokeWeight(1); // 設定線的寬度為1
      line(x, -height, x, height); // 畫出垂直線
      line(-width, y, width, y); // 畫出水平線
    }
  }
}

function draw() {
	background(100, 100);
	translate(width/2, height/2);
	
	var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
	var inner_orbit_speed = frameCount/60/3 * 2 * PI;
	
	// 步驟 1-1:定位小公轉軸 1 的軸心
	rotate(outer_orbit_speed);
	translate(200, 0);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 校正小公轉軸 rotate 函數和大公轉軸 translate 函數
	rotate(-inner_orbit_speed);
	translate(-200, 0);
	
	// 繪製格線
	createGrid();
}

Imgur

如果只對大公轉軸的 translate 做校正是沒用的,因為原本的 translate(200, 0); 就是由 rotate(outer_orbit_speed); 疊加上去的,必須兩個都進行校正。

正確校正版本

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

var gridSpacing = 50; // 設定每 50 px 就畫一條格線 

function createGrid() {
  for (var x = -width; x < width; x += gridSpacing) {
    for (var y = -height; y < height; y += gridSpacing) {
      stroke(200); // 設定線的顏色為灰色
      strokeWeight(1); // 設定線的寬度為1
      line(x, -height, x, height); // 畫出垂直線
      line(-width, y, width, y); // 畫出水平線
    }
  }
}

function draw() {
	background(100, 100);
	translate(width/2, height/2);
	
	var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
	var inner_orbit_speed = frameCount/60/3 * 2 * PI;
	
	// 步驟 1-1:定位小公轉軸 1 的軸心
	rotate(outer_orbit_speed);
	translate(200, 0);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 對四個座標轉換做校正
	rotate(-inner_orbit_speed);
	rotate(outer_orbit_speed);
	translate(-200, 0);
	rotate(-outer_orbit_speed);
	
	// 繪製格線
	createGrid();
}

Imgur

棒棒!我們對所有動作都進行反向校正之後,就可以讓座標系統維持最原始的樣子了。

校正原本的作品

我們用剛剛實驗的結果來校正原本的作品。

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

function draw() {
	background(100, 100);
	translate(width/2, height/2);
	
	var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
	var inner_orbit_speed = frameCount/60/3 * 2 * PI;
	
	// 步驟 1-1:定位小公轉軸 1 的軸心
	rotate(outer_orbit_speed);
	translate(200, 0);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 對四個座標轉換做校正
	rotate(-inner_orbit_speed);
	rotate(outer_orbit_speed);
	translate(-200, 0);
	rotate(-outer_orbit_speed);
	
	// 步驟 2-1:定位小公轉軸 2 的軸心
	rotate(outer_orbit_speed);
	translate(0, 200);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 2-2:繪製沿著小公轉軸 2 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 對四個座標轉換做校正
	rotate(-inner_orbit_speed);
	rotate(outer_orbit_speed);
	translate(0, -200);
	rotate(-outer_orbit_speed);
	
	// 步驟 3-1:定位小公轉軸 3 的軸心
	rotate(outer_orbit_speed);
	translate(-200, 0);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 3-2:繪製沿著小公轉軸 3 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 對四個座標轉換做校正
	rotate(-inner_orbit_speed);
	rotate(outer_orbit_speed);
	translate(200, 0);
	rotate(-outer_orbit_speed);
	
	// 步驟 4-1:定位小公轉軸 4 的軸心
	rotate(outer_orbit_speed);
	translate(0, -200);
	rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
	
	// 步驟 4-2:繪製沿著小公轉軸 4 繞行的 4 個 circle
	rotate(inner_orbit_speed);
	circle(100, 0, 20);
	circle(-100, 0, 20);
	circle(0, 100, 20);
	circle(0, -100, 20);
	
	// 對四個座標轉換做校正
	rotate(-inner_orbit_speed);
	rotate(outer_orbit_speed);
	translate(0, 200);
	rotate(-outer_orbit_speed);
}

Imgur

這是軌跡版本:

Imgur

到這邊我們終於得到預期結果了,同時大公轉軸和小公轉軸都有四個對象在做圓周運動。


上一篇
[Day 08] p5.js 實戰演練(二) –– 疊合公轉軸(二)
下一篇
[Day 10] p5.js 基礎教學(四) –– push 與 pop 函數
系列文
p5.js 的環形藝術30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言