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:
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).
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 
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:
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--;
}