【问题标题】:Ray Cylinder intersection射线圆柱相交
【发布时间】:2016-05-11 22:06:54
【问题描述】:

我正在开发一个光线追踪系统并且它正在工作,现在我正在尝试支持更多的基元(目前它支持:球体、长方体、平面和三角形),但我遇到了圆柱体问题。

我知道要将射线与圆柱体相交,我需要进行两次检查,第一次是与身体(我得到一个无限圆柱体),为此我假设在平面 xz (x² + z²) 中的二维圆= r,其中 r 是半径)然后我需要检查 Y 坐标是否在 0 和高度之间,最后我需要检查交叉点是否在大写字母中(x²+z²

我的代码如下(更多解释见 cmets)

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);
}

此代码生成以下图像

(如您所见,顶盖未渲染,我也想渲染大写)

我一直在研究,问题如下:

point1.x*point1.x + point1.z*point1.z &lt;= m_radius*m_radius

代码从不在这里输入,这里是第一个像素的输出文本(由std::cout &lt;&lt; "point " &lt;&lt; point1.y &lt;&lt; " hipo " &lt;&lt; point1.x*point1.x + point1.z*point1.z &lt;&lt; " radio " &lt;&lt; m_radius*m_radius &lt;&lt; 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

我想用盖子渲染整个圆柱体。谁能指导我渲染整个圆柱体? (身体和帽子)

谢谢

【问题讨论】:

  • 你的图形框架到底是什么?
  • 我正在从头开始构建光线追踪,我没有使用框架
  • 好吧,发帖minimal reproducible example,或者让你的问题更简洁。 “任何建议” 太模糊了。
  • 不清楚,你有什么问题?
  • 我添加了最后一个问题,而不是“有什么建议吗?”。问题是如何用盖子渲染整个圆柱体?

标签: c++ graphics raytracing


【解决方案1】:

我假设您能够找到射线和圆柱表面之间的交点,这些交点是沿射线获得的 t 值。做类似的计算,找到与两个基平面的交点。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多