мышь к лучу - обнаружение столкновения сферы - PullRequest
2 голосов
/ 03 ноября 2011

Я пытался получить работающий алгоритм, который обнаруживает пересечение между лучом (представляющим пули из оружия) и сферой вокруг врага .... Я попробовал несколько найденных в сети, но ни один, кажется, не работает должным образом , может я что-то не так делаю ...

Это то, что я сейчас использую:

    //// Ray-sphere intersection. 
    // p=(ray origin position - sphere position),
    // d=ray direction,
    // r=sphere radius,
    // Output:
    // i1=first intersection distance,
    // i2=second intersection distance
    // i1<=i2
    // i1>=0
    // returns true if intersection found,false otherwise.// 


    bool Player::RaySphereIntersect(const Vector3 &p, const Vector3 &d, double r,                 double  &i1, double &i2){ 
double det,b;   
b = -Vector3::dot(p,d); 
det = b*b - Vector3::dot(p,p) + r*r;    
if (det<0){     
    return false;   
}   
det= sqrt(det); 
i1= b - det;    
i2= b + det;    

// intersecting with ray?   
if(i2<0) 
    return false;   
if(i1<0)
    i1=0;   
return true;
    }

Где я использую положение врага в качестве позиции сферы, примерно положение оружия игрока в качестве источника луча и проецируемые координаты мыши для направления луча ... Это код OpenGL, который я использую для проецирования координат мыши на дальний самолет:

    Vector3 projectedMouse(float mx, float my){

GLdouble model_view[16];
GLint viewport[4];
GLdouble projection[16];

GLfloat winX, winY, winZ;
GLdouble dx, dy, dz, bx, by, bz;

glGetDoublev(GL_MODELVIEW_MATRIX, model_view);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);

winX = (float)mx;
 winY = (float)viewport[3] - (float)my;

glReadPixels ((int)mx, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); 
gluUnProject(winX, winY, 1, model_view, projection, viewport, &dx, &dy, &dz);

projectedAim = Vector3(dx, dy, dz);

return projectedAim;
    }

Что кажется правильным, потому что я рисую линию GL с ней, и она выглядит нормально ... Так что, может быть, это код пересечения, но, похоже, ничего не работает .... Я пробовал другой, который должен возвращать расстояние до точки пересечения , но для любой данной позиции противника это все еще дает мне очень случайные результаты:

    double intersectRaySphere(Vector3 rO, Vector3 rV, Vector3 sO, double sR) 
       Vector3 Q = sO-rO;
       double c = Q.magnitude();
       double v = Vector3::dot(Q,rV);
       double d = sR*sR - (c*c - v*v);

       // If there was no intersection, return -1
       if (d < 0.0) return (-1.0f);

       // Return the distance to the [first] intersecting point
       return (v - sqrt(d));

они оба были слегка изменены, чтобы соответствовать математической функции в библиотеке, которую я использую ... Кто-нибудь может заметить что-то не так с ними или предложить другую? это сводит меня с ума ....

Спасибо!

1 Ответ

2 голосов
/ 05 ноября 2011

Похоже, вы что-то делаете с правилом Крамера, чтобы найти перекресток. Рассмотрим замену. Корни многочлена скажут вам точки пересечения.

Начиная с двумерного случая, мы хотим видеть, имеет ли ортогональное (и, следовательно, минимальное) расстояние точки P, расположенной в центре круга C, расстояние меньше радиуса R круга C.

в основном. Мы находим минимальное расстояние между центром круга и вашим лучом / линией. как нам это сделать? Есть несколько способов.

Мы знаем, что кратчайшее расстояние - это прямая линия с ортогональным наклоном (в отрицательном отклике R2) к нашему лучу, начинающемуся в середине круга. Затем мы находим пересечение между нашими двумя линиями. если бы нам пришлось идти больше, чем на длину R, мы находимся снаружи, и нам все равно, насколько далеко.

http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html

Решение пересечения двух линий и видение его пересечения дальше, чем R, возможно, не самый эффективный подход, но, к счастью, у Вольфрама есть лучший способ сделать то же самое, используя математику более высокого уровня.

Теперь, учитывая, что луч в R3, пересекающий сферу, это в основном то же самое, но «ортогональный» сложнее угодить, чем в R2, поэтому мы используем двойные перекрестные произведения. и решить параметрические уравнения.

http://www.cs.umbc.edu/~olano/435f02/ray-sphere.html

Это умный способ проверить, удовлетворяет ли какая-либо часть нашего луча уравнению нашей сферы в качестве ограничения.

float a = Vector3::dot(d,d);
float b = Vector3::dot(d * 2, p); 
float c = Vector3::dot(p,p) - r*r
// if the discriminant of the quadratic formula is positive
// we have at least one intersection
return (b*b - 4 * a * c) >= 0 

Короче. Я нашел правило Крамера полезным в дифференциальных уравнениях только тогда, когда мои столбцы были функциями и их производными. Обычно при поиске вронскиана.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...