我一直试图找到一种可以检测射线(代表枪支子弹)和敌人周围球体之间交叉点的工作算法....我尝试了一些在网上找到的但是似乎都没有正常工作,也许我做错了什么......
这是我目前正在使用的那个:
//// 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));
他们都被略微修改以匹配我正在使用的库中的Math函数....任何人都可以发现它们有问题,或者建议另一个吗?这让我发疯了......
谢谢!
答案 0 :(得分:2)
看起来你正在用Cramer的规则来解决交叉问题。考虑替代。多项式的根将告诉你交点。
从2D情况开始我们想要的是查看位于圆C中心的点P的正交(因此最小)距离是否小于圆C的半径R. / p>
基本上。我们找到圆心与光线/线之间的最小距离。我们如何做到这一点?有几种方法。
我们知道最短距离是一条直线,它具有从圆形中间开始的正交斜率(在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
简而言之。当我的列是函数及其派生词时,我才发现Cramer的规则对微分方程很有帮助。通常在找到Wronskian时。