射线-三角形相交。它有两个方向

Ray-triangle intersection. It work with two directions

我不知道为什么,但光线-三角形相交算法(Möller-Trumbore 和 Watertight)适用于 2 个方向。

从头到尾 - 它必须如何工作

从头到尾——问题所在

白色十字 - 不必要的交叉路口

screenshot

我尝试使用 3 个分量向量,所以我从代码中删除了所有 W 值。

    class Ray
    {
    public:
        Ray(){}
        ~Ray(){}
    
        Vector4 m_origin;
        Vector4 m_end;
        Vector4 m_direction;
    
        void update()
        {
            m_end._f32[3] = 0.f;
            m_origin._f32[3] = 0.f;
    
            m_direction._f32[ 0 ] = m_end._f32[0] - m_origin._f32[0];
            m_direction._f32[ 1 ] = m_end._f32[1] - m_origin._f32[1];
            m_direction._f32[ 2 ] = m_end._f32[2] - m_origin._f32[2];
            m_direction._f32[ 3 ] = 0.f;
            m_direction.normalize(); // without W
        }
    };

三角与算法

    struct Triangle
    {
        Vector4 v1; // vertex 1 position
        Vector4 v2; // vertex 2 position
        Vector4 v3; // vertex 3 position
        Vector4 e1; // edge, see update()
        Vector4 e2; // edge, see update()
    
        void update()
        {
            e1 = Vector4( v2._f32[0] - v1._f32[0],
                v2._f32[1] - v1._f32[1],
                v2._f32[2] - v1._f32[2],
                0.f);
                
            e2 = Vector4( v3._f32[0] - v1._f32[0],
                v3._f32[1] - v1._f32[1],
                v3._f32[2] - v1._f32[2],
                0.f);
        }
    
        // Möller-Trumbore algorithm
        bool rayTest_MT( const Ray& ray, bool withBackFace, f32& T, f32& U, f32& V, f32& W )
        {
            Vector4  pvec = ray.m_direction.cross_return(e2);
            f32 det  = e1.dot(pvec);
            
            if( withBackFace )
            {
                if( std::abs(det) < 0.0000001f && det > -0.0000001f )
                    return false;
            }
            else
            {
                if( det < 0.0000001f && det > -0.0000001f )
                    return false;
            }
    
            Vector4 tvec(
                ray.m_origin._f32[0] - v1._f32[0],
                ray.m_origin._f32[1] - v1._f32[1],
                ray.m_origin._f32[2] - v1._f32[2],
                0.f);
    
            //tvec.setW(1.f);//...
    
            f32 inv_det = 1.f / det;
            U = tvec.dot(pvec) * inv_det;
    
            if( U < 0.f || U > 1.f )
                return false;
    
            Vector4  qvec = tvec.cross_return(e1);
            V    = ray.m_direction.dot(qvec) * inv_det;
    
            if( V < 0.f || U + V > 1.f )
                return false;
    
            T = e2.dot(qvec) * inv_det;
            W = 1.f - U - V;
            return true;
        }
    };

简单向量

Vector4
{
public:
    f32 _f32[4];

    Vector4()
    {
        _f32[ 0 ] = 0.f;
        _f32[ 1 ] = 0.f;
        _f32[ 2 ] = 0.f;
        _f32[ 3 ] = 0.f;
    }
.........

也许我需要使用 W 组件...某处没有。看我的评论。

Möller-Trumbore algorithm from scratchapixel.com

Watertight Ray/Triangle Intersection

拦截射线上的单位距离

计算的最后一个值T是射线上距射线原点的单位距离。其中 T == 0.0f 在原点,T == 1.0f 在光线末端,T > 1.0f 在光线末端之后,T < 0.0f 在光线原点之前。

因此您需要检查 T 以确保截距位于射线的正确部分。例子

  • 前面不包括原点。 return T > EPSILON;

  • 在包括原点在内的光线之前。 return T > -EPSILON;

  • 在包括起点和终点的射线上。 return T > -EPSILON && T < 1.0f + EPSILON;

  • 在不包括起点和终点的射线上。 return T > EPSILON && T < 1.0f - EPSILON;

等等...

EPSILON

我们使用 EPSILON 来处理浮点数错误,对于此算法,您可能希望使用比 EPSILON 更大的值,尤其是当光线与多边形法线之间的角度接近时90 度