NonhierSphere Mesh::getBoundingBall(const std::vector<Point3D>& verts) const { Point3D C = verts[0] + 0.5*(verts[1]-verts[0]); double radius = (verts[1] - verts[0]).length() / 2.0; // This is the bouncing ball algorithm. Take any two points and construct the sphere's center // at the center point of the line between the two vertices and raidus half the distance // between the two vertices // Then loop through each vertex. If it is outside the sphere then move the sphere's center // a little bit towards the point while growing the radius as well so that the point is now inside // the sphere. Keep doing this until there are no vertices outside the sphere for(bool outsider = true; outsider == true;) { outsider = false; for(auto v : verts) { double length = (v-C).length(); if(length > radius) { double diff = length - radius; double delta = diff / length; C = C + (0.5 * delta)*(v-C); radius = radius + (0.5 * diff); outsider = true; } } } return NonhierSphere(C, radius); }
Mesh::Mesh(const std::vector<Point3D>& verts, const std::vector< std::vector<int> >& faces, const std::vector<Vector3D>& upVectors) : m_verts(verts), m_polygons(), m_boundingSphere(Point3D(0.0, 0.0, 0.0), 0.0) { for (std::vector<Face>::const_iterator it = faces.begin(); it != faces.end(); it++) { Vector3D v1 = verts[it->at(0)] - verts[it->at(1)]; Vector3D v2 = verts[it->at(2)] - verts[it->at(1)]; Vector3D normal = v2.cross(v1); std::vector<Point3D> vertices; for (Face::const_iterator it2 = it->begin(); it2 != it->end(); it2++) { vertices.push_back(verts[*it2]); } // Just put something on the plane for the up vector. m_polygons.push_back(Polygon(vertices, normal, v1)); } // If we're given up vectors add them to the polygons. if (!upVectors.empty()) { std::vector<Polygon>::iterator p = m_polygons.begin(); std::vector<Vector3D>::const_iterator it = upVectors.begin(); for ( ; p != m_polygons.end() && it != upVectors.end(); it++, p++) { p->set_upVector(*it); } } // Now create our bounding sphere // Idea is to find max distance between two points. // TODO: I don't think this is right.... double maxDist = 0.0; Point3D point1, point2; for (std::vector<Point3D>::const_iterator p1 = verts.begin(); p1 != verts.end(); p1++) { for (std::vector<Point3D>::const_iterator p2 = p1 + 1; p2 != verts.end(); p2++) { double dist = (*p1 - *p2).length(); if (dist > maxDist) { maxDist = dist; point1 = *p1; point2 = *p2; } } } double radius = maxDist / 2.0; Point3D center = (1.0/2.0) * (point1 + point2); m_boundingSphere = NonhierSphere(center, radius); }
SphericalLight::SphericalLight(glm::vec3 position, glm::vec3 color, double radius) : AreaLight(position, color), _radius(radius) { m_primitive = NonhierSphere(position, _radius); }