Pixel coordinate to world coordinate (orthographic cam)

Hello there, I have built the following script.

The idea is somewhat simple :

  1. I loop over each element with a specific class (here easterEgg)
  2. I map an event listener for click on each of this element
  3. The user click on it
  4. I get an emoji from the attribute of the clicked elem
  5. I calculate the real coordinate of the click (pixelX and pixelY), here I debug this position with drawHtmlSquare and the calculated coordinate are good
  6. With this coordinate, I place my emoji texture (created with createEmojiTexture()) in the same position but in webgl, like so when the user click on a word the emoji appear just below the cursor

My problem is specifically here, I don’t find the way to get the right coordinate.

I have tried many things (latest attempts are visible here).

The most close result that I have is with :

const calcx = pixelX / (window.innerHeight / 2) - 1;
const calcy = - pixelY / (window.innerWidth / 2) + 1;
const cunproj = new THREE.Vector3(calcx, calcy, -1).unproject(camera);
emojiMesh.position.set(cunproj.x, cunproj.y, -1);

But this is not very good, in the following img I map the click (red square) to the result (emoji) :

Another problem that I have is when I want to use the vector directly in the position.set like so - with that nothing appear on my screen :

const calcx = pixelX / (window.innerHeight / 2) - 1;
const calcy = - pixelY / (window.innerWidth / 2) + 1;
const cunproj = new THREE.Vector3(calcx, calcy, -1).unproject(camera);
emojiMesh.position.set(cunproj);

I’m pretty much a noob in webgl/three.js, so any idea is welcomed !

Looks like the projected points are off by .5 of the screenspace…
Can you try:

const cunproj = new THREE.Vector3(calcx-.5, calcy-.5, -1).unproject(camera);

1 Like

Hello, thanks for your answer, I found the solution :smile:

My calculation was not good at all.

Full explanation below

Important note, my 0,0 coordinate on three.js is always at the center of my screen in my case. Also, I use an orto camera, so I don’t need to mind z.

To translate the coordinates of a point from view A (where 0,0 is at the top left, so our screen) to view B (where 0,0 is at the center, the threejs view), we need to perform two transformations:

  1. Horizontal translation (x-axis)
  2. Vertical translation (y-axis)

Horizontal Translation (x-axis)

In view A, the origin (0,0) is at the top left. In view B, the origin (0,0) is at the center. To translate the x-coordinate of a point from view A to view B, we need to move the origin of view A to the center of view B.

  • If (Xa, Ya) are the coordinates of a point in view A, the new coordinate Xb in view B is obtained by subtracting half of the width (W/2) from Xa.

Formula: Xb = Xa - (W/2)

Vertical Translation (y-axis)

Similarly, for the y-coordinate, we also need to move the origin of view A to the center of view B. However, note that the y-coordinates increase downwards in view A, but in view B, they increase upwards from the center.

  • To translate the y-coordinate, we need to subtract Ya from half of the height (H/2).

Formula: Yb = (H/2) - Ya

And I use the coordinate like that without unproject or project.

const calcx = pixelX - (window.innerWidth / 2) ;
const calcy = (window.innerHeight / 2) - pixelY;
  
for (let i = 0; i < 50; i++) {
    const emojiMesh = new THREE.Mesh(emojiGeometry, emojiMaterial);
    emojiMesh.position.set(calcx, calcy, -1);
    .......
}
1 Like