设置光线(原点,方向)和三角形交点(不含glm)

时间:2013-12-30 15:39:04

标签: c++ opengl intersection raycasting

Edit3:我的问题与我预期的功能完全不同。生病让代码停留,也许这有助于某人:)(并且不要忘记调试!)。

我试图找到一条线与三角形相交的矢量。

当前状态:即使鼠标不在地板上且摄像机视图依赖(随机矩阵),也会出现随机交叉点

步骤

  1. 取消项目鼠标协调
  2. 检查线/三角交叉点
  3. 取消鼠标协调

    我检查了glm :: unproject和gluUnproject的来源并创建了这个函数。

       pixel::CVector3 pixel::CVector::unproject(
        CVector2 inPosition,
        pixel::CShape window,
        pixel::matrix4 projectionMatrix,
        pixel::matrix4 modelViewMatrix,
        float depth
        )
    {
        // transformation of normalized coordinates
        CVector4 inVector;
        inVector.x = (2.0f * inPosition.x) / window.width - 1.0f;
        inVector.y = (2.0f * inPosition.y) / window.height - 1.0f;
        inVector.z = 2.0f * depth - 1.0f;
        inVector.w = 1.0f;
    
        // multiply inverted matrix with vector
        CVector4 rayWorld = pixel::CVector::multMat4Vec4(pixel::CMatrix::invertMatrix(projectionMatrix * modelViewMatrix), inVector);
    
        CVector3 result;
        result.x = rayWorld.x / rayWorld.w;
        result.y = rayWorld.y / rayWorld.w;
        result.z = rayWorld.z / rayWorld.w;
    
    
    
        return result;
    }
    

    检查交叉路口

    pixel::CVector3 pixel::Ray::intersection(
        Ray ray,
        pixel::CVector3 v0,
        pixel::CVector3 v1,
        pixel::CVector3 v2
        )
    {
        // compute normal
        CVector3 a, b, n;
        a = v1 - v0;
        b = v2 - v0;
    
        n = ray.direction.cross(b);
    
        // find determinant
        float det = a.dot(n);
    
        if (det < 0.000001f)
        {
            std::cout << "Ray intersecting with backface triangles \n";
            return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
        }
        det = 1.0f / det;
    
        // calculate distance from vertex0 to ray origin
        CVector3 s = ray.origin - v0;
        float u = det * s.dot(n);
    
        if (u < -0.000001f || u > 1.f + 0.000001f)
        {
            std::cout << "U: Intersection outside of the triangle!\n";
            return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
        }
    
        CVector3 r = s.cross(a);
        float v = det * ray.direction.dot(r);
        if (v < -0.000001f || u + v > 1.f + 0.000001f)
        {
            std::cout << "V/U: Intersection outside of triangle!\n";
            return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
        }
    
        // distance from ray to triangle
        det = det *  b.dot(r);
    
        std::cout << "T: " << det << "\n";
    
        CVector3 endPosition;
        endPosition.x = ray.origin.x + (ray.direction.x * det);
        endPosition.y = ray.origin.y + (ray.direction.y * det);
        endPosition.z = ray.origin.z + (ray.direction.z * det);
    
        return endPosition;
    }
    

    用法

        if (event.button.button == SDL_BUTTON_RIGHT)
                {
    
                    camera->setCameraActive();
                    float mx = event.motion.x;
                    float my = window->info.height - event.motion.y;
                    // ray casting
                    pixel::Ray ray;
    
                    std::cout << "\n\n";
    
                        // near
                    pixel::CVector3 rayNear = pixel::CVector::unproject(
                        pixel::CVector::vector2(mx, my),
                        pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                        camera->camInfo.currentProjection,
                        camera->camInfo.currentView,
                        1.0f
                        );
                    // far
                    pixel::CVector3 rayFar = pixel::CVector::unproject(
                        pixel::CVector::vector2(mx, my),
                        pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                        camera->camInfo.currentProjection,
                        camera->camInfo.currentView,
                        0.0f
                        );
    
    
                    // normalized direction results in the same behavior
                    ray.origin = cameraPosition;
    
                    ray.direction = pixel::CVector::normalize(rayFar- rayNear);
    
                    std::cout << "Raycast \n";
                    std::cout << "Mouse Position: " << mx << " - " << my << "\n";
                    std::cout << "Camera Position: " << ray.origin.x << " - " << ray.origin.y << " - " << ray.origin.z << "\n";
                    std::cout << "Ray direction: " << ray.direction.x << " - " << ray.direction.y << " - " << ray.direction.z << "\n";
    
    
                    pixel::CVector3 vertOne = pixel::CVector::vector3(0.0f, 0.0f, -300.0f);
                    pixel::CVector3 vertTwo = pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
                    pixel::CVector3 vertThree = pixel::CVector::vector3(300.0f, 0.0f, 0.0f);
                    pixel::CVector3 vertFour = pixel::CVector::vector3(300.0f, 0.0f, -300.0f);
    
    
                    pixel::CVector3 rayHit = pixel::Ray::intersection(ray, vertOne, vertTwo, vertThree);
                    pixel::CVector3 rayHit2 = pixel::Ray::intersection(ray, vertThree, vertFour, vertOne);
                    std::cout << "Ray hit: " << rayHit.x << " - " << rayHit.y << " - " << rayHit.z << "\n";
                    std::cout << "Ray hit: " << rayHit2.x << " - " << rayHit2.y << " - " << rayHit2.z << "\n";
                    std::cout << "--------------------\n";
                    towerHouse->modelMatrix = pixel::CMatrix::translateMatrix(rayHit);
    

    输出

    由于我从未使用过glm :: unproject或gluUnproject,我不知道正常输出应该是什么样子,但我得到的结果如下:

    射线方向:0.109035 -0.0380502 0.0114562

    看起来不对我,但是检查我的代码与其他来源(如上所述),我没有看到错误/ s。

    Ray交叉点在某些特殊情况下工作(相机旋转),即使我没有点击地板,我也会得到交叉点。 交叉口输出从背面碰撞到三角形外部也是如此。

    所有这些错误看起来像问题的主要来源是不投影。

    正确方向的任何提示?

2 个答案:

答案 0 :(得分:1)

这个问题的答案无处可寻,但这在评论或聊天中难以解释。

首先:

            // near
            pixel::CVector3 rayNear = pixel::CVector::raycast(
                pixel::CVector::vector2(mx, my),
                pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                camera->camInfo.currentProjection,
                camera->camInfo.currentView,
                1.0f // WRONG
                );
            // far
            pixel::CVector3 rayFar = pixel::CVector::raycast(
                pixel::CVector::vector2(mx, my),
                pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                camera->camInfo.currentProjection,
                camera->camInfo.currentView,
                0.0f // WRONG
                );

窗口空间中的 0.0 ,远 1.0 (取决于深度范围,但如果您更改了深度范围,则应该已经知道这一点)。

在光线投射功能中,您有:

CVector3 result;
result.x = rayWorld.x / rayWorld.w;
result.y = rayWorld.y / rayWorld.w;
result.z = rayWorld.z / rayWorld.w;

w == 0.0有可能,此时结果还不是光线......它是 对象空间中的位置 (不是世界)。通常,您总是会使用性能良好的矩阵,但是如果您查看UnProject (...)的正式实现,您会注意到它们处理w == 0.0具有特殊返回值的情况或者设置状态标志。

            pixel::CVector3 vertOne = pixel::CVector::vector3(0.0f, 0.0f, -300.0f);
            pixel::CVector3 vertTwo = pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
            pixel::CVector3 vertThree = pixel::CVector::vector3(300.0f, 0.0f, 0.0f);
            pixel::CVector3 vertFour = pixel::CVector::vector3(300.0f, 0.0f, -300.0f);

这些顶点是什么坐标空间?大概是物体空间,这意味着如果你从相机的视点(在世界空间中定义)投射穿过远平面上的点的光线,并尝试更频繁地测试物体空间中三角形的交点不,你会想念。这是因为每个空间的原点,比例和旋转可能不同。在尝试此测试之前,您需要将这些点转换为世界空间(原始代码的floor->modelMatrix可以很好地用于此目的)。

答案 1 :(得分:1)

我追踪了问题并修复了错误。我有错误的矩阵*矩阵和矩阵*向量乘法运算符。