0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ProcessingでドローコールDrawCallの負荷を確認する

Posted at

image.png

リアルタイム3Dにおいて、ドローコールの負荷が馬鹿にならないという問題があります。
例えば、マインクラフトのように、ボックスが大量にあるような場合です。

Processing環境で、負荷を減らす方法を確認します。

環境

MacBookPro M1
Processing 4.2

26万回のbox()呼び出し

処理が重いです。
約 6 fps

int N = 64;          // 各軸方向の個数
float spacing = 80;  // 立方体どうしの距離
float boxSize = 40;  // 立方体の大きさ

void setup() {
  size(800, 800, P3D);
  perspective(radians(60),1,10,10000);
  noStroke();
}

void draw() {
  background(0);
  lights();

  // シーン全体を見やすくするためのカメラっぽい変換
  translate(width/2, height/2, -spacing * N * 1.5);
  rotateY(frameCount * 0.01);
  rotateX(frameCount * 0.007);

  // 64×64×64 = 262144 回 box() をcall
  for (int z = 0; z < N; z++) {
    for (int y = 0; y < N; y++) {
      for (int x = 0; x < N; x++) {
        pushMatrix();
            // 中心が(0,0,0)付近に来るようにオフセット
            float px = (x - (N - 1) / 2.0) * spacing;
            float py = (y - (N - 1) / 2.0) * spacing;
            float pz = (z - (N - 1) / 2.0) * spacing;
            translate(px, py, pz);
    
            // 色を少し変えてもOK(不要なら固定色で)
            float c = map(z, 0, N-1, 50, 255);
            fill(c, 150, 255 - c);
    
            box(boxSize);
        popMatrix();
      }
    }
  }

  // =====================
  // fps表示(負荷確認用)
  // =====================
  hint(DISABLE_DEPTH_TEST);   // 手前に描くため
  camera();                   // カメラをリセット
  noLights();
  fill(255);
  text("fps: " + nf(frameRate, 1, 1), 10, 20);
  hint(ENABLE_DEPTH_TEST);
}

26万回のbox()を登録したPShape 1回の呼び出し

劇的に軽くなります。
簡単で高速。
約 54 fps

int N = 64;          // 各軸方向の個数
float spacing = 80;  // 立方体どうしの距離
float boxSize = 40;  // 立方体の大きさ
PShape cubes;

void setup() {
  size(800, 800, P3D);
  perspective(radians(60),1,10,10000);
  noStroke();

  // =========================
  // 4096個のキューブをPShapeにまとめる
  // =========================
  cubes = createShape(GROUP);

  for (int z = 0; z < N; z++) {
    for (int y = 0; y < N; y++) {
      for (int x = 0; x < N; x++) {

        // 個々のキューブPShapeを作成
        PShape b = createShape(BOX, boxSize);
        b.setStroke(false);

        float px = (x - (N - 1) / 2.0) * spacing;
        float py = (y - (N - 1) / 2.0) * spacing;
        float pz = (z - (N - 1) / 2.0) * spacing;

        // それぞれの位置へオフセット
        b.translate(px, py, pz);

        // 色を少し変える
        float c = map(z, 0, N-1, 50, 255);
        b.setFill(color(c, 150, 255 - c));

        // GROUPに追加
        cubes.addChild(b);
      }
    }
  }
}

void draw() {
  background(0);
  lights();

  // シーン全体を回して眺める
  pushMatrix();
    translate(width/2, height/2, -spacing * N * 1.5);
    rotateY(frameCount * 0.01);
    rotateX(frameCount * 0.007);
    // 1回の shape() をcall
    shape(cubes);
  popMatrix();

  // =====================
  // fps表示(負荷確認用)
  // =====================
  hint(DISABLE_DEPTH_TEST);   // 手前に描くため
  camera();                   // カメラをリセット
  noLights();
  fill(255);
  text("fps: " + nf(frameRate, 1, 1), 10, 20);
  hint(ENABLE_DEPTH_TEST);
}

テクスチャ版

マイクラ程度の低解像度テクスチャ16x16を適用しても、特に速度に変化はありませんでした。

int N = 64;          // 各軸方向の個数
float spacing = 40;  // 立方体どうしの距離
float boxSize = 40;  // 立方体の大きさ

PShape cubes;        // 4096個のキューブをまとめたPShape(GROUP)
PImage checkerTex;   // 市松模様テクスチャ

void setup() {
  size(800, 800, P3D);
  noStroke();
  perspective(radians(60),1,10,10000);
  
  // =========================
  // 市松模様テクスチャを生成
  // =========================
  checkerTex = makeCheckerTexture(16, 16, 8); 


  // =========================
  // 4096個のキューブをPShapeにまとめる
  // =========================
  cubes = createShape(GROUP);

  textureMode(NORMAL); // 0.0〜1.0のUV(BOXはデフォルトでこの想定)

  for (int z = 0; z < N; z++) {
    for (int y = 0; y < N; y++) {
      for (int x = 0; x < N; x++) {

        // テクスチャ付きBOXを作成
        PShape b = createShape(BOX, boxSize);
        b.setStroke(false);
        b.setTexture(checkerTex);  // ← 市松模様を貼る
        b.setFill(color(255));     // テクスチャにそのままの色で

        float px = (x - (N - 1) / 2.0) * spacing;
        float py = (y - (N - 1) / 2.0) * spacing;
        float pz = (z - (N - 1) / 2.0) * spacing;

        b.translate(px, py, pz);

        cubes.addChild(b);
      }
    }
  }
}

void draw() {
  background(0);
  lights();

  pushMatrix();
  translate(width/2, height/2, -spacing * N * 1.5);
  rotateY(frameCount * 0.01);
  rotateX(frameCount * 0.007);

  shape(cubes);  // ここは1回だけ

  popMatrix();

  // fps表示
  hint(DISABLE_DEPTH_TEST);
  camera();
  noLights();
  fill(255);
  text("fps: " + nf(frameRate, 1, 1), 10, 20);
  hint(ENABLE_DEPTH_TEST);
}

// =====================
// 市松模様テクスチャ生成
// =====================
PImage makeCheckerTexture(int w, int h, int cells) {
  PImage img = createImage(w, h, RGB);
  img.loadPixels();

  int cellW = w / cells;
  int cellH = h / cells;

  for (int y = 0; y < h; y++) {
    int cy = y / cellH;
    for (int x = 0; x < w; x++) {
      int cx = x / cellW;
      // (cx + cy) の偶奇で白黒を切り替え
      if ((cx + cy) % 2 == 0) {
        img.pixels[y * w + x] = color(255,128,0);
      } else {
        img.pixels[y * w + x] = color(0,128,255);
      }
    }
  }

  img.updatePixels();
  return img;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?