/** * @brief clip a ray by a Cone. * @param ray_ the ray to clip * @param bounds ray sorted bounds of the resulting clipping segment. * @return true if ray was clipped. bounds parameter is filld by this method * * For simple convex objects, there is two values in bounds that represent in and out events. * An in event is whe the ray enters the geometry, an out is when the ray leaves the geometry. * * Adapted from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrLine3Cone3.cpp * */ bool clip(Ray& ray_, IntervalSet &bounds) const { Diff_Geom ipoints[2]; float t[2]; int numintersection = get_clip_points(ray_, ipoints, t); if (numintersection == 0) return false; else if (numintersection == 2) { Diff_Geom *in = new Diff_Geom(ipoints[0].pos(), ipoints[0].normal(), t[0]); Diff_Geom *out = new Diff_Geom(ipoints[1].pos(), ipoints[1].normal(), t[1]); bounds.add(in, out); return true; } else { Diff_Geom *in, *out; IntervalSet capset; // check with cap plane Plane cap(m_vertex + m_axis * m_height, m_axis); if (cap.clip(ray_, capset) ) { /* Beuark mais ca facilite la gestion mémoire ... */ Diff_Geom *tmp =capset.bounds()[0].data; in = new Diff_Geom(*tmp); if (in->t()< t[0]) { out = new Diff_Geom(ipoints[0].pos(), ipoints[0].normal(), t[0]); } else { out = in; in = new Diff_Geom(ipoints[0].pos(), ipoints[0].normal(), t[0]); } bounds.add(in, out); return true; } else { return false; } } }
bool clip(Ray& ray_, IntervalSet &bounds) const { Diff_Geom ipoints[2]; float t[2]; int numintersection = get_clip_points(ray_, ipoints, t); if (numintersection == 0) return false; else if (numintersection == 2) { Diff_Geom *in = new Diff_Geom(ipoints[0].pos(), ipoints[0].normal(), ipoints[0].dNdx(), ipoints[0].dNdy(), t[0], ipoints[0].dPdx(), ipoints[0].dPdy(), ipoints[0].dDdx(), ipoints[0].dDdy(), ipoints[0].u(), ipoints[0].v(), ipoints[0].dTdx(), ipoints[0].dTdy(), true); Diff_Geom *out = new Diff_Geom(ipoints[1].pos(), ipoints[1].normal(), ipoints[1].dNdx(), ipoints[1].dNdy(), t[1], ipoints[1].dPdx(), ipoints[1].dPdy(), ipoints[1].dDdx(), ipoints[1].dDdy(), ipoints[1].u(), ipoints[1].v(), ipoints[1].dTdx(), ipoints[1].dTdy(), false); bounds.add(in, out); return true; } else { Diff_Geom *in, *out; IntervalSet capset; // check with cap plane Plane cap(m_vertex + m_axis * m_height, m_axis); if (cap.clip(ray_, capset) ) { in = capset.bounds()[0].data; in->set_u(in->u()/(PSCALE*m_radius)); in->set_v(in->v()/(PSCALE*m_radius)); in->set_dTdx(in->dTdx()* (1.f/(PSCALE*m_radius))); in->set_dTdy(in->dTdy()* (1.f/(PSCALE*m_radius))); if (in->t()< t[0]) { //if (p_diff_geom_in_->t() < t[0]) { out = new Diff_Geom(ipoints[0].pos(), ipoints[0].normal(), ipoints[0].dNdx(), ipoints[0].dNdy(), t[0], ipoints[0].dPdx(), ipoints[0].dPdy(), ipoints[0].dDdx(), ipoints[0].dDdy(), ipoints[0].u(), ipoints[0].v(), ipoints[0].dTdx(), ipoints[0].dTdy(), false); } else { out = in; out->set_in(false); in = new Diff_Geom(ipoints[0].pos(), ipoints[0].normal(), ipoints[0].dNdx(), ipoints[0].dNdy(), t[0], ipoints[0].dPdx(), ipoints[0].dPdy(), ipoints[0].dDdx(), ipoints[0].dDdy(), ipoints[0].u(), ipoints[0].v(), ipoints[0].dTdx(), ipoints[0].dTdy(), true); } delete (capset.bounds()[1].data); bounds.add(in, out); return true; } else { return false; } } }
int get_clip_points(Ray& ray_, Diff_Geom ipoints[2], float t[2]) const{ int numintersection = 0; Vector3D E = ray_.ori() - m_vertex; float AdD = m_axis.dot(ray_.dir()); float cosSqr = m_costheta*m_costheta; float AdE = m_axis.dot(E); float DdE = ray_.dir().dot(E); float EdE = E.dot(E); float c2 = AdD*AdD-cosSqr; float c1 = AdD*AdE - cosSqr*DdE; float c0 = AdE*AdE - cosSqr*EdE; float dot; Vector3D zero; if (std::fabs(c2)>0) { float discr = c1*c1 - c0*c2; float invC2 = 1.f/c2; if (discr < 0) { // No intersection return 0; } else if (discr > 0) { // two distinct intersections float root = std::sqrt(discr); // entry point t[numintersection] = (-c1 + root) * invC2; E = ray_.at(t[numintersection]) - m_vertex; dot = E.dot(m_axis); if ( (dot > 0) && (dot <= m_height)) { fillConicalDiffGeom(ipoints[numintersection], ray_, t[numintersection], true); ++numintersection; } // exit point t[numintersection] = (-c1 - root) * invC2; E = ray_.at(t[numintersection]) - m_vertex; dot = E.dot(m_axis); if ( (dot > 0) && (dot <= m_height)) { fillConicalDiffGeom(ipoints[numintersection], ray_, t[numintersection], false); ++numintersection; } return numintersection; } else { // one reapeated intersection : ray is tangent to the cone // may be return 0 instead of an intersection ? return 0; t[numintersection] = -c1 * invC2; E = ray_.at(t[numintersection]) - m_vertex; dot = E.dot(m_axis); if ( (dot > 0) && (dot <= m_height)) { fillConicalDiffGeom(ipoints[numintersection], ray_, t[numintersection], true); ++numintersection; } return numintersection; } } else if (std::fabs(c1) > 0) { // the ray is on the boundary of the cone // we consider no intersection // TODO : check this for CSG return 0; } else { //return false; // Cone contains ray V+tD // The ray intersect the cone exactly at its vertex :( // TODO : manage this particular case in another function ipoints[numintersection].set_pos(m_vertex); ipoints[numintersection].set_normal(-m_axis); ipoints[numintersection].set_u(1.f); ipoints[numintersection].set_v(0.f); E = ray_.ori() - m_vertex; t[numintersection] = ( (E.dot(ray_.dir())<0) ? std::sqrt(EdE) : -std::sqrt(EdE) ) ; ipoints[numintersection].set_t(t[numintersection]); ipoints[numintersection].set_in(true); ipoints[numintersection].set_u(0.f); ipoints[numintersection].set_v(1.f); // todo : compute here normal derivatives (according to x and y directions on the image plane) ipoints[numintersection].set_dNdx(zero); ipoints[numintersection].set_dNdy(zero); ++numintersection; // check with cap plane Plane cap(m_vertex + m_axis * m_height, m_axis); IntervalSet capset; if (cap.clip(ray_, capset)) { if (capset.bounds()[0].t < t[numintersection-1]) { t[numintersection] = t[numintersection-1]; ipoints[numintersection] = ipoints[numintersection-1]; --numintersection; } else { capset.bounds()[0].data->set_in(false); } ipoints[numintersection] = *(capset.bounds()[0].data); // TODO : update u, v dTdx and dTdy ipoints[numintersection].set_u(ipoints[numintersection].u()/(PSCALE*m_radius)); ipoints[numintersection].set_v(ipoints[numintersection].v()/(PSCALE*m_radius)); ipoints[numintersection].set_dTdx(ipoints[numintersection].dTdx()* (1.f/(PSCALE*m_radius))); ipoints[numintersection].set_dTdy(ipoints[numintersection].dTdy()* (1.f/(PSCALE*m_radius))); delete capset.bounds()[0].data; delete capset.bounds()[1].data; return 2; } else { // must never reach this point ! assert(false); return 0; } } }
/** * @brief get_clip_points * @param ray_ * @param ipoints * @param t * @return the number of clipping position on the ray (0 to 2) */ int get_clip_points(Ray& ray_, Diff_Geom ipoints[2], float t[2]) const{ int numintersection = 0; Vector3D E = ray_.ori() - m_vertex; float AdD = m_axis.dot(ray_.dir()); float cosSqr = m_costheta*m_costheta; float AdE = m_axis.dot(E); float DdE = ray_.dir().dot(E); float EdE = E.dot(E); float c2 = AdD*AdD-cosSqr; float c1 = AdD*AdE - cosSqr*DdE; float c0 = AdE*AdE - cosSqr*EdE; float dot; if (std::fabs(c2)>0) { float discr = c1*c1 - c0*c2; float invC2 = 1.f/c2; if (discr < 0) { // No intersection return 0; } else if (discr > 0) { // two distinct intersections float root = std::sqrt(discr); // entry point t[numintersection] = (-c1 + root) * invC2; ipoints[numintersection].set_pos(ray_.at(t[numintersection])); E = ipoints[numintersection].pos() - m_vertex; dot = E.dot(m_axis); if ( (dot > 0) && (dot <= m_height)) { Vector3D normal=compute_normal(ipoints[numintersection].pos()); ipoints[numintersection].set_normal(normal); ipoints[numintersection].set_t(t[numintersection]); ++numintersection; } // exit point t[numintersection] = (-c1 - root) * invC2; ipoints[numintersection].set_pos(ray_.at(t[numintersection])); E = ipoints[numintersection].pos() - m_vertex; dot = E.dot(m_axis); if ( (dot > 0) && (dot <= m_height)) { Vector3D normal=compute_normal(ipoints[numintersection].pos()); ipoints[numintersection].set_normal(normal); ipoints[numintersection].set_t(t[numintersection]); ++numintersection; } return numintersection; } else { // one reapeated intersection : ray is tangent to the cone // may be return 0 instead of an intersection ? return 0; t[numintersection] = -c1 * invC2; ipoints[numintersection].set_pos(ray_.at(t[numintersection])); E = ipoints[numintersection].pos() - m_vertex; dot = E.dot(m_axis); if ( (dot > 0) && (dot <= m_height)) { Vector3D normal=compute_normal(ipoints[numintersection].pos()); ipoints[numintersection].set_normal(normal); ipoints[numintersection].set_t(t[numintersection]); ++numintersection; } return numintersection; } } else if (std::fabs(c1) > 0) { // the ray is on the boundary of the cone // we consider no intersection // TODO : check this for CSG return 0; } else { //return false; // Cone contains ray V+tD // The ray intersect the cone exactly at its vertex :( ipoints[numintersection].set_pos(m_vertex); ipoints[numintersection].set_normal(-m_axis); E = ray_.ori() - m_vertex; t[numintersection] = ( (E.dot(ray_.dir())<0) ? std::sqrt(EdE) : -std::sqrt(EdE) ) ; ipoints[numintersection].set_t(t[numintersection]); ++numintersection; // TODO compute cap plane intersection // check with cap plane Plane cap(m_vertex + m_axis * m_height, m_axis); IntervalSet capset; if (cap.clip(ray_, capset)) { if (capset.bounds()[0].t < t[numintersection-1]) { t[numintersection] = t[numintersection-1]; ipoints[numintersection] = ipoints[numintersection-1]; --numintersection; } ipoints[numintersection] = *(capset.bounds()[0].data); delete capset.bounds()[0].data; delete capset.bounds()[1].data; return 2; } else { // must never reach this point ! assert(false); return 0; } } }