Is mouse over sphere in 3D?

I have a sphere somewhere, and its location is known. However, I'm also using PeasyCam, so a problem remains - I don't know the camera vectors. So, how to check if the mouse (or any other vector for that) is over the sphere?

My code so far-

import peasy.*;

PeasyCam cam;

float x = 0, y = 0,z = 0;

void setup(){
  size(720, 720, P3D);
  cam = new PeasyCam(this, 200);
}

void draw(){
  translate(x, y, z);
  sphere(100);//being minimalistic

  x += sin(y);//random methods, real code is different
  y += cos(z);
  z += random(1);

  println(mouseOverSphere(x, y, z, 100);
}

boolean mouseOverSphere(float posX, float posY, float posZ, float size){
  //What to do here??
}
Tagged:

Answers

  • Answer ✓

    Look at screenX, screenY iirc

  • @Chrisir I did look at screenX and screenY, but I didn't understand what to do next.
    Thanks anyway.

  • Not sure if it works with peasycam

    Look my post here I made a full sketch

    https://forum.processing.org/two/discussion/comment/84835/#Comment_84835

  • @Chrisir Thanks, I'll check that out.

  • edited January 2017 Answer ✓

    Edit: this wasn't quite correct! updated

    Normally I would expect the silhouette (collision screen area) of a translated sphere to be almost equal to an orthogonal circle of the same radius facing the viewer. In the real world this tends to be true of any sphere that you aren't really close to (or that isn't larger than your field of vision) -- the visible tangents to the edge of the sphere are very close to the equator. If you know the origin of the sphere (using modelX / screenX) you can find whether the mouse point is inside the corresponding ellipse using the formula for point-circle collision detection.

    HOWEVER this is slightly off in the default P3D view, and it is dramatically off in the PeasyCam default view. Its 0,0,0 has an up-close perspective that causes the equator line of a sphere to be rendered much smaller (significantly behind) its silhouette -- like if you were holding a baseball 3 inches from your face -- and this is offset with perspective. Both things can create a substantial mismatch region if you try to approximate sphere collision detection using a circular silhouette anywhere in PeasyCam -- even a head-on shot drawn from 0,0,0 will be inaccurate (see screenshot).

    To see this in action in this test sketch rotate the sphere with the mouse, and press any key for a new sphere location. Although the ellipse is clearly bisecting the sphere, you can never make it align with the silhouette of the sphere anywhere in PeasyCam space, no matter how you rotate it.

    import peasy.*;
    PeasyCam cam;
    PVector sph; 
    int size = 75;
    
    void setup(){
      size(400, 400, P3D);
      noFill();
      cam = new PeasyCam(this, 200);
      sph = new PVector(0,0,0);
    }
    
    void draw(){
      background(192);
      translate(sph.x,sph.y,sph.z);
      sphere(size);
      pushStyle();
        strokeWeight(4);
        stroke(255,0,0);
        fill(255,0,0,64);
        ellipse(0,0,size*2+1,size*2+1);
      popStyle(); 
    }
    
    void randomTranslate(){
      sph.x = random(-size,size);
      sph.y = random(-size,size);
      sph.z = 0;
    }
    
    void keyPressed(){
      cam.reset();
      randomTranslate();
    }
    

    Making the ellipse bigger by any fudge factor also won't fix this issue.

    One alternate solution is:

    1. Render a solid white sphere to a PGraphics buffer
    2. check for collision by checking the mouse location against a pixel value in that buffer.
    3. if it is white, report a hit.
  • Thanks @jeremydouglass and @Chrisir.
    So I guess the best way would be what jeremydouglass suggested.
    And I'm not entirely sure how to adapt Chrisir's code to suit my needs, but I'll do that later on.

  • For more on the perspective-correction of the circle silhouette in OpenGL, see the comments on this here -- although no specific solution is proposed, it is just noted that it needs to be corrected:

  • According to some comments there, I believe even camera() function in Processing should just multiply the current transformation matrix with some "camera" matrix. Am I right?

Sign In or Register to comment.