In order to find the 2D HUD position of a 3D object (using three.js version r71), you may do the following, which I have modified from this post:
findHUDPosition : function (obj) {
var vector = new THREE.Vector3();
obj.updateMatrixWorld();
vector.setFromMatrixPosition(obj.matrixWorld);
vector.project(this.camera);
vector.x = ( vector.x * this.windowHalfX );
vector.y = ( vector.y * this.windowHalfY );
return {
x: vector.x,
y: vector.y,
z: vector.z
}
}
The parameter obj
is the object you are trying to find the position of in the hud.
vector.project(this.camera);
draws a vector from the object to the position of this.camera
, through the near
plane of the camera.
The new value of vector
's components are the intersection of the projected vector and this.camera
's near plane.
The coordinates are in three.js' world coordinate system though, so we have to do a quick conversion to pixel coordinates, to scale up to the size of our canvas.
vector.x = ( vector.x * this.windowHalfX );
vector.y = ( vector.y * this.windowHalfY );
The above conversion is for a setup where the HUD's coordinate system has an origin (0,0) at the center of the screen, and has a maximum value of half the canvas' resolution. For example, if your canvas is 1024 x 768 pixels, the position of the upper right corner would be (512, 384).
For a typical screen coordinate system, the bottom right corner would be (1024, 768), and the middle of the screen would be (512, 384). To have this setup, you can use the following conversion, as seen in this post.
vector.x = ( vector.x * widthHalf ) + widthHalf;
vector.y = - ( vector.y * heightHalf ) + heightHalf;
Notice, the z coordinate doesn't matter now, since we are in 2D.
The last thing you'll want to do is make sure that the object you're showing in 2D is actually visible to the perspective camera. This is as simple as checking to see if the object falls within the frustum of this.camera
. source for following code
checkFrustrum : function (obj) {
var frustum = new THREE.Frustum();
var projScreenMatrix = new THREE.Matrix4();
this.camera.updateMatrix();
this.camera.updateMatrixWorld();
projScreenMatrix.multiplyMatrices( this.camera.projectionMatrix, this.camera.matrixWorldInverse );
frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices( this.camera.projectionMatrix,
this.camera.matrixWorldInverse ) );
return frustum.containsPoint ( obj.position );
}
If this is not done, you can have an object which is behind the camera being registered as visible in the 2D scene (this poses problems for object tracking). It's also good practice to update obj
's matrix and matrix world.