Asmodeus

07-13-2015, 06:15 AM

Hello, I would like to ask some theoretical Questions here , combined with some pseudo code to explain what i need or mean. So recently i implemented traditional ray casting from the camera's position into the scene. I will devide my post in 2 parts:

PART ONE:

Ray Unprojecting from far to near plane

float mouse_x = (float)InputState::getMOUSE_X();

float mouse_y = WINDOW_HEIGHT - (float)InputState::getMOUSE_Y();

glm::vec4 viewport = glm::vec4(0.0f, 0.0f, WINDOW_WIDTH, WINDOW_HEIGHT);

this->ray_start = glm::unProject(glm::vec3(mouse_x, mouse_y, 0.0f), camera->getViewMatrix(), Projection, viewport);

this->ray_end = glm::unProject(glm::vec3(mouse_x, mouse_y, 1.0f), camera->getViewMatrix(), Projection, viewport);

Then i implemented a simple function to detect if the ray has collided with a bounding sphere.

glm::vec3 vSphereCenter = Sphere->getCenter();

glm::vec3 vA = this->ray_start;

glm::vec3 vB = this->ray_end;

float fSphereRadius = Sphere->getRadius();

glm::vec3 vDirToSphere = vSphereCenter - vA;

glm::vec3 vLineDir = glm::normalize(vB - vA);

float fLineLength = glm::distance(vA, vB);

float t = glm::dot(vDirToSphere, vLineDir);

glm::vec3 vClosestPoint;

if (t <= 0.0f)

vClosestPoint = vA;

else if (t >= fLineLength)

vClosestPoint = vB;

else

vClosestPoint = vA + vLineDir*t;

return glm::distance(vSphereCenter, vClosestPoint) <= fSphereRadius;

So far so good. The code above works. Here starts my broken "theory" / "questions". Let's say that we have a scene that consists of models. All models have some auto-generated bounding spheres. So we want to check whitch object the player has "clicked" on , or the object the ray intersects with.First when i was thinking about this. I didnt think that several models can be in a line (in each axis), thats why you should loop over all the models that have been hit and find the closest to the camera. Look at the pseudo code mix below, added some comments as well.

//Here i present you the Pseudo C++ mix :D

std::vector<models> scene_models; //All Models in the scene

std::vector<models> selected_models; //All models that have been hit by the ray

//Loop over every model find where the ray intersects

for(i,scene_models.size())

{

if(RayIntersectsWith(model[i]->getBoundSphere())

{

selected_models.pushback(model[i])

}

}

//Loop over all intersected model and find the one closest to the camera

for(i,selected_models.size())

{

//get the distance(camera->pos,selected_models[i]->getBoundSphere()->getCenter());

//Find the one closest to the camera = closest_model_to_the_camera;

}

//Do something with closest_model_to_the_camera

My Question is as follows: Is this the right way to go ? Would it work ? Is there a more efficient way to apply this ?

PART TWO

This part is not connected with the part one. Here i wanted to ask how would one implement terrain responsive ray. A ray that can return the world coords on a 3D Terrain. Currently i have something that works , but not that well. At the moment i am using the ray and performing a binary search to find the point on the terrain

//What i mean by binary search:

Take the starting point of the ray. Set Ray Lenght.

1. Take the middle point of the ray.

2. Determine if that point is above of below the terrain

3. if the point is below the terrain take the upper half / else take the lower half of the ray

4. Repeat N times steps 1-4. (Recursivly)

//This is not very accurate nor efficient way but does find the exact world position on the terrain, the more times(the bigger the N) you repeat the process the more accurate the result is.

. And it does work , the only problem is that i have to use big camera angle (~near 90 degrees). The terrain i am using is generated from a height map.

My question is: Is there some stable, reliable way to return the world coordinates on terrain from the ray.

PART ONE:

Ray Unprojecting from far to near plane

float mouse_x = (float)InputState::getMOUSE_X();

float mouse_y = WINDOW_HEIGHT - (float)InputState::getMOUSE_Y();

glm::vec4 viewport = glm::vec4(0.0f, 0.0f, WINDOW_WIDTH, WINDOW_HEIGHT);

this->ray_start = glm::unProject(glm::vec3(mouse_x, mouse_y, 0.0f), camera->getViewMatrix(), Projection, viewport);

this->ray_end = glm::unProject(glm::vec3(mouse_x, mouse_y, 1.0f), camera->getViewMatrix(), Projection, viewport);

Then i implemented a simple function to detect if the ray has collided with a bounding sphere.

glm::vec3 vSphereCenter = Sphere->getCenter();

glm::vec3 vA = this->ray_start;

glm::vec3 vB = this->ray_end;

float fSphereRadius = Sphere->getRadius();

glm::vec3 vDirToSphere = vSphereCenter - vA;

glm::vec3 vLineDir = glm::normalize(vB - vA);

float fLineLength = glm::distance(vA, vB);

float t = glm::dot(vDirToSphere, vLineDir);

glm::vec3 vClosestPoint;

if (t <= 0.0f)

vClosestPoint = vA;

else if (t >= fLineLength)

vClosestPoint = vB;

else

vClosestPoint = vA + vLineDir*t;

return glm::distance(vSphereCenter, vClosestPoint) <= fSphereRadius;

So far so good. The code above works. Here starts my broken "theory" / "questions". Let's say that we have a scene that consists of models. All models have some auto-generated bounding spheres. So we want to check whitch object the player has "clicked" on , or the object the ray intersects with.First when i was thinking about this. I didnt think that several models can be in a line (in each axis), thats why you should loop over all the models that have been hit and find the closest to the camera. Look at the pseudo code mix below, added some comments as well.

//Here i present you the Pseudo C++ mix :D

std::vector<models> scene_models; //All Models in the scene

std::vector<models> selected_models; //All models that have been hit by the ray

//Loop over every model find where the ray intersects

for(i,scene_models.size())

{

if(RayIntersectsWith(model[i]->getBoundSphere())

{

selected_models.pushback(model[i])

}

}

//Loop over all intersected model and find the one closest to the camera

for(i,selected_models.size())

{

//get the distance(camera->pos,selected_models[i]->getBoundSphere()->getCenter());

//Find the one closest to the camera = closest_model_to_the_camera;

}

//Do something with closest_model_to_the_camera

My Question is as follows: Is this the right way to go ? Would it work ? Is there a more efficient way to apply this ?

PART TWO

This part is not connected with the part one. Here i wanted to ask how would one implement terrain responsive ray. A ray that can return the world coords on a 3D Terrain. Currently i have something that works , but not that well. At the moment i am using the ray and performing a binary search to find the point on the terrain

//What i mean by binary search:

Take the starting point of the ray. Set Ray Lenght.

1. Take the middle point of the ray.

2. Determine if that point is above of below the terrain

3. if the point is below the terrain take the upper half / else take the lower half of the ray

4. Repeat N times steps 1-4. (Recursivly)

//This is not very accurate nor efficient way but does find the exact world position on the terrain, the more times(the bigger the N) you repeat the process the more accurate the result is.

. And it does work , the only problem is that i have to use big camera angle (~near 90 degrees). The terrain i am using is generated from a height map.

My question is: Is there some stable, reliable way to return the world coordinates on terrain from the ray.