c++ - 射线柱相交

标签 c++ graphics raytracing

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

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

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

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

我想渲染整个带帽的圆柱体。谁能指导我渲染整个圆柱体? ( body 和帽子)

谢谢

最佳答案

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

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

关于c++ - 射线柱相交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35164707/

相关文章:

c++ - 在 c++ w/directx 中测试正方形是否与多边形重叠(可选)

java - Java 中的矩阵和 vector 数组

c++ - 虽然我们放弃了大 O 符号中的常数,但它在现实生活中重要吗?

c++ - 使用 std::tie 比较结构

java - 为什么我的 RenderingHints 键在应用于 Graphics2D 对象时不被遵守?

java - 在 Java Graphics2D 中获取字符串边界的问题

render - 为什么我的蒙特卡洛光线追踪如此嘈杂?

c++ - C++ 中的通用(几乎)自描述参数与 GUI 相结合?

c++ - 当我尝试将一对插入 map 时,Qt 程序出现段错误

java - 如何在java中绘制gif动画?