/** * Determines whether point is within the object or on the surface * @param point :: Point to be tested * @returns true if point is within object or on surface */ bool MeshObject::isValid(const Kernel::V3D &point) const { BoundingBox bb = getBoundingBox(); if (!bb.isPointInside(point)) { return false; } Kernel::V3D direction(0.0, 0.0, 1.0); // direction to look for intersections std::vector<Kernel::V3D> intersectionPoints; std::vector<TrackDirection> entryExitFlags; getIntersections(point, direction, intersectionPoints, entryExitFlags); if (intersectionPoints.empty()) { return false; } // True if point is on surface for (const auto &intersectionPoint : intersectionPoints) { if (point.distance(intersectionPoint) < M_TOLERANCE) { return true; } } // Look for nearest point then check its entry-exit flag double nearestPointDistance = point.distance(intersectionPoints[0]); size_t nearestPointIndex = 0; for (size_t i = 1; i < intersectionPoints.size(); ++i) { if (point.distance(intersectionPoints[i]) < nearestPointDistance) { nearestPointDistance = point.distance(intersectionPoints[i]); nearestPointIndex = i; } } return (entryExitFlags[nearestPointIndex] == TrackDirection::LEAVING); }
/** * Determines wither point is on the surface. * @param point :: Point to check * @returns true if the point is on the surface */ bool MeshObject::isOnSide(const Kernel::V3D &point) const { BoundingBox bb = getBoundingBox(); if (!bb.isPointInside(point)) { return false; } const std::vector<Kernel::V3D> directions = { Kernel::V3D{0, 0, 1}, Kernel::V3D{0, 1, 0}, Kernel::V3D{1, 0, 0}}; // directions to look for intersections // We have to look in several directions in case a point is on a face // or edge parallel to the first direction or also the second direction. for (const auto &direction : directions) { std::vector<Kernel::V3D> intersectionPoints; std::vector<TrackDirection> entryExitFlags; getIntersections(point, direction, intersectionPoints, entryExitFlags); if (intersectionPoints.empty()) { return false; } for (const auto &intersectionPoint : intersectionPoints) { if (point.distance(intersectionPoint) < M_TOLERANCE) { return true; } } } return false; }
/** * Given a track, fill the track with valid section * @param UT :: Initial track * @return Number of segments added */ int MeshObject::interceptSurface(Geometry::Track &UT) const { int originalCount = UT.count(); // Number of intersections original track BoundingBox bb = getBoundingBox(); if (!bb.doesLineIntersect(UT)) { return 0; } std::vector<Kernel::V3D> intersectionPoints; std::vector<TrackDirection> entryExit; getIntersections(UT.startPoint(), UT.direction(), intersectionPoints, entryExit); if (intersectionPoints.empty()) return 0; // Quit if no intersections found // For a 3D mesh, a ray may intersect several segments for (size_t i = 0; i < intersectionPoints.size(); ++i) { UT.addPoint(entryExit[i], intersectionPoints[i], *this); } UT.buildLink(); return UT.count() - originalCount; }
Vector3d traceRay(Ray* ray, vector<SceneObject*>* objects, vector<SceneObject*>* lights, int remainingDepth) { Vector3d backgroundColour(0, 0, 0); Vector3d ambientLight(25, 25, 25); /*Vector3d RED(255, 0, 0); Vector3d GREEN(0, 255, 0); Vector3d BLUE(255, 0, 255); Vector3d YELLOW(255, 255, 0); Vector3d CYAN(0, 255, 255); Vector3d MAJENTA(255, 0, 255);*/ if (remainingDepth <= 0) return backgroundColour; vector<Intersection*>* intersections = getIntersections(objects, ray, NULL, false, (remainingDepth < 2)); Intersection* closestIntersection = getClosestIntersection(ray->origin, intersections); Vector3d closestOrigin; Vector3d closestDirection; SceneObject* closestObject; if (closestIntersection != NULL) { closestOrigin = *(closestIntersection->origin); closestDirection = *(closestIntersection->direction); closestObject = closestIntersection->object; } freeIntersections(intersections); intersections->clear(); delete intersections; if (closestIntersection != NULL) { Vector3d fullLightColour = ambientLight; Vector3d surfaceColour = *(closestIntersection->object->colour); //for each light, add it to the full light on this point (if not blocked) for (unsigned int lightNum = 0; lightNum < lights->size(); lightNum++) { SceneObject* light = (*lights)[lightNum]; Vector3d toLight = *(light->position) - closestOrigin; Vector3d toLightNormalized = toLight.normalized(); double dot = toLightNormalized.dot(closestDirection); if (dot > 0) { intersections = getIntersections(objects, new Ray(&closestOrigin, &toLightNormalized), closestObject, true, false); bool inLight = false; if (intersections->size() == 0) { inLight = true; } else { Intersection* intersection = (*intersections)[0]; Vector3d intersectionOrigin = Vector3d(*(intersection->origin)); Vector3d intersectionDirection = Vector3d(*(intersection->direction)); SceneObject* obj = intersection->object; if ((intersectionOrigin - closestOrigin).norm() > toLight.norm()) { inLight = true; } } if (inLight) { fullLightColour += *(light->colour) * dot; } freeIntersections(intersections); intersections->clear(); delete intersections; } } double reflectivity = closestObject->reflectivity; if (reflectivity > 0) { Vector3d rayDirection = *(ray->direction); Vector3d normal = closestDirection; Vector3d reflectedDirection = rayDirection - ((2 * (normal.dot(rayDirection))) * normal); Ray* reflectedRay = new Ray(&closestOrigin, &reflectedDirection); Vector3d reflectionColour = traceRay(reflectedRay, objects, lights, remainingDepth - 1); delete reflectedRay; surfaceColour *= 1 - reflectivity; surfaceColour += reflectionColour * reflectivity; } Vector3d endColour = surfaceColour; endColour[0] *= fullLightColour[0] / 255; endColour[1] *= fullLightColour[1] / 255; endColour[2] *= fullLightColour[2] / 255; return endColour; } else { return backgroundColour; } }