0

I am trying to figure out how to get the 2D screen coordinates for a 3D point.

I am using three.js to generate some snowflakes that fall slowly down the screen. I originally wrote the script just as a 2d canvas animation and added mouse interaction so you could blow the snow around with mouse movement. It worked well, but when switching to webgl the snowflakes were now represented as 3D points and getting the distance of the mouse to each particle makes particles further from the center of the screen behave in an undesired way because of the perspective.

http://www.simplemathguild.com/snowtest.html

WestLangley
  • 102,557
  • 10
  • 276
  • 276
kurpa
  • 1

1 Answers1

0

What you need to do is to transform your worldPos vec3 by the viewProjection matrix and then perform the perspective divide. This brings it to NDC space where (-1,-1,x) = bottom left of your screen and (+1,+1,x) = upper right of your screen. Adjust this by your screen width and screen height and you have the coordinate in screen space.

In code, this is what it looks like:

worldToScreen: function(viewProjectionMatrix, screenWidth, screenHeight){
    var m = viewProjectionMatrix;
    var w = m[3] * this[0] + m[7] * this[1] + m[11] * this[2] + m[15]; // required for perspective divide
    this.transformByMat4(viewProjectionMatrix);
    if (w!==0){ // do perspective divide and NDC -> screen conversion
        var invW = 1.0/w;
        this[0] = (this[0]*invW + 1) / 2 * screenWidth;
        this[1] = (1-this[1]*invW) / 2 * screenHeight; // screen space Y goes from top to bottom
        this[2] *= invW;
    } 
    return this;
}

Btw this is what essentially what the GPU is doing under the hood to render stuff, minus the NDC to screen coordinate conversion.

Check the THREE Vector3 methods, very likely it is implemented there, or just use the code snippet above.

WacławJasper
  • 3,284
  • 14
  • 19
  • I am assuming you mean "this" as Vector3. As far as I know Three.js has no transformByMat4 function. Can you clarify? – XFCC Dec 11 '15 at 12:50
  • 1
    In case it wasnt clear, the snippet is pulled from my own lib and not from Three.js. When I wrote the answer, the question was tagged with webgl. I believe the corresponding method to transformByMat4 is applyMatrix in Three and this[0], [1], [2] are the .x, .y, .z properties of Three Vector3. – WacławJasper Dec 11 '15 at 17:32