用光线投射对象拾取

sle*_*ler 9 opengl casting mouse-picking ray-picking

我在使用光线投射算法检测盒子中的鼠标命中时遇到了不准确的问题.我完全不知道如何正确地解决这个问题,这让我困扰了好几个星期.

使用图片(以[0,0,-30]为中心的框)最容易描述问题:

屏幕截图的问题

黑色线代表绘制的实际hitbox,绿色框代表实际看起来被击中的内容.注意它是如何偏移的(如果盒子离原点更远,它似乎变得更大)并且略小于绘制的hitbox.

这是一些相关的代码,

光线投射:

double BBox::checkFaceIntersection(Vector3 points[4], Vector3 normal, Ray3 ray) {

    double rayDotNorm = ray.direction.dot(normal);
    if(rayDotNorm == 0) return -1;

    Vector3 intersect = points[0] - ray.origin;
    double t = intersect.dot(normal) / rayDotNorm;
    if(t < 0) return -1;

    // Check if first point is from under or below polygon
    bool positive = false;
    double firstPtDot = ray.direction.dot( (ray.origin - points[0]).cross(ray.origin - points[1]) );
    if(firstPtDot > 0) positive = true;
    else if(firstPtDot < 0) positive = false;
    else return -1;

    // Check all signs are the same
    for(int i = 1; i < 4; i++) {
        int nextPoint = (i+1) % 4;
        double rayDotPt = ray.direction.dot( (ray.origin - points[i]).cross(ray.origin - points[nextPoint]) );
        if(positive && rayDotPt < 0) {
            return -1;
        }
        else if(!positive && rayDotPt > 0) {
            return -1;
        }
    }

    return t;
}
Run Code Online (Sandbox Code Playgroud)

鼠标到光线:

GLint viewport[4];
GLdouble modelMatrix[16];
GLdouble projectionMatrix[16];

glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);

GLfloat winY = GLfloat(viewport[3] - mouse_y);

Ray3 ray;
double x, y, z;
gluUnProject( (double) mouse_x, winY, 0.0f, // Near
              modelMatrix, projectionMatrix, viewport,
              &x, &y, &z );
ray.origin = Vector3(x, y, z);

gluUnProject( (double) mouse_x, winY, 1.0f, // Far
              modelMatrix, projectionMatrix, viewport,
          &x, &y, &z );
ray.direction = Vector3(x, y, z);

if(bbox.checkBoxIntersection(ray) != -1) {
    std::cout << "Hit!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我已经尝试将实际光线绘制成一条线,它似乎正确地与绘制的框相交.

我通过将所有点和光线原点/方向按箱位置缩小而部分修复了偏移问题,但我不知道为什么这样可行并且命中箱的大小仍然不准确.

任何想法/替代方法?如果需要,我还有其他代码供应.

dat*_*olf 11

你假设方向错了.正确的是:

ray.direction = Vector3(far.x - near.x, far.y - near.y, far.z - near.z);
Run Code Online (Sandbox Code Playgroud)

在不减去近交叉点和远交点的情况下,您的方向将会消失.