Raycasting of Sprites Does Not Account for Center and Scale

Raycasting for sprites does not work in a lot of different circumstances. When the center of the sprite is altered, the area that the raycaster checks moves with it. So, the circle that is being checked (raycasting of a sprite just checks a disc around the center) is located around the new center. This means that instead of the circle covering a large portion of the sprite it really only covers the one corner (while also covering a large area that is actually not inside of the sprite). Please see my beautiful art below for reference:

— Center at (0.5, 0.5)
drawing

— Center at (0, 0)
drawing 1

I originally tried to fix it by doing some math in the raycast function (code below), but this math only works if the camera is not rotated. Once the camera rotates obviously the sprite is no longer oriented solely in the XY plane.

// Raycast override function

function() {
      var intersectPoint = new THREE.Vector3();
      var worldPosition = new THREE.Vector3();
      var worldScale = new THREE.Vector3();

      return function raycast(raycaster, intersects) {
        worldPosition.setFromMatrixPosition(this.matrixWorld);
        worldScale.setFromMatrixScale(this.matrixWorld);

       worldPosition.x =
          (0.5 - this.center.x) * worldScale.x + worldPosition.x;
        worldPosition.y =
          (0.5 - this.center.y) * worldScale.y + worldPosition.y;
        raycaster.ray.closestPointToPoint(worldPosition, intersectPoint);

        if (Math.abs(worldPosition.x - intersectPoint.x) > worldScale.x / 2) {
          return;
        }
        if (Math.abs(worldPosition.y - intersectPoint.y) > worldScale.y / 2) {
          return;
        }

        var distance = raycaster.ray.origin.distanceTo(intersectPoint);

        if (distance < raycaster.near || distance > raycaster.far) return;

        intersects.push({
          distance: distance,
          point: intersectPoint.clone(),
          face: null,
          object: this,
        });
      };
    })();

I’m going to also throw something up on StackExchange to see if someone has a quick fix for me, but for the long term fix I figured that this deserved a bug report. In general the center and scale values of a sprite need to be used to properly detect a raycast.

Three.js version
  • Dev
  • r91
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • macOS
  • Linux
  • Android
  • iOS
Hardware Requirements (graphics card, VR Device, …)

Author: Fantashit

1 thought on “Raycasting of Sprites Does Not Account for Center and Scale

  1. when ever I need something sprite-like and clickable, I just end up using a plane with .quaternion.copy(camera.quaternion) in .updateMatrixWorld or somewhere. this way you use same raycast code that you use for meshes.

    another bonus is that you are free to change shaders to whatever you want (without hax).

Comments are closed.