How to find or change Processing3+ camera angle of view and focal length?

Hi!

I'm working with a P3D render and having trouble to compute the actual width which will fit in my monitor on a given plane (the monitor/screen plane) perpendicular to the camera axis, when I get closer or further away from that plane, moving the camera through the perpendicular axis.

(https://forum.processing.org/two/uploads/imageupload/507/2HZHUOVM4KRL.png "Problem Description")

Considering the code I created below to illustrate my problem (Java class), I would like to print the rectangle always coinciding with the border of the screen, but on the z=0 plane, no matter what my "eye" variable value is (as far as it is positive).

import processing.core.PApplet;
import processing.core.PConstants;

public class CameraTest extends PApplet {

    private static final int CAMERA_EYE = 900;

    //camera distance from the x,y plane, over z axis
    private float eye = CAMERA_EYE; 

    public void setup() {
        super.frameRate(30);
        super.background(0xFFFFFFFF);
    }

    public void settings() {
        super.fullScreen(PConstants.P3D);
    }

    public void draw() {
        super.background(0xFFFFFFFF);
        //adjusting camera
        super.beginCamera();
        super.camera(
                super.displayWidth/2, super.displayHeight/2, this.eye, //eye in middle of the screen, custom distance
                super.displayWidth/2, super.displayHeight/2, 0, //scene center at middle of the screen, in xy plane (z = 0)
                0, 1, 0); //camera up side on y axis
        super.endCamera();

        //drawing the monitor borders, using 3D lines (z = 0)
        super.stroke(0xFFFF0000);
        super.strokeWeight(4);
        //upper line
        super.line(0, 0, 0, super.displayWidth, 0, 0);
        //botton line
        super.line(0, super.displayHeight, 0, super.displayWidth, super.displayHeight, 0);
        //left line
        super.line(0, 0, 0, 0, super.displayHeight, 0);
        //right line
        super.line(super.displayWidth, 0, 0, super.displayWidth, super.displayHeight, 0);

        //printing eye value in the middle of screen
        super.fill(0xFF000000);
        super.textMode(PApplet.CENTER);
        super.text("Distance: " + this.eye, super.displayWidth/2, super.displayHeight/2, 
                this.eye - 660); //keeping distance from camera always the same.

    }

    public void keyPressed() {
        if (super.key == PApplet.CODED) {
            switch (super.keyCode) {
            case PApplet.UP:
                //move camera closer to the display plane
                this.eye -= 10;
                if (this.eye < 10) {
                    this.eye = 10;
                }
                break;
            case PApplet.DOWN:
                //move camera away from the display plane
                this.eye += 10;
                break;
            }
        } else if (super.key == 'r') {
            //reset camera position
            this.eye = CAMERA_EYE;
        }
    }

    public static void main(String[] args) {
        PApplet.main(CameraTest.class.getName()); 
    }

}

I imagine that I would need to find out the camera angle of view and/or focal length to do that. Am I right? Any hints on how can I do it? Couldn't find these information yet googling...

Usage: Arrow Up: get closer to the z=0 axis; Arrow Down: get further from the z=0 axis; r: resets the camera's position.

Crossed fingers! Thank you!

Answers

  • T_DT_D
    Answer ✓

    One easy way to achieve is, is to replace the current matrix with the inital one.

    import processing.core.PApplet;
    import processing.core.PMatrix3D;
    
    public class CameraTest extends PApplet {
    
      PMatrix3D mat_default = new PMatrix3D();
      
      public void settings() {
        size(800, 600, P3D);
      }
      
      public void setup() {
        getMatrix(mat_default);
      }
    
      public void draw() {
        background(255);
        
        // set projection matrix
        perspective(60 * DEG_TO_RAD, width/(float)height, 1, 1000);
        
        // set modelview matrix
        float eye = 20 + mouseY;
        camera(eye, eye, eye,   0, 0, 0,   0, 0, -1);
    
        // set world/scene matrix
        rotateZ(-mouseX/100f);
    
        // gizmo
        strokeWeight(1);
        stroke(0xFFFF0000); line(0,0,0,100,0,0);
        stroke(0xFF00FF00); line(0,0,0,0,100,0);
        stroke(0xFF0000FF); line(0,0,0,0,0,100);
        
        // box
        stroke(0);
        fill(200);
        lights();
        box(40);
        
        // 2D, screen space
        pushMatrix();
        hint(DISABLE_DEPTH_TEST);
        setMatrix(mat_default);
        noLights();
        {
          noFill();
          stroke(255,0,0);
          strokeWeight(10);
          rect(0,0, width, height);
        }
        hint(ENABLE_DEPTH_TEST);
        popMatrix();
      }
      
      public static void main(String[] args) {
        PApplet.main(CameraTest.class.getName());
      }
    
    }
    
  • edited October 2016

    Hello, T_D!

    Many thanx for your answer! That's exactly what I need for my actual problem: independent drawing on screen and 3d space (for example, drawing 3D moving objects, with 2D pictures behind them, considering camera eye position affects only 3D space drawings, while pictures keep being drawn in the whole screen width and height - assuming their size is width x height).

    I'll calmly study some functions and constants that you used in your code as I think my life can get really easier from now on, using them. :D

    BTW, I'm not very into Processing, so I was starting to make some successful tests based on the perspective(...) method API explanations (which I found was related to my question after posting it), and found that (on z=0, with default perspective() values):

    float actualHeight = 2*PApplet.tan(PApplet.PI/6)*eye;
    float actualWidth = actualHeight * displayWidth / displayHeight;
    

    But the way you do it looks much more practical than providing "screen actual height or width" variables to other classes that may want to draw on the main renderer. Thanx again!

Sign In or Register to comment.