使用 push/popmatrix 和 for 循环旋转正方形

rotate squares with push/popmatrix and for loop

我试图让我的网格中的每个方块随机旋转,所以每个方块都有不同的角度,但我旋转了我所有的方块。 我不明白为什么,因为旋转和矩形在 for 循环内一次绘制一次?


int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));


void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {

      pushMatrix();
      rotate(radians(rando));
      rect(x, y, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

使用 pushMatrix()/popMatrix() 来隔离每个方块的坐标,您走在正确的轨道上。

问题在于 rect(),因为它“隐藏”了翻译。

这一行:

rotate(radians(rando));
rect(x, y, rectSize, rectSize, 10);

大致相当于:

rotate(radians(rando));
translate(x, y);
rect(0, 0, rectSize, rectSize, 10);

并且(如您在 2D Transformations tutorials 中所见)操作顺序很重要。

在你的情况下,你想先平移,然后旋转(从那个平移的位置):

translate(x, y);
rotate(radians(rando));
rect(0, 0, rectSize, rectSize, 10);

总之,您的代码如下所示:


int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));


void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {

      pushMatrix();
      translate(x, y);
      rotate(radians(rando));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

更新 如果你想用不同的随机值旋转每个方块,你需要为每个方块计算一个值。

你可以这样:


int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));


void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      rando = random(55);
      pushMatrix();
      translate(x, y);
      rotate(radians(rando));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

很简单,对吧? Re-calculate值!这里也有一个问题 :) 如果你这样做,随机 re-calculated 不仅是每个方块一次,而且是每帧一次,所以你最终会得到非常不稳定的方块。

那就是你需要一次又一次地 re-draw 相同的方块(即使内容没有改变)。如果你只是想要一个静态图像,你可以跳过 draw() 并只使用 setup():

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;

void setup() {
  size(900, 900);


  noStroke();
  fill(40);
  rectMode(CENTER);
  
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {

      pushMatrix();
      translate(x, y);
      rotate(radians(random(55)));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }
}

即使没有 setup() 的“立即模式”也会产生相同的图像:

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;

size(900, 900);


noStroke();
fill(40);
rectMode(CENTER);

background(255);
for (int x=marginX; x<width; x+=xStep) {
  for (int y=marginY; y<height; y+=yStep) {

    pushMatrix();
    translate(x, y);
    rotate(radians(random(55)));
    rect(0, 0, rectSize, rectSize, 10);
    popMatrix();
  }
}

假设您确实需要 draw(),因为您可能希望使用键盘快捷键或单击鼠标来获得 re-randomise 值。

要绕过限制,您需要为每个方块计算一次随机值,然后在渲染时简单地检索这些值。

这意味着你需要一个结构来存储每个方块的每个随机值,你在 setup() 中写入一次值并在 draw() 中重复读取:数组可以轻松解决你的问题。

由于您使用的是嵌套 for 循环,因此您可以使用二维数组。请记住,循环中的 x,y 计数器是绝对像素坐标,您需要单独的索引来访问数组。这很容易:只需将 x,y 除以像素增量,它就会 'step' 计数器:

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
// store random values for each square
float[][]randos;

void setup() {
  size(900, 900);
  
  // initialise random array
  randos = new float[width / xStep][height / yStep];
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      // calculate array indices
      int xIndex = x / xStep;
      int yIndex = y / yStep;
      // write random values
      randos[yIndex][xIndex] = random(55);
    }
  }

  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      // calculate array indices
      int xIndex = x / xStep;
      int yIndex = y / yStep;
      pushMatrix();
      translate(x, y);
      // read random values
      rotate(radians(randos[xIndex][yIndex]));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

数组也可以是一维的,只是需要不同的计数:

int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
// store random values for each square
float[] randos;

void setup() {
  size(900, 900);
  
  // initialise random array
  int numSquares = (width / xStep) * (height / yStep);
  randos = new float[numSquares];
  int index = 0;
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      randos[index++] = random(55);
    }
  }

  noStroke();
  fill(40);
  rectMode(CENTER);
}

void draw() {
  background(255);
  int index = 0;
  for (int x=marginX; x<width; x+=xStep) {
    for (int y=marginY; y<height; y+=yStep) {
      pushMatrix();
      translate(x, y);
      rotate(radians(randos[index++]));
      rect(0, 0, rectSize, rectSize, 10);
      popMatrix();
    }
  }

}

(作为下一步,您可以将使用随机值初始化数组的设置部分封装到一个函数中:这将允许您在再次调用此函数时 reset/recalculate 新的随机值(例如在鼠标上click/key press/etc.)