From cf4ba27ee9c8d1e4585325ba506ae9428b9a2397 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 20 Mar 2014 12:29:49 +0100 Subject: [PATCH 1/3] fix an error in the hair intersection code reported by Pramook Khungurn --- src/shapes/hair.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shapes/hair.cpp b/src/shapes/hair.cpp index cfd791f4..4aef8248 100644 --- a/src/shapes/hair.cpp +++ b/src/shapes/hair.cpp @@ -527,7 +527,7 @@ public: dot(pointFar - v2, n2) <= 0) { if (farT > maxt) return false; - p = Point(rayO + rayD * nearT); + p = Point(rayO + rayD * farT); t = (Float) farT; } else { return false; From 0c20766291ca8a25a3596ff439567a50fb5a4c10 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 20 Mar 2014 12:30:28 +0100 Subject: [PATCH 2/3] slightly improved accuracy of intersection computations in the the cylinder shape --- src/shapes/cylinder.cpp | 50 ++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/shapes/cylinder.cpp b/src/shapes/cylinder.cpp index 51725014..27bfaf26 100644 --- a/src/shapes/cylinder.cpp +++ b/src/shapes/cylinder.cpp @@ -131,32 +131,32 @@ public: /* Transform into the local coordinate system and normalize */ m_worldToObject(_ray, ray); - const Float + const double ox = ray.o.x, oy = ray.o.y, dx = ray.d.x, dy = ray.d.y; - const Float A = dx*dx + dy*dy; - const Float B = 2 * (dx*ox + dy*oy); - const Float C = ox*ox + oy*oy - m_radius*m_radius; + const double A = dx*dx + dy*dy; + const double B = 2 * (dx*ox + dy*oy); + const double C = ox*ox + oy*oy - m_radius*m_radius; - Float nearT, farT; - if (!solveQuadratic(A, B, C, nearT, farT)) + double nearT, farT; + if (!solveQuadraticDouble(A, B, C, nearT, farT)) return false; if (!(nearT <= maxt && farT >= mint)) /* NaN-aware conditionals */ return false; - const Float zPosNear = ray.o.z + ray.d.z * nearT; - const Float zPosFar = ray.o.z + ray.d.z * farT; + const double zPosNear = ray.o.z + ray.d.z * nearT; + const double zPosFar = ray.o.z + ray.d.z * farT; if (zPosNear >= 0 && zPosNear <= m_length && nearT >= mint) { - t = nearT; + t = (Float) nearT; } else if (zPosFar >= 0 && zPosFar <= m_length) { if (farT > maxt) return false; - t = farT; + t = (Float) farT; } else { return false; } @@ -170,25 +170,25 @@ public: /* Transform into the local coordinate system and normalize */ m_worldToObject(_ray, ray); - const Float + const double ox = ray.o.x, oy = ray.o.y, dx = ray.d.x, dy = ray.d.y; - const Float A = dx*dx + dy*dy; - const Float B = 2 * (dx*ox + dy*oy); - const Float C = ox*ox + oy*oy - m_radius*m_radius; + const double A = dx*dx + dy*dy; + const double B = 2 * (dx*ox + dy*oy); + const double C = ox*ox + oy*oy - m_radius*m_radius; - Float nearT, farT; - if (!solveQuadratic(A, B, C, nearT, farT)) + double nearT, farT; + if (!solveQuadraticDouble(A, B, C, nearT, farT)) return false; if (nearT > maxt || farT < mint) return false; - const Float zPosNear = ray.o.z + ray.d.z * nearT; - const Float zPosFar = ray.o.z + ray.d.z * farT; + const double zPosNear = ray.o.z + ray.d.z * nearT; + const double zPosFar = ray.o.z + ray.d.z * farT; if (zPosNear >= 0 && zPosNear <= m_length && nearT >= mint) { return true; } else if (zPosFar >= 0 && zPosFar <= m_length && farT <= maxt) { @@ -201,8 +201,8 @@ public: void fillIntersectionRecord(const Ray &ray, const void *temp, Intersection &its) const { its.p = ray(its.t); - Point local = m_worldToObject(its.p); + Float phi = std::atan2(local.y, local.x); if (phi < 0) phi += 2*M_PI; @@ -214,11 +214,15 @@ public: its.shape = this; its.dpdu = m_objectToWorld(dpdu); its.dpdv = m_objectToWorld(dpdv); - its.geoFrame.n = Normal(normalize(cross(its.dpdu, its.dpdv))); - if (m_flipNormals) - its.geoFrame.n *= -1; its.geoFrame.s = normalize(its.dpdu); its.geoFrame.t = normalize(its.dpdv); + its.geoFrame.n = Normal(cross(its.geoFrame.s, its.geoFrame.t)); + + /* Migitate roundoff error issues by a normal shift of the computed intersection point */ + its.p += its.geoFrame.n * (m_radius - std::sqrt(local.x*local.x+local.y*local.y)); + + if (m_flipNormals) + its.geoFrame.n *= -1; its.shFrame = its.geoFrame; its.wi = its.toLocal(-ray.d); its.hasUVPartials = false; @@ -378,7 +382,7 @@ public: Float alpha = ellipseAxes[0][j], beta = ellipseAxes[1][j]; Float tmp = 1 / std::sqrt(alpha*alpha + beta*beta); Float cosTheta = alpha * tmp, sinTheta = beta*tmp; - + Point p1 = ellipseCenter + cosTheta*ellipseAxes[0] + sinTheta*ellipseAxes[1]; Point p2 = ellipseCenter - cosTheta*ellipseAxes[0] - sinTheta*ellipseAxes[1]; From 923069f877a068334d4c955ed6089697b5bf9597 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 20 Mar 2014 12:57:31 +0100 Subject: [PATCH 3/3] ported cylinder.cpp improvements to hair.cpp --- src/shapes/hair.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shapes/hair.cpp b/src/shapes/hair.cpp index 4aef8248..39e3bce4 100644 --- a/src/shapes/hair.cpp +++ b/src/shapes/hair.cpp @@ -840,6 +840,11 @@ void HairShape::fillIntersectionRecord(const Ray &ray, const Vector relHitPoint = its.p - m_kdtree->firstVertex(iv); its.geoFrame.n = Normal(normalize(relHitPoint - dot(axis, relHitPoint) * axis)); its.geoFrame.t = cross(its.geoFrame.n, its.geoFrame.s); + + /* Migitate roundoff error issues by a normal shift of the computed intersection point */ + const Vector local = its.geoFrame.toLocal(relHitPoint); + its.p += its.geoFrame.n * (m_kdtree->getRadius() - std::sqrt(local.y*local.y+local.z*local.z)); + its.shFrame = its.geoFrame; its.wi = its.toLocal(-ray.d); its.hasUVPartials = false;