2014年4月24日木曜日

Processingで3D空間

Processingで3Dを使うときのサンプルというか 雛形みたいなもの

final float BoxSize = 120;
final float AxisLineLen = BoxSize / 1.5;
final float AutoRotateDegree = 0.5;

boolean IsCameraRotate = true;
float CameraXrot = radians( 45);
float CameraYrot = radians(-45);
float CameraZoom = 160;
boolean pmousePressed = false, pkeyPressed = false;

void setup() { 
  textFont(createFont("GulimChe", 20));
  textAlign(LEFT, TOP);
  size(1024, 768, P3D);
  noFill();
}

void draw() {
  keyboardInput();
  
  pushMatrix();
  background(127);
  MoveCamera();
  DrawBox();
  popMatrix();
  
  text("camR:" + (int)degrees(CameraXrot), 0, 20 * 0);
  text("camP:" + (int)degrees(CameraYrot), 0, 20 * 1);
  text("zoom:" + (int)CameraZoom, 0, 20 * 2);
  text("musX:" + mouseX, 0, 20 * 3);
  text("musY:" + mouseY, 0, 20 * 4);
  
  if (!pkeyPressed && keyPressed && key == 's')
  { save("./Processing_ss.png"); } 
  
  pmousePressed = mousePressed;
  pkeyPressed   = keyPressed;
}

void keyboardInput() {
  if (!pkeyPressed && keyPressed) {
    if (key == '1') { IsCameraRotate = false; CameraXrot = radians( 0); CameraYrot = radians( 0); }
    if (key == '2') { IsCameraRotate = false; CameraXrot = radians(90); CameraYrot = radians( 0); }
    if (key == '3') { IsCameraRotate = false; CameraXrot = radians(90); CameraYrot = radians(89.71); }
    if (key == '4') { IsCameraRotate =  true; CameraXrot = radians(45); CameraYrot = radians(-45); }
  }
}

void DrawBox() {
  strokeWeight(2);
  stroke(255);     box(BoxSize / 2, BoxSize / 4, BoxSize);
  
  strokeWeight(1);
  stroke(#FF0000); line(0, 0, 0, 0, 0,  AxisLineLen); sphere(1, 0, 0, AxisLineLen);
  stroke(#7F0000); line(0, 0, 0, 0, 0, -AxisLineLen);
  stroke(#00FF00); line(0, 0, 0,  AxisLineLen, 0, 0); sphere(1, AxisLineLen, 0, 0);
  stroke(#007F00); line(0, 0, 0, -AxisLineLen, 0, 0);
  stroke(#0000FF); line(0, 0, 0, 0,  AxisLineLen, 0); sphere(1, 0, AxisLineLen, 0);
  stroke(#00007F); line(0, 0, 0, 0, -AxisLineLen, 0);
}

boolean MvCm_IsCameraMove = false;
void MoveCamera() {
  if (mousePressed) {
    CameraXrot += radians(pmouseX - mouseX) / 2;
    CameraYrot += radians(pmouseY - mouseY) / 2;
    MvCm_IsCameraMove = MvCm_IsCameraMove || pmouseX != mouseX || pmouseY != mouseY;
  } else {
    if (pmousePressed) 
    { IsCameraRotate = IsCameraRotate ? false : !MvCm_IsCameraMove; }
    if (IsCameraRotate) { CameraXrot += radians(AutoRotateDegree); }
    MvCm_IsCameraMove = false;
  }
  
  if (keyPressed && key == 'z') { CameraZoom++; }
  if (keyPressed && key == 'x') { CameraZoom--; }
  
  CameraXrot = (CameraXrot + TWO_PI) % TWO_PI;
  if (CameraYrot < -HALF_PI) { CameraYrot += PI; }
  if (CameraYrot >  HALF_PI) { CameraYrot -= PI; }
  
  camera(CameraXrot, CameraYrot, CameraZoom);
}

void camera(float X, float Y, float zoom) 
{ camera(cos(Y) * zoom * sin(X), sin(Y) * zoom, cos(Y) * zoom * cos(X), 0, 0, 0, 0, 1, 0); }

void sphere(float r, float x, float y, float z) 
{ pushMatrix(); translate(x, y, z); sphere(r); popMatrix(); }

やってることは
1カメラを移動
2箱と棒を表示
だけです
他にマウスのドラッグでカメラの位置を変えたりだとか、キーの入力に応じて視点を変更したりスクリーンショットを保存できます


カメラの位置変更はキーボードで行っています
一旦はマウスホイールでの動作も確認したのですが、あまりマウスホイールはどうさがよろしくなかったので

スクリーンショットの撮影をキー入力関数で行わないのは
キー入力:できるだけ早い段階でキーを読んでおきたい
スクリーンショット:すべての表示が終わった最後の段階で撮影したい
という違いによるものです

Processingは基本的に静的変数が使えないので
複数フレーム間で共有したい値はすべてグローバル変数にする必要があります
この辺りがちょっと面倒です

ちょっとした3Dの表示とかはProcessingだと簡単に作れるので
C#とかで作ったデータを何らかの方法でProcessingに渡すことができれば いろいろ応用が広がりそうです

0 件のコメント:

コメントを投稿