how to map a 2D coordinate into 3D...

edited February 2017 in How To...

Hi, I have a set of points in 3D and want to use mouse to alter the position of those points. I have got the equivalent position of these points in 2D using screenX & screenY (mapping 3D into 2D), but have difficulty in mapping 2D back to 3D..

What I want is to use the mouse's position(mouseX mouseY) to determine the position of point's Z axis (height) to be visually in the same position as my mouse.

is there any function to counter-screenX & screenY...? (sort of sine - arcsine..if it can explain it less confusing..)

Let's say the position I would like to alter is

PVector pos = point.x, point.y, point.z

and I want the point.z be altered by mouseX and mouseY.. so it should be something like

if(mouseClicked)
{
point.z = counterScreen(mouseX, mouseY);.....
}

Answers

  • @kfrajer Thanks! I found it difficult to decide z value in 3D, so I gave up and use keyboard to control z value but I used the website you referred to to get the x & y value, that's very helpful thanks a looooot!!

  • Y is height and Z is depth.

    Image the space above a table.

    Y is how far above the table, Z is back and forth

  • You can try

    point.z = map(mouseY, 0, height, -200,200);

    Or increase the z value when mouseY > pmouseY etc..

  • Imagine you are standing in a room looking through a window at a beautiful country scene and you see something of interest at a 3D position [x,y,z]. Now imagine a line that links [x,y,z] to your eye. It will pass through the window and if we note the position it intersects with the window we get a 2D position [sx,sy].

    So far so good. Now lets try and reverse the process we draw a line from our eye to infinity through the window position [sx,sy] the 'something of interest' could be anywhere along that line. It means that it is impossible to generate a 3D position from the 2D screen position.

  • edited March 2017

    It means that it is impossible to generate a 3D position from the 2D screen position.

    Unless you have a rule that provides that third dimension. For example:

    1. if all points are at a fixed cartesian depth (e.g. all points have the same z value) or
    2. if all points are at a known fixed distance (e.g. all points are found on the surface of a sphere centered on the viewer) etc.

    Or you can create a depth map. For each point, index it under its screenX, screenY. Then look up a given screenX, screenY in your index / hashmap / whatever and return the point (if any) with the closest z (if more than one). But this is getting complex -- there may be simpler ways of accomplishing what you want depending on the scenario -- for example, if you know that points will never appear in front of each other.

    That is: once you have selected a point, you could alter the depth in relative ways with the mouse, for example dragging. Since you know the absolute z in the point object, it doesn't matter that you can't input an absolute z with the mouse -- it can be relative.

  • Post your code please

    Entire

  • The depth map idea is the easiest to implement, and serves the purpose well enough.

    Superb explanation @quark.

  • in this sketch you can drag a sphere with mouse and change its x,y

    when you hold a key during drag, ONLY Z changes with mouseY (up and down)

    // States
    final int HELP = 0; // consts 
    final int GAME = 1;
    int state = GAME;   // current 
    
    final int viewsTotal = 0;
    //final int viewsNeighbours = 1;  // 26 Neighbours 
    //final int viewsPlaneXY = 2;
    //final int viewsNeighboursInThePlaneXZ = 3;  // 8 Neighbours 
    //final int viewsNeighboursInThePlaneXY = 4;
    //final int viewsNeighboursInThePlaneYZ = 5;
    //final int viewsNeighboursDiagonally = 6;   // 8 Neighbours 
    
    int view = viewsTotal;
    
    // boxes 
    BoxClass[][][] boxes = new BoxClass[6][6][6];
    
    // cam rotation 
    float camCurrentAngle=0.0;      
    float camRadius=1.0;         
    
    PFont font1;
    
    boolean showGrid = false;  
    
    boolean hold; 
    PVectorInt selected = new PVectorInt(-1, 0, 0);
    
    // --------------------------------------------------------
    // main funcs 
    
    void setup() {
      size(1400, 800, P3D);
    
      defineBoxes();
      background(111);
      font1 = createFont("Arial", 32);
      textFont(font1);
    } // func 
    
    void draw() {
      switch (state) {
    
      case HELP:
        // to do  
        background(111);
        text("Help\n\nThis is the help..."
          +"\n\npress any key.", 
          32, 344);
        break;
    
      case GAME:
        playTheGame();   
        break;
    
      default:
        //exit
        break;
      } // switch
    } // func draw()
    
    // ----------------------------------------------------
    
    void playTheGame() {
    
      background(111);
    
      // reset some stuff that was set differently by the HUD
      hint(ENABLE_DEPTH_TEST);
      textSize(32);
      lights();
    
      scale (camRadius);
    
      translate(width/2, 0);
      rotateY(radians(camCurrentAngle));
    
      showTheGridDependingOnCurrentView();
      strokeWeight(1);
    
      if (hold) {
        if (keyPressed) {
          float diff=pmouseX-mouseX; 
          //  boxes[selected.x][selected.y][selected.z].x-=diff;
          diff=pmouseY-mouseY; 
          boxes[selected.x][selected.y][selected.z].z-=diff;
        } else 
        {
          float diff=pmouseX-mouseX; 
          boxes[selected.x][selected.y][selected.z].x-=diff;
          diff=pmouseY-mouseY; 
          boxes[selected.x][selected.y][selected.z].y-=diff;
        }
      }//if
    
      // camera 
      if (keyPressed&&key=='r')
        camCurrentAngle++;
      if (keyPressed&&key=='l')
        camCurrentAngle--;
    
      // 2D part / HUD  ---------------------------------------------
      camera();
      //  hint(DISABLE_DEPTH_MASK);
      hint(DISABLE_DEPTH_TEST);
      noLights();
      textMode(MODEL);
      //  textMode(SHAPE);
      textSize(22);
    
      if (hold) {
        fill(255, 2, 2); 
        text("Hold mode: drag a sphere to change its x,y. Hold a key and drag to change ONLY Z with mouse up and down (y is mapped to Z).", 
          10, 20 );
      } else {
        fill(255);
        text("Hello. "
          +"Use r and l to rotate. "
          +"Select a sphere with nouse click. "
          +"Demonstrates the usage of screenX,screenY.", 
          10, 20 );
        // text(mouseX + "," + mouseY, mouseX+7, mouseY-7);
      }
    }
    
    // ------------------------------------------------------------------
    
    void showTheGridDependingOnCurrentView() {
    
      switch (view) {
    
      case viewsTotal:
    
        //   println("here");
        // show list 
        // for (PVectorInt pvInt : listShape) {
        stroke(255, 2, 2);
    
        // show boxes : all
        boolean showInRed=false;
        for (int i = 0; i < boxes.length; i++) {
          for (int j = 0; j < boxes[i].length; j++) {
            for (int k = 0; k < boxes[i][j].length; k++) {
    
              if (selected.x==i&&selected.y==j&&selected.z==k)
                showInRed=true;
              else
                showInRed=false; 
    
              boxes[i][ j][k].show(showInRed);
            }
          }
        }// for
        break; 
    
      default : 
        // error 
        break;
      } // switch
    } // func 
    
    // ----------------------------------------------------
    // input funcs
    
    void keyPressed () {
    
      switch (state) {
    
      case HELP : 
        state = GAME; 
        break; 
    
      case GAME : 
        if (key!=CODED) {
          // not CODED -----------------------------------
          if (key=='X') {
            // reset  
            defineBoxes();
          } else if (key == 's') {
            showGrid=!showGrid;
          } else {
            // do nothing
          }
        } else {
          // if (key==CODED) { --------------------------------------------
          //
          switch (keyCode) {
    
          case java.awt.event.KeyEvent.VK_F1 : 
            // F1 
            state = HELP; 
            break; 
    
          case java.awt.event.KeyEvent.VK_PAGE_UP : 
            camRadius-=.01; 
            break; 
    
          case java.awt.event.KeyEvent.VK_PAGE_DOWN : 
            camRadius+=.01; 
            break; 
    
          default : 
            // do nothing 
            break;
          } // switch
        } // else
    
        break;
      } // switch 
      //
    } // func 
    
    // ----------------------------------------------------
    // misc funcs
    
    void defineBoxes() {
      // define boxes
      int k2=0; 
      char letter=' '; 
      for (int i = 0; i < boxes.length; i++) {
        for (int j = 0; j < boxes[i].length; j++) {
          for (int k = 0; k < boxes[i][j].length; k++) {
            // prepare values 
            color currentCol = color (255); //  color (random(255), random(255), random(255));
            boolean exist = true; 
    
            // create a box   
            boxes[i][ j][k] = new BoxClass( -180 + i*(height/10), 
              158 + j*(height/10), 
              130 - k*(height/10), 
              currentCol, 
              exist, 
              ' ' );
          }
        }
      } // for
    } // func 
    
    // ----------------------------------------
    
    void mousePressed() {
    
      for (int i = 0; i < boxes.length; i++) {
        for (int j = 0; j < boxes[i].length; j++) {
          for (int k = 0; k < boxes[i][j].length; k++) {
    
            if (dist(mouseX, mouseY, boxes[i][j][k].scX, boxes[i][j][k].scY) < 20) {
              selected= new PVectorInt( i, j, k); 
              hold=true; 
              return;
            }
          }
        }
      }
    }
    
    void mouseReleased() {
      hold=false; // off
      selected= new PVectorInt( -1, -1, -1); //selected is off
    }
    
    // =====================================================
    // classes
    
    class BoxClass {
    
      // this class represents one Box / Cell
    
      float x; 
      float y; 
      float z; 
    
      float scX, scY; 
    
      color col; 
      boolean exist = true; 
    
      // constr
      BoxClass(float x_, float y_, float z_, 
        color col_, 
        boolean exist_, 
        char letter_) {
        x = x_; 
        y = y_; 
        z = z_; 
        col = col_; 
        exist = exist_;
      } // constr
    
      void show(boolean showBoxAsRed) {
        if (exist||showGrid) {
          pushMatrix(); 
          translate(x, y, z); 
    
          fill(col); 
          if (showBoxAsRed)
            fill(255, 2, 2); //RED 
          noStroke(); 
    
          sphere(7);
          scX = screenX(0, 0, 0); 
          scY = screenY(0, 0, 0);
    
          popMatrix();
        }
      } // method
    } // class 
    
    // ==============================================================
    
    class PVectorInt {
      // it's like a PVector but int (not float)
      int x, y, z; 
      PVectorInt(int x_, int y_, int z_) {
        x=x_; 
        y=y_; 
        z=z_;
      } // constr
    
      PVectorInt copy() {
        return new PVectorInt(x, y, z);
      }
    }
    // =============================================================
    
Sign In or Register to comment.