c++ - 鼠标到射线 - 球体碰撞检测

标签 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 &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 函数......任何人都可以发现它们有什么问题,或者建议另一个吗?这让我发疯....

谢谢!

最佳答案

看起来您正在使用 Cramer 规则来解决交叉问题。考虑替代。多项式的根会告诉您交点。

从 2D 情况开始,我们想要查看位于圆 C 中心的点 P 的正交(因此是最小)距离是否小于圆 C 的半径 R。

基本上。我们找到圆心和您的射线/线之间的最小距离。我们如何做到这一点?有几种方法。

我们知道最短距离是一条直线,它从圆的中间开始与我们的射线具有正交斜率(在 R2 负 recip 中)。然后我们找到两条线之间的交点。如果我们不得不走的长度超过 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 时。

关于c++ - 鼠标到射线 - 球体碰撞检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8000363/

相关文章:

c++ - 为什么在虚拟继承中调用默认构造函数?

c++ - std::function 和 std::bind 做动态内存分配吗?

c++ - Visual Studio C++ - 未解析的符号 __environ

c++ - 根据模板类型在 std::to_string() 和 .toString() 之间切换

c++ - OpenGL 在正交和透视之间切换

c++ - Valgrind 在 ATI 上运行 opengl 程序时报告很多错误 - 我应该担心吗?

OpenGL 围绕一个点旋转相机

c++ - 在 OpenGL 中使用 std::vector 作为顶点/元素列表

c++ - 我如何递归地重写这个?

c++ - QOpenGLFramebufferObject绑定(bind)纹理