c++ - Ray Cylinder intersection -
i developing ray tracing system , working, trying support more primitives (for supports: spheres, boxes, planes , triangles), , having problems cylinders.
i know intersect ray cylinder need 2 check, first body (with infinite cylinder), assume circle in 2 dimensions, in plane xz (x² + z² = r, r radius) need check y coordinate between 0 , height , need check if intersection in caps (x²+z²<=r, r radius).
my code follow (see comments more explanations)
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 = 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 smallest , >=0 t if (x1 > x2) { t=x2; } if (t < 0) { t=x1; } // if both solution <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 y-component point computed smaller 0 or bigger height => no intersection! if (point.y < 0 || point.y > m_height) { return intersection(false); } //if ray direction not pararel y plane if (ray.getdirection().y != 0.0f) //paralel { //compute t's point intersection in y plane float t3 = (0-ray.getorigin().y)/ray.getdirection().y; float t4 = (m_height-ray.getorigin().y)/ray.getdirection().y; float t2; //choose smallest , >=0 t t2 = std::min(t3,t4); if (t2 < 0) { t2 = std::max(t3,t4); } if (t2 >= 0) { // if there t >= 0 compute de point , check if point inside 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 inside cap but, t smallest? t cap or t body cylinder? // choose smallest t , check if t cap , compute normal , 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 body cylinder, compute point , return intersection point = ray.getorigin() + ray.getdirection()*t; return intersection(true, point, normal); }
this code result in following image
(as can see top cap not rendering, , want render caps also)
i have been researching , problem here:
point1.x*point1.x + point1.z*point1.z <= m_radius*m_radius
the code never enter here, here output text (generated std::cout << "point " << point1.y << " hipo " << point1.x*point1.x + point1.z*point1.z << " radio " << m_radius*m_radius << std::endl;
) firsts pixeles (that should enter in condition because first pixeles corresponds top cap)
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
as can see never hipo
< radio
i want render whole cylinder caps. can guide me render whole cylinder? (body , caps)
thanks
i assume able find intersection points between ray , cylinder surface, obtained t values along ray. similar computation find intersections planes of 2 basis.
you 2 pairs [tc0, tc1], [tp0, tp1]. if these intervals not overlap, ray doesn't hit cylinder. otherwise, largest of tc0 , tp0 tells surface hit, , t value tells where.
Comments
Post a Comment