# Reversing Projection like \`gluUnproject()\`

**URL:** https://discourse.processing.org/t/reversing-projection-like-gluunproject/35964
**Category:** Processing
**Created:** [March 27, 2022, 4:13pm UTC](https://discourse.processing.org/t/reversing-projection-like-gluunproject/35964 "2022-03-27T16:13:33Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![Brahvim](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/brahvim/32/14756_2.png) [@Brahvim](https://discourse.processing.org/u/Brahvim)
#### Post date: [March 27, 2022, 4:13pm UTC](https://discourse.processing.org/t/reversing-projection-like-gluunproject/35964/1 "2022-03-27T16:13:34Z")

</div>

Edit, made a day later: [This Stackoverflow Post](https://stackoverflow.com/questions/41309251/how-to-unproject-a-vector-in-3d) seems to be of some help.

* * *

## ORIGINAL POST:

Hello there! As the title states, I want to “reverse” the effect that applying projection makes to a vector.

So, in Processing, we have the `perspective()` and `ortho()` functions to apply Projection.

What I did, was I made a system to take a vector from my “game world” (such as one that represents the position of a vertex to be drawn), normalize it / cap it / convert it to a unit vector, and multiply it by the screen’s dimensions (the `width` and `height` variables in Processing), then use one of the projection functions to achieve proper scaling of graphics to screens of all sizes.

Does Processing have any built-in ways to achieve this? Is my question not sensible and am I stupid? (🤣) Should I look further into raycasting?

Also, I found out during my own research that you can get the Projection Matrix that Processing builds up with this code:

```processing
// I couldn't think of a better name, sorry!:
PMatrix3D f = ((PGraphicsOpenGL)g).projection.get();

```

Please note that the values in this Matrix are in a ‘normalized range’, i.e., between `-1.0f` and `1.0f`.

---

<div class="post-metadata">

### Author: ![Brahvim](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/brahvim/32/14756_2.png) [@Brahvim](https://discourse.processing.org/u/Brahvim)
#### Post date: [April 9, 2022, 10:29am UTC](https://discourse.processing.org/t/reversing-projection-like-gluunproject/35964/2 "2022-04-09T10:29:37Z")

</div>

Originally, I was normalizing the Screen co-ordinate and then multiplying it to convert it to a World co-ordinate just the same way I did the world-to-screen conversion.

This,

```processing
PMatrix3D f = new PMatrix3D(((PGraphicsOpenGL)g).projection);
// Or `f = ((PGraphicsOpenGL)g).projection.get();
f.invert();
PVector worldVec = f.mult(screenVec, null);
// (Or `f.mult(screeVec, worldVec)`)

```

…did not do what I expected.

My final solution, which surprised me, was actually just a simple `map()` for each component of the vector.

Great! I have a solution now 😃

(Found the solution a day and almost 4 hours before writing this post.)

Immediate edit: wondering what I could do for the `z`-axis now :0

---

<div class="post-metadata">

### Author: ![Brahvim](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/brahvim/32/14756_2.png) [@Brahvim](https://discourse.processing.org/u/Brahvim)
#### Post date: [May 26, 2022, 5:00pm UTC](https://discourse.processing.org/t/reversing-projection-like-gluunproject/35964/3 "2022-05-26T17:00:12Z")

</div>

It has been months! I have had **this** solution for very long, but I absolutely _never_ posted it.

And yes, I have realized, that apparently, it is better to use `screenX()`, `screenY()` and `screenZ()` for hit/intersection/collision tests rather than un-projecting.  
This, is still good to have, however.

**Please inform me if this breaks**. Sometimes, however, you WILL need to adjust the  
`mouse.sub()` line, in which case, I cannot help! Ask any questions you like, too!  
(Also, the `cx` and `cy` variables are `width / 2` and `height / 2`, respectively.)

You might need to _not use_ the line with `cameraInv` as well, if using `perspective()`.

Please note that you need to declare this somewhere in your code, outside any functions or classes:  
`PGraphicsOpenGL glGraphics;`

Then inside `setup()`, write this!:  
`glGraphics = (PGraphicsOpenGL)g;`

(I feel that it should be `glGraphics = (PGraphicsOpenGL)getGraphics();` instead, but the code given above works, so… I didn’t worry as much…)

…alright, here you go! `":D`:

```processing
PVector mouse = new PVector();

void unprojectMouse() {
    mouse.set(mouseX, mouseY);
    mouse = glGraphics.modelviewInv.mult(mouse, null);
    mouse = glGraphics.cameraInv.mult(mouse, null);

    // This part of the code changes depending on what projection you are using.
    // If it is orthographic (`ortho()`), this may work:
    
    //mouse.sub(width + cx, height + cy);
    //mouse.x = -mouse.x;
    //mouse.z = 0;

    // Use this otherwise:
    //mouse.sub(width, height);
}

// I generally like to call this inside a method called "`pre()`".
// To use it, however, we need to do this:

void setup() {
  registerMethod("pre", this);
}

// ..the reason being, that this is a method that Processing has made for libraries to use.
// It is called before `draw()`, and helps me write cleaner code.

void pre() {
  unprojectMouse();
}

// .. you can choose to not do all these weird things 
// and just call `unprojectMouse()` inside `draw()` :)

}

```

I also used this on Android (Only the version that uses `perspective()` was tested, although both should work given proper modifications).

```processing
void unprojectTouches() {
  for (int i = 0; 
    i < nTouches; i++) {
    projectedTouches[i]
      .set(touches[i].x, 
      touches[i].y);
    projectedTouches[i] 
      = glGraphics.modelviewInv
      .mult(projectedTouches[i], 
      null);
    projectedTouches[i] 
      = glGraphics.cameraInv
      .mult(projectedTouches[i], 
      null);
    projectedTouches[i].sub(
      width, height);
  }
}

```

(I know it looks messy, but those who choose to paste this into APDE will love it, `:D`!

…here’s a cleaner version 😂

```processing
void unprojectTouches() {
  for (int i = 0; i < nTouches; i++) {
    projectedTouches[i].set(touches[i].x, touches[i].y);

    projectedTouches[i] = glGraphics
      .modelviewInv.mult(projectedTouches[i], null);

    projectedTouches[i] = glGraphics
     .cameraInv.mult(projectedTouches[i], null);

    projectedTouches[i].sub(width, height);
  }
}

```

😅)

…_ **but** _, you also need to include this part:

```processing
int nTouches;
PVector[] projectedTouches; // Should be called 
// `unprojectedTouches` - I know, I know...
PGraphicsOpenGL glGraphics; // This was mentioned at the top of this post.

void setup() {
  fullScreen(P3D); // Make sure you're using `P3D`.

  registerMethod("pre", this); // As stated earlier, this is optional.

  glGraphics = (PGraphicsOpenGL)g; // Necessary.
  // ..or,
  //glGraphics = (PGraphicsOpenGL)getGraphics();

  // Free boilerplate code!!!:
  for (int i = 0; i < 10; i++)
    projectedTouches[i] = new PVector();
}

// ..and this is optional too! 
// Call `unprojectTouches()` in `draw()` all you like, ":D!
void pre() {
  unprojectTouches();
}

void touchStarted() {
  nTouches++;
}

void touchEnded() {
  nTouches--;
}

```

---

<div class="post-metadata">

### Author: ![Brahvim](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/brahvim/32/14756_2.png) [@Brahvim](https://discourse.processing.org/u/Brahvim)
#### Post date: [August 23, 2022, 9:09am UTC](https://discourse.processing.org/t/reversing-projection-like-gluunproject/35964/4 "2022-08-23T09:09:16Z")

</div>

> **[gluUnproject() for P3D and OPENGL Sketches](http://andrewmarsh.com/blog/2011/12/04/gluunproject-p3d-and-opengl-sketches/)**
>
> Some issues with projection matrices in Processing 1.51

(Edit: Web Archive version, just in case… [gluUnproject() for P3D and OPENGL Sketches](https://web.archive.org/web/20220823092630/http://andrewmarsh.com/blog/2011/12/04/gluunproject-p3d-and-opengl-sketches/))

```processing
Selection_in_P3D_OPENGL_A3D unprojector
  = new Selection_in_P3D_OPENGL_A3D();
PVector mouse = new PVector();

void setup() {
}

void draw() {
  // After `perspective()` and `camera()` have been called,
  unprojector.captureViewMatrix((PGraphics3D)g);
  unprojector.gluUnProject(mouseX, mouseY, 0, mouse);

  // Use `mouse` now!
}

```
