在Processing中自定义相机方向?

时间:2014-11-05 19:00:17

标签: java 3d processing

这就是我想要实现的目标:我想在3D处理草图中绘制全局轴(仅正半轴)为x:红色,y:绿色,g:蓝色。然后我想将相机放在xyz坐标(20,20,30)处,并让它看一下xyz(0,0,0),这样相机的向上矢量与全局z轴(几乎)共线。因此,最后我想看到红色轴(x)向左,绿色轴(y)向右,蓝色轴(z)向上 - 然后我想要像PeasyCam一样进行鼠标交互,但是尊重这个方向。

由于Rotating camera around object axis with Peasycam,我知道PeasyCam无法真正做到这一点,所以我尝试使用OCD: Obsessive Camera Direction。下面是一个使用它的MWE,并模拟一些PeasyCam鼠标交互。

问题在于:无论我如何在ODC Camera构造函数中设置向上矢量,我在拖动时都会得到几乎相同的行为(gif上的白色圆圈表示鼠标位置):

/tmp/Sketch/animate-O2.gif

显然,无论如何设置向上矢量,渲染都会显示y向下的绿色矢量。

实际上,如果查看updateUp()中的ocd/src/damkjer/ocd/Camera.java函数,可以看到原始设置的组件会根据摄像头和目标位置被覆盖,所以我猜,难怪为什么草图对它们没有不同的反应;唯一能够改变向上矢量的东西似乎是通过roll()方法设置的滚动参数。

我的问题是:我可以在下面的代码中做些什么来实现我想要的(相机拖动交互,但是0,0,1向量呈现/保持向上)?

这是MWE代码,Sketch.pde

// modification of example on http://mrfeinberg.com/peasycam/
// https://stackoverflow.com/questions/17683602/rotating-camera-around-object-axis-with-peasycam/26755516#26755516
// sdaau, 2014

import damkjer.ocd.*;
DCamera cam1; //Camera cam1; // (see subclass below)
int saveCount=500;

void setup() {
  // Setup graphics
  size(300, 200, P3D);
  // only .roll() seems to be able to manipulate up vector?
  cam1 = new DCamera(this, //Camera(this, // (parent,
    40, 40, 60,            // cameraX, cameraY, cameraZ,
    0, 0, 0,               // targetX, targetY, targetZ
//    0, 0, 1,               // upX, upY, upZ // (seems ignored)
//    0, 1, 0,               // upX, upY, upZ // (seems ignored)
    1, 0, 0,               // upX, upY, upZ // (seems ignored)
    10, 500                // nearClip, farClip) //(doesn't clip as peasycam!)
  );
  //~ cam1.roll(radians(-90));
}

void draw() {
  cam1.feed(); //"send what this camera sees to the view port"
  // actual drawing:
  background(0);
  stroke(255,0,0); line(0,0,0, 1000,0,0); // x axis
  stroke(0,255,0); line(0,0,0, 0,1000,0); // ... y
  stroke(0,0,255); line(0,0,0, 0,0,1000); // ... z
  fill(255,0,0);
  box(30);
  pushMatrix();
  translate(0,0,20);
  fill(0,0,255);
  box(5);
  popMatrix();
  fill(-1);
//  text("U 0,0,1", -20, 30, 6);
//  text("U 0,1,0", -20, 30, 6);
  text("U 1,0,0", -20, 30, 6);
  if (mouseButton == LEFT) {
    hint(DISABLE_DEPTH_TEST);
    camera(); // must have after disable for 2D draw
    ellipse(mouseX,mouseY,20,20);
    saveFrame( "images/image_" + saveCount + ".png" );
    saveCount++;
    hint(ENABLE_DEPTH_TEST);
  }
}

// this to emulate peasycam:
// these to replicate the peasycam interaction with OCD:
void mouseDragged() {
    if (mouseButton == LEFT) {
      // http://www.airtightinteractive.com/demos/processing/bezier_ribbon_p3d/BezierRibbons.pde
      cam1.arc(radians(-(mouseY - pmouseY))/4);
      cam1.circle(radians(-(mouseX - pmouseX))/4);
    } else if (mouseButton == RIGHT) {
      cam1.zoom(radians(mouseY - pmouseY) / 2.0);
    } else if (mouseButton == CENTER) {
      // peasycam calls this .pan(); damkjer.ocd calls it .track()
      cam1.track(-(mouseX - pmouseX), -(mouseY - pmouseY));
    }
}
void mouseWheel(MouseEvent event) {
    float e = event.getCount();
    cam1.zoom(e*4.0);
}

public class DCamera extends damkjer.ocd.Camera {
  // private final PApplet p; // in peasycam/src/peasy/PeasyCam.java; in ocd/src/damkjer/ocd/Camera.java it is called theParent! both are private!
  private PApplet theParent; // replicate as in ocd/.../Camera.java; it helps, even if super has same name (must re-assign in ctor)

  // directly from libraries/ocd/src/damkjer/ocd/Camera.java
  public DCamera(PApplet aParent,
                float aCameraX, float aCameraY, float aCameraZ,
                float aTargetX, float aTargetY, float aTargetZ,
                float aNearClip, float aFarClip)
  {
    super(aParent, aCameraX, aCameraY, aCameraZ, aTargetX, aTargetY, aTargetZ, aNearClip, aFarClip);
    theParent = aParent;
  }
  // another constructor, to handle up vector:
  public DCamera(PApplet aParent,
                float aCameraX, float aCameraY, float aCameraZ,
                float aTargetX, float aTargetY, float aTargetZ,
                float anUpX,    float anUpY,    float anUpZ,
                float aNearClip, float aFarClip)
  {
    super(aParent, aCameraX, aCameraY, aCameraZ, aTargetX, aTargetY, aTargetZ, anUpX, anUpY, anUpZ, aNearClip, aFarClip);
    theParent = aParent;
  }
}

/*
# https://stackoverflow.com/questions/3323619/how-to-sort-files-numerically-from-linux-command-line
# https://stackoverflow.com/questions/246215/how-can-i-list-files-with-their-absolute-path-in-linux

convert -delay 5 -loop 0 $(ls ./images/ | sort --version-sort -f) animate.gif
gifsicle -O2 --colors 8 animate.gif -o animate-O2.gif
*/

1 个答案:

答案 0 :(得分:0)

好吧,我决定尝试ProSceneJavadocs: proscene API),结果证明它符合我的要求:

/tmp/Sketch/animate-O2-2.gif

...也就是说,它可以从z(蓝色)矢量向上开始 - 然后鼠标可以用来“转动”该轴(大约)。

ProScene的默认交互与PeasyCam几乎相同(尽管鼠标轮相反),所以为了这个目的,我认为我找到了一个解决方案(虽然知道OCD是否可以实现同样的效果会很棒)

以下是代码Sketch.pde

// modification of example on http://mrfeinberg.com/peasycam/
// http://stackoverflow.com/questions/17683602/rotating-camera-around-object-axis-with-peasycam/26755516#26755516
// sdaau, 2014

import remixlab.proscene.*;
import remixlab.dandelion.geom.*; // Vec
Scene scene;
int saveCount=500;
//Choose one of P3D for a 3D scene, or P2D or JAVA2D for a 2D scene
String renderer = P3D;

void setup() {
  // Setup graphics
  size(300, 200, renderer);
  //Scene instantiation
  scene = new Scene(this);
  scene.setGridVisualHint(false);
  scene.setAxesVisualHint(false);
  // specify starting camera position, orientation and target
  scene.camera().setUpVector(new Vec(0, 0, -1), true); // boolean noMove
  scene.camera().setPosition(new Vec(30, 30, 50));
  scene.camera().lookAt(new Vec(0, 0, 0));
  // when damping friction = 0 -> spin
  scene.eye().frame().setDampingFriction(0);
}

void draw() {
  // actual drawing:
  background(0);
  stroke(255,0,0); line(0,0,0, 1000,0,0); // x axis
  stroke(0,255,0); line(0,0,0, 0,1000,0); // ... y
  stroke(0,0,255); line(0,0,0, 0,0,1000); // ... z
  fill(255,0,0);
  box(30);
  pushMatrix();
  translate(0,0,20);
  fill(0,0,255);
  box(5);
  popMatrix();
  fill(-1);
  text("U 0,0,-1", -20, 30, 6);
  if (mouseButton == LEFT) {
    hint(DISABLE_DEPTH_TEST);
    camera(); // must have after disable for 2D draw
    ellipse(mouseX,mouseY,20,20);
//    saveFrame( "images/image_" + saveCount + ".png" );
    saveCount++;
    hint(ENABLE_DEPTH_TEST);
  }
}

void keyPressed() {
  if(scene.eye().frame().dampingFriction() == 0)
    scene.eye().frame().setDampingFriction(0.5);
  else
    scene.eye().frame().setDampingFriction(0);
  println("Camera damping friction now is " + scene.eye().frame().dampingFriction());
}


/*
# http://stackoverflow.com/questions/3323619/how-to-sort-files-numerically-from-linux-command-line
# http://stackoverflow.com/questions/246215/how-can-i-list-files-with-their-absolute-path-in-linux

convert -delay 5 -loop 0 $(ls ./images/ | sort --version-sort -f) animate.gif
gifsicle -O2 --colors 8 animate.gif -o animate-O2.gif
*/