Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
54
Help us understand the problem. What is going on with this article?
@clomie

3D空間に発光するパーティクルを配置する

More than 5 years have passed since last update.

発光してる感じのPImageを色別にいくつか生成して、それを視点に対して常に平行に描画することで3D上に発光するパーティクルがたくさんあるように見せる。

パーティクルは、enumで色配分を定義しておく。1つのパーティクルはだいたい縦横150pxぐらいで、enumのcalculateで中心点からの距離に応じたRGB値を返すようにしてる。ただ、enumはProcessing 2.2.1だと使えないみたいでちょっと困った。StackOverflowに別タブで拡張子をjavaにするとjavaで書けるよって書いてあったのでこれで。

視点の移動はPeasycamを初めて使ってみたんだけど、何もしなくてもマウスでいろいろ動かせるしめっちゃ便利。PImageはgetRotationsの結果のfloat配列をそれぞれrotateX, rotateY, rotateZの引数に与えてからimageで貼り付ければ視点と平行に描画できる。点の配置については、この資料にある「単位球内に一様分布する点」の計算式をそのまま。

blendModeは最初はADDを指定してたけど、手前と奥でパーティクルが重なった時に無駄に光ってしまい気持ち悪かった。いろいろ試した結果、SCREENだといい感じに表示されたので採用。あとhint(DISABLE_DEPTH_TEST) を指定しないとPImageが透過できないみたい。

というわけでこんな感じのコードになりました。

particle3D.pde
import java.util.*;
import peasy.*;

private PeasyCam cam;
private Particle[] particles = new Particle[1000];

private boolean record = false;

void setup() {
  size(960, 540, P3D);

  hint(DISABLE_DEPTH_TEST);
  blendMode(SCREEN);
  imageMode(CENTER);
  frameRate(30);

  cam = new PeasyCam(this, width);
  cam.setMaximumDistance(width * 2);

  List<PImage> images = new ArrayList<PImage>();
  for (Colors c : Colors.values ()) {
    images.add(createLight(c));
  }

  for (int i = 0; i < particles.length; i++) {
    PImage image = images.get(i % images.size());
    particles[i] = new Particle(image);
  }
}

private PImage createLight(Colors colors) {
  int side = 150;
  float center = side / 2.0;
  PImage img = createImage(side, side, RGB);

  for (int y = 0; y < side; y++) {
    for (int x = 0; x < side; x++) {
      float distance = (sq(center - x) + sq(center - y)) / 10;
      int c = colors.calculate(distance);
      img.pixels[x + y * side] = c;
    }
  }

  return img;
}

void draw() {

  background(0);
  translate(width/2, height/2, 0);

  cam.rotateX(radians(0.25));
  cam.rotateY(radians(0.25));

  float[] rotations = cam.getRotations();
  for (Particle p : particles) {
    p.render(rotations);
  }

  if (record) {
    saveFrame("frame/frame-######.tif");
  }
}

void keyPressed() {
  if (key == 's') {
    record = true;
  }
}

class Particle {

  private final PImage light;
  private final float x, y, z;

  Particle(PImage light) {
    this.light = light;

    float radP = radians(random(360));

    float unitZ = random(-1, 1);
    float sinT = sqrt(1 - sq(unitZ));

    float unitR = pow(random(1), 1.0/3.0);
    float r = width;

    x = r * unitR * sinT * cos(radP);
    y = r * unitR * sinT * sin(radP);
    z = r * unitR * unitZ;
  }

  void render(float[] rotation) {
    pushMatrix();
    translate(x, y, z);
    rotateX(rotation[0]);
    rotateY(rotation[1]);
    rotateZ(rotation[2]);
    image(light, 0, 0);
    popMatrix();
  }
}
Colors.java
public enum Colors {
  RED(8, 4, 4), 
  ORANGE(8, 6, 4), 
  YELLOW(8, 8, 4), 
  LEAF(6, 8, 4), 
  GREEN(4, 8, 4), 
  EMERALD(4, 8, 6), 
  CYAN(4, 8, 8), 
  SKY(4, 6, 8), 
  BLUE(4, 4, 8), 
  PURPLE(6, 4, 8), 
  MAGENTA(8, 4, 8);

  private static final float SUPPRESS = 3;
  private float r, g, b;

  private Colors(float r, float g, float b) {
    this.r = r;
    this.g = g;
    this.b = b;
  }

  public int calculate(float d) {
    return 0xff << 24 | color(r, d) << 16 | color(g, d) << 8 | color(b, d);
  }

  private static int color(float a, float distance) {
    int color = (int)(256 * a / distance - SUPPRESS);
    return Math.max(0, Math.min(color, 255));
  }
}

実行するとこんな感じで表示される。

shot.png

54
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
clomie

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
54
Help us understand the problem. What is going on with this article?