2

I want to position x,y,z labels (sprites) on the axis I have in my scene. The problem is that zooming with the camera , should result to also moving the particles analogously so they stay in the side of the "screen".

So I just want to find a way to always know where the lines of x,y,z are out of the camera to update the labels' positions : fiddle (here they are just static).

the pseudocode of what I might need to acheve that :

    function update() { 
      var pointInLinePosition = calculateLastVisiblePointOfXline();
      xSprite.position.set(pointInLinePosition.x, pointInLinePosition.y, pointInLinePosition.z);
    }

    function calculateLastVisiblePointOfXline(){
    } 
ThanosSar
  • 532
  • 6
  • 20

2 Answers2

0

I found a solution which is satisfying enough (for me at least) but not perfect.

Firstly I create a frustum using the scene's camera :

var frustum = new THREE.Frustum();
frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse ) );

Then, I check if any of the planes of the frustum intersects with any of the lines I have in the scene :

for (var i = frustum.planes.length - 1; i >= 0; i--) { 

      var py = frustum.planes[i].intersectLine( new THREE.Line3( new THREE.Vector3(0,0,0), new THREE.Vector3(1000,0,0) ) ) ; 
      if(py !== undefined) {
        ySprite.position.x = py.x-1 ;  
      }

      var px = frustum.planes[i].intersectLine( new THREE.Line3( new THREE.Vector3(0,0,0), new THREE.Vector3(0,0,1000) ) ) ; 
      if(px !== undefined) {
        xSprite.position.z = px.z-1 ; 
      }

    };

If there is an intersection, I update the labels' position using the return value of the intersectLine() which is the point of intersection.

This is the updated fiddle : fiddle

I hope that helps. In my case it fit.

ThanosSar
  • 532
  • 6
  • 20
  • I did something similar and it has an issue common to your solution: The planes of the frustum extend infinitely and intersections outside the frustum can happen. So one would need to find the correct intersection. – H.B. Jan 22 '18 at 07:54
0

A correct test for intersections also has to make sure that the intersection point is actually within the frustum as the frustum planes extend indefinitely, potentially leading to false positive intersections.

One naive way of validating intersections, is checking the distance of the intersection to all planes. If the distance is greater or equal to zero, the point is within the frustum.

Adjusted code snipped from ThanosSar's answer:

const intersect = point => frustum.planes
    .map(plane =>
        plane.intersectLine(new THREE.Line3(new THREE.Vector3(0, 0, 0), point))
    )
    .filter(sect => sect != null)
    .filter(sect => frustum.planes.every(plane => plane.distanceToPoint(sect) >= -0.000001))[0];

const iy = intersect(new THREE.Vector3(1000, 0, 0));
if (iy != null)
    ySprite.position.x = iy.x - 1;

const ix = intersect(new THREE.Vector3(0, 0, 1000));
if (ix != null)
    xSprite.position.z = ix.z - 1;

(The comparison is with >= -0.000001 to account for floating point rounding errors)

Fiddle

H.B.
  • 166,899
  • 29
  • 327
  • 400