2016-02-02 7 views
-1

Я разрабатываю систему Ray Tracing и работает, теперь я пытаюсь поддерживать более примитивные (на данный момент он поддерживает: сферы, коробки, плоскости и треугольники), и у меня возникают проблемы с цилиндрами.Перекресток Ray Cylinder

Я знаю, чтобы пересечь луч с цилиндром Мне нужно сделать две проверки, первая с телом (с этим я получаю бесконечный цилиндр), для этого я предполагаю круг в двух измерениях в плоскости 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;) из Firsts pixeles (который должен входить в таком состоянии, потому что первый pixeles соответствует верхней крышке)

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

Я хочу, чтобы сделать весь цилиндр с крышками. Может ли кто-нибудь вести меня, чтобы изобразить весь цилиндр? (Корпус и крышка)

Благодаря

+0

Какова ваша графическая структура? –

+0

Я строю трассировку лучей с нуля, я не использую рамки – RdlP

+1

Хорошо, опубликуйте [MCVE] жестко, или сделайте свой вопрос более кратким. _ «Любой совет» _ слишком расплывчатый. –

ответ

0

Я предполагаю, что вы можете найти точки пересечения между лучом и поверхностью цилиндра, полученным в т значений вдоль луча. Сделайте аналогичное вычисление, чтобы найти пересечения с плоскостями двух баз.

Вы получите две пары [tc0, tc1], [tp0, tp1]. Если эти интервалы не перекрываются, луч не попадает в цилиндр. В противном случае наибольшее из tc0 и tp0 сообщает вам, какая поверхность на самом деле попала, и это значение t указывает вам где.