#c #opengl
#c #opengl
Вопрос:
Я пытался получить работающий алгоритм, который обнаруживает пересечение между лучом (представляющим пули из пистолета) и сферой вокруг врага…. Я попробовал несколько найденных в сети, но, похоже, ни один из них не работает должным образом, возможно, я делаю что-то не так…
Это тот, который я сейчас использую:
//// 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 amp;p, const Vector3 amp;d, double r, double amp;i1, double amp;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, amp;winZ);
gluUnProject(winX, winY, 1, model_view, projection, viewport, amp;dx, amp;dy, amp;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. Сузьте круг: проблема в вашем коде пересечения или в вашем состоянии чтения / интерпретации OpenGL?
2. это наверняка пересечение, поскольку линия a рисуется так, как должна, поэтому координаты мыши и проекция кажутся нормальными!
Ответ №1:
Похоже, вы что-то делаете с правилом Крамера для решения проблемы пересечения. Рассмотрим замену. Корни многочлена укажут вам точки пересечения.
Начиная с 2D-случая, мы хотим увидеть, имеет ли ортогональное (и, следовательно, минимальное) расстояние от точки P, расположенной в центре окружности C, расстояние меньше радиуса R окружности C.
В принципе. Мы находим минимальное расстояние между центром окружности и вашим лучом / линией. Как нам это сделать? Есть несколько способов.
Мы знаем, что кратчайшее расстояние — это прямая линия, которая имеет ортогональный наклон (в отрицательном повторении R2) к нашему лучу, начинающемуся в середине круга. Затем мы находим пересечение между нашими двумя линиями. если бы нам пришлось пройти больше длины R, мы находимся снаружи, и нам все равно, как далеко это.
http://mathworld .wolfram.com/Point-LineDistance2-Dimensional.html
Решение проблемы пересечения двух линий и обнаружение того, что пересечение дальше, чем R, может быть не самым эффективным подходом, но, к счастью, у wolfram есть лучший способ сделать по существу то же самое, используя математику более высокого уровня.
Теперь, рассматривая луч в 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
Короче говоря. Я нашел правило Крамера полезным в дифференциальных уравнениях только тогда, когда мои столбцы были функциями и их производными. Обычно при нахождении вронского.