Recently I have been trying to implement picking via mouse ray. I made a little project with three spheres in it and I simply check for ray-sphere intersection. If there is such, I have a sphere to pick. After I made everything to work fine with that little project I tried to implement this in a bigger one. The bigger project is a solar systems creator. However, when I try to select a sun(that is the only thing I need to be selected) the selection won't work. Below I am posting the code for the solution.
First, the intersection test:
bool CelestialBody::IsClickedOn(Ray mouseRay)
{
float a = DotProduct(mouseRay.GetDirection(), mouseRay.GetDirection());
float b = 2 * DotProduct(mouseRay.GetOrigin(), mouseRay.GetDirection());
float c = DotProduct(mouseRay.GetOrigin(), mouseRay.GetOrigin()) - this->radius * this->radius;
float discriminant = b * b - 4 * a * c;
std::cout<<discriminant<<std::endl;
if(discriminant < 0)
{
return false;
}
return true;
}
Second, the mouse click code:
if(userMouse.IsLeftButtonDown())
{
int cursorX = int(userMouse.GetCurrentPosition().GetX());
int cursorY = int(userMouse.GetCurrentPosition().GetY());
Vector3d nearPoint = userCamera.GetPosition();
Vector3d farPoint = MouseClass::ConvertMouseToOGLCoordinate(cursorX, cursorY, 1.0f);
Vector3d direction = farPoint - nearPoint;
direction.Normalize();
std::vector<std::string> parentNames = sceneLayout->GetParentNames();
int size = parentNames.size();
for(int i = 0; i < size; i++)
{
Vector3d parentBodyPos = sceneLayout->GetCelestialBodyPosition(parentNames);
Vector3d origin = nearPoint - parentBodyPos;
CelestialBody *currentBody = sceneLayout->GetCelestialBody(parentNames);
mouseRay = Ray(origin, direction);
bool isCollided = currentBody->IsClickedOn(mouseRay);
if(isCollided)
{
currentBody->SetColor(Color(0, 0, 255));
}
else
{
currentBody->SetColor(Color(255, 250, 255));
}
}
//userMouse.ReleaseLeftButton();
}
And at last, the ConvertMouseToOGLCoordinate() function code:
Vector3d MouseClass::ConvertMouseToOGLCoordinate(int mouseX, int mouseY, int mouseZ)
{
GLint viewport[4];
GLdouble modelMatrix[16];
GLdouble projectionMatrix[16];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);float winY = float(viewport[3] - mouseY);
double x, y, z;
gluUnProject((double)mouseX, winY, mouseZ,
modelMatrix, projectionMatrix, viewport,
&x, &y, &z);
return Vector3d(x, y, z);
}
These are the snippets which correspond to the little project's code.
The thing I suspect to crash the algorithm is the position from which I view the scene. My camera coords are (0.0; 9000.0; 0.0) and when I switch from side view (0.0, 0.0, 9000.0) I am able to pick one of the planets. On the little project, however, I am able to pick from whatever position my camera is.
I know I haven't explained things good enough but that is all I can do... If you want the whole code of both projects, I will supply you with it .