Ray Cylinder交叉口

时间:2016-02-02 22:07:40

标签: c++ graphics raytracing

我正在开发一个Ray Tracing系统并且它正在工作,现在我正在尝试支持更多原语(现在它支持:球体,盒子,平面和三角形),而且我遇到了圆柱体问题。

我知道将光线与圆柱相交我需要做两次检查,第一次是用本体(我得到一个无限圆柱体),为此我假设二维圆,在平面xz(x²+z²) = r,其中r是半径)然后我需要检查Y坐标是否在0和高度之间,最后我需要检查交叉点是否在大写字母中(x²+z²&lt; = r,其中r是半径)。< / p>

我的代码如下(有关更多解释,请参阅注释)

Intersection Cylinder::hit(Ray ray)
{
    ray.setOrigin(vec3(getInverseTransform() * vec4(ray.getOrigin(),1)));
    ray.setDirection(glm::normalize(vec3(getInverseTransform() * vec4(ray.getDirection(),0))));

    // R(t) = o + td
    // x² + z² = r²
    // (ox+tdx)² + (oz+tdz)² = r²
    // (ox)² + 2oxtdx + (tdx)² + (oz)² + 2oztdz + (tdz)² = r²
    // t²(dx + dz) + 2t(oxdx + ozdz) + (ox)² + (oz)² - r² = 0
    // a=(dx + dz); b = 2(oxdx + ozdz); c = (ox)² + (oz)² - r²
    float a = ray.getDirection().x*ray.getDirection().x + ray.getDirection().z*ray.getDirection().z;
    float b = 2*(ray.getOrigin().x*ray.getDirection().x + ray.getOrigin().z*ray.getDirection().z);
    float c = ray.getOrigin().x*ray.getOrigin().x + ray.getOrigin().z*ray.getOrigin().z - m_radius*m_radius;

    float discr = b*b - 4*a*c;
    if (discr < 0)
    {
        return Intersection(false);
    }

    float x1 = (-b+sqrt(discr))/(2*a);
    float x2 = (-b-sqrt(discr))/(2*a);

    float t;
    //choose the smallest and >=0 t
    if (x1 > x2)
    {
        t=x2;
    }

    if (t < 0)
    {
        t=x1;
    }


    // if both solution are <0 => NO INTERSECTION!
    if (t<0)
    {
        return Intersection(false);
    }

    // normal calculation
    // f(x,y) = x² + z² - r² = 0
    // T = (dx/dt, y, dz/dt)
    // 0 = df/dt = (df/dx, y, df/dz) · T
    // N = (2x, 0, 2z)
    vec3 point = ray.getOrigin() + ray.getDirection()*t;
    vec3 normal = vec3(2*point.x, 0.0f, 2*point.z);


    // If the y-component from point computed is smaller than 0 or bigger than height => NO INTERSECTION!
    if (point.y < 0 || point.y > m_height)
    {
        return Intersection(false);
    }

    //If ray direction is not pararel to Y Plane
    if (ray.getDirection().y != 0.0f) //Paralel
    {
        //Compute t's for point intersection in the Y Plane
        float t3 = (0-ray.getOrigin().y)/ray.getDirection().y;
        float t4 = (m_height-ray.getOrigin().y)/ray.getDirection().y;
        float t2;

        //choose the smallest and >=0 t
        t2 = std::min(t3,t4);
        if (t2 < 0)
        {
            t2 = std::max(t3,t4);
        }
        if (t2 >= 0)
        {
            // If there is a t >= 0 compute de point and check if the point is inside the cap
            vec3 point1 = ray.getOrigin() + ray.getDirection()*t2;
            std::cout << "point " << point1.y << " hipo "  << point1.x*point1.x + point1.z*point1.z << " radio " << m_radius*m_radius << std::endl;
            if (point1.x*point1.x + point1.z*point1.z <= m_radius*m_radius+0.9f)
            {
                // Intersection point is inside cap but, Which t is the smallest? t from cap or t from body cylinder?
                // I choose the smallest t and check if the t is from cap and compute normal and return intersection.
                t = std::min(t,t2);
                if (t == t3)
                {
                    normal = vec3(0.0f,-1.0f,0.0f);
                    return Intersection(true, point1, normal);
                }
                else if (t == t4)
                {
                    normal = vec3(0.0f,1.0f,0.0f);
                    return Intersection(true, point1, normal);
                }
            }
        }
    }

    // Intersection in the body cylinder, compute the point and return the intersection
    point = ray.getOrigin() + ray.getDirection()*t;

    return Intersection(true, point, normal);
}

此代码导致以下图像

enter image description here

(正如你可以看到顶帽没有渲染,我也想渲染大写)

我一直在研究,问题看起来像这样:

point1.x*point1.x + point1.z*point1.z <= m_radius*m_radius

代码永远不会进入这里,这里是输出文本(由std::cout << "point " << point1.y << " hipo " << point1.x*point1.x + point1.z*point1.z << " radio " << m_radius*m_radius << std::endl;生成)来自第一个像素(由于第一个像素与顶帽相对应,应该进入该条件)

point 0.5 hipo 0.0900812 radio 0.09
point 0.5 hipo 0.0900206 radio 0.09
point 0.5 hipo 0.0900812 radio 0.09
point 0.5 hipo 0.0900206 radio 0.09
Pixel: y: 280
point 0.5 hipo 0.0913921 radio 0.09
point 0.5 hipo 0.120013 radio 0.09
point 0.5 hipo 0.0913921 radio 0.09
point 0.5 hipo 0.120013 radio 0.09
Pixel: y: 281
point 0.5 hipo 0.0930369 radio 0.09
point 0.5 hipo 0.183345 radio 0.09
point 0.5 hipo 0.0930369 radio 0.09
point 0.5 hipo 0.183345 radio 0.09
Pixel: y: 282
point 0.5 hipo 0.0950108 radio 0.09
point 0.5 hipo 0.261889 radio 0.09
point 0.5 hipo 0.0903952 radio 0.09
point 0.5 hipo 0.0903952 radio 0.09
point 0.5 hipo 0.0950108 radio 0.09
point 0.5 hipo 0.261889 radio 0.09
Pixel: y: 283
point 0.5 hipo 0.0973093 radio 0.09
point 0.5 hipo 0.347767 radio 0.09
point 0.5 hipo 0.0927148 radio 0.09
point 0.5 hipo 0.0927148 radio 0.09
point 0.5 hipo 0.0973093 radio 0.09
point 0.5 hipo 0.347767 radio 0.09

正如您所见,hipo并非如此。比radio

我想用帽子渲染整个圆柱体。任何人都可以引导我渲染整个圆柱吗? (身体和帽子)

由于

1 个答案:

答案 0 :(得分:0)

我假设你能够找到光线和圆柱面之间的交点,它们是沿着光线获得的t值。做一个类似的计算,找到两个基础的平面的交点。

你会得到两对[tc0,tc1],[tp0,tp1]。如果这些间隔不重叠,则光线不会碰到圆柱体。否则,tc0和tp0中最大的一个告诉你实际命中了什么表面,这个t值告诉你在哪里。