LMBov-Ray/0040755000175000001440000000000007655304335011275 5ustar lmbusersLMBov-Ray/src/0040755000175000001440000000000007655302345012063 5ustar lmbusersLMBov-Ray/src/RayTracer.cpp0100644000175000001440000002447507637364413014500 0ustar lmbusers/******************************************************************************\ * The raytracing engine for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifdef _MSC_VER #pragma warning(disable: 4786) // name truncated to 255 chars in debug info #endif #include "RayTracer.h" #include // standard is not ubiquitous #include #include // - RayTracer::RayTracer ------------------------------------------------------ RayTracer::RayTracer(const Scene& scene) : scene_(scene), image_(scene.getWindowWidth(), scene.getWindowHeight(), "Image generated by LMBov-Ray, the Blindness of " "Vision Ray Tracer"), rayCount_(0) { } // - RayTracer::renderImage ---------------------------------------------------- void RayTracer::renderImage() { const double windowRealWidth = fabs(scene_.getWindowLowerLeftCorner().x - scene_.getWindowUpperRightCorner().x); const double windowRealHeight = fabs(scene_.getWindowLowerLeftCorner().y - scene_.getWindowUpperRightCorner().y); const double deltaX = windowRealWidth / scene_.getWindowWidth(); const double deltaY = windowRealHeight / scene_.getWindowHeight(); const double ssdX = deltaX / 3.0; // supersample delta const double ssdY = deltaY / 3.0; // supersample delta const double firstPixelX = scene_.getWindowLowerLeftCorner().x + deltaX / 2.0; const double firstPixelY = scene_.getWindowLowerLeftCorner().y + windowRealHeight - deltaY / 2.0; double currPosX = firstPixelX; double currPosY = firstPixelY; ColorRGB color; for (unsigned y = 0; y < scene_.getWindowHeight(); ++y) { for (unsigned x = 0; x < scene_.getWindowWidth(); ++x) { if (scene_.getSupersample()) { Ray r1 = Ray::fromPoints(Point(scene_.getEye().x, scene_.getEye().y, scene_.getEye().z), Point(currPosX-ssdX, currPosY-ssdY, 0.0)); const ColorRGB c1 = rayTrace(r1, 0); Ray r2 = Ray::fromPoints(Point(scene_.getEye().x, scene_.getEye().y, scene_.getEye().z), Point(currPosX-ssdX, currPosY+ssdY, 0.0)); const ColorRGB c2 = rayTrace(r2, 0); Ray r3 = Ray::fromPoints(Point(scene_.getEye().x, scene_.getEye().y, scene_.getEye().z), Point(currPosX+ssdX, currPosY-ssdY, 0.0)); const ColorRGB c3 = rayTrace(r3, 0); Ray r4 = Ray::fromPoints(Point(scene_.getEye().x, scene_.getEye().y, scene_.getEye().z), Point(currPosX+ssdX, currPosY+ssdY, 0.0)); const ColorRGB c4 = rayTrace(r4, 0); // average colors color.setR((c1.getR() + c2.getR() + c3.getR() + c4.getR()) / 4.0); color.setG((c1.getG() + c2.getG() + c3.getG() + c4.getG()) / 4.0); color.setB((c1.getB() + c2.getB() + c3.getB() + c4.getB()) / 4.0); } else // not supersampling { Ray ray = Ray::fromPoints(Point(scene_.getEye().x, scene_.getEye().y, scene_.getEye().z), Point(currPosX, currPosY, 0.0)); ray.direction.normalize(); color = rayTrace(ray, 0); } image_.setPixel(scene_.getWindowWidth() - x - 1, scene_.getWindowHeight() - y - 1, color); currPosX += deltaX; } currPosY -= deltaY; currPosX = firstPixelX; } } // - RayTracer::saveImage ------------------------------------------------------ void RayTracer::saveImage() { image_.writeToFile(scene_.getOutputFileName().c_str()); } // - RayTracer::rayTrace ------------------------------------------------------- ColorRGB RayTracer::rayTrace(const Ray& ray, int depth, double refractionIndex) { if (depth > scene_.getDepth()) return ColorRGB(0.0, 0.0, 0.0); assert(Equal(ray.direction.length(), 1.0)); // ray direction should be normalized TraceableThingPtr hitObject; PointVect hitPointNormal; Material hitMaterial(ColorRGB(0.0, 0.0, 0.0), 0.0, 0.0, 0.0, 0.0); if (rayHit(ray, hitPointNormal, hitMaterial)) { const ColorRGB localColor = calcShade(hitMaterial, hitPointNormal.p, hitPointNormal.v); // reflection ColorRGB reflectedColor(0.0, 0.0, 0.0); if (hitMaterial.reflection > 0.0) { Vector incid = ray.direction; incid.normalize(); const Vector rrDirection = incid - 2 * Dot(hitPointNormal.v, incid) * hitPointNormal.v; // bring the reflected ray origin a little away from the surface, to // avoid a new intersection with the same object (oh, rounding problems) const Point rrOrigin = hitPointNormal.p + hitPointNormal.v * 1e-10; const Ray reflectedRay(rrOrigin, rrDirection); reflectedColor = rayTrace(reflectedRay, depth + 1); } // transmition ColorRGB transmitedColor(0.0, 0.0, 0.0); if (hitMaterial.transparency > 0.0) { // TODO: refraction! const Vector trDirection = ray.direction; const Point trOrigin = hitPointNormal.p + -hitPointNormal.v * 1e-10; const Ray tranmitedRay(trOrigin, trDirection); transmitedColor = rayTrace(tranmitedRay, depth + 1, hitMaterial.refractionIndex); } const ColorRGB finalColor = combineColors(hitMaterial, localColor, reflectedColor, transmitedColor); return finalColor; } return scene_.getBackgroundColor(); } // - RayTracer::calcShade ------------------------------------------------------ ColorRGB RayTracer::calcShade(const Material& material, const Point& point, const Vector& normal) { // ambient const double iAmb = scene_.getAmbientLight() * material.ka; const double rAmb = iAmb * material.color.getR(); const double gAmb = iAmb * material.color.getG(); const double bAmb = iAmb * material.color.getB(); // diffuse and specular double rDif = 0.0; double gDif = 0.0; double bDif = 0.0; double rgbSpec = 0.0; Vector v = Vector::fromPoints(point, scene_.getEye()); v.normalize(); for (Scene::LightContainerConstIter p = scene_.lightsBegin(); p != scene_.lightsEnd(); ++p) { PointVect hitFromLight; Material mat(ColorRGB(0.0, 0.0, 0.0), 0.0, 0.0, 0.0, 0.0); Ray ray = Ray::fromPoints((*p)->position, point); ray.direction.normalize(); // rayHit() expect a ray with normalized direction const bool hasHitFromLight = rayHit(ray, hitFromLight, mat); // in principle 'hasHitFromLight' would always be true, but it can be // false due rounding errors (I think it is worse when the rays are // nearly tangent to the object) if (!hasHitFromLight) return ColorRGB(0.0, 0.0, 0.0); if (Equal(Dist(hitFromLight.p, point), 0.0)) { Vector l = Vector::fromPoints(point, (*p)->position); l.normalize(); Vector r = 2 * Dot(normal, l) * normal - l; r.normalize(); const double iDif = (*p)->intensity * material.kd * Dot(l, normal); rDif += iDif * material.color.getR(); gDif += iDif * material.color.getG(); bDif += iDif * material.color.getB(); const double dotProd = Dot(v, r); if (dotProd > 0.0) rgbSpec += (*p)->intensity * material.ks * pow(dotProd, material.n); } } return ColorRGB(rAmb + rDif + rgbSpec, gAmb + gDif + rgbSpec, bAmb + bDif + rgbSpec); } // - RayTracer::rayHit --------------------------------------------------------- bool RayTracer::rayHit(const Ray& ray, PointVect& hitPointNormal, Material& hitMaterial) { assert(Equal(ray.direction.length(), 1.0)); // ray direction should be normalized ++rayCount_; double smallestT = std::numeric_limits::max(); bool hasHit = false; for (Scene::ObjectContainerConstIter p = scene_.objectsBegin(); p != scene_.objectsEnd(); ++p) { double t; PointVect pv; if ((*p)->intersectWith(ray, pv, t) && t < smallestT) { hasHit = true; smallestT = t; hitMaterial = (*p)->getMaterial(); hitPointNormal = pv; } } return hasHit; } // - RayTracer::combineColors ------------------------------------------------- ColorRGB RayTracer::combineColors(const Material& material, const ColorRGB& localColor, const ColorRGB& reflectedColor, const ColorRGB& transmitedColor) { int numColors = 1; double r = localColor.getR(); double g = localColor.getG(); double b = localColor.getB(); if (material.reflection > 0.0) { ++numColors; r += reflectedColor.getR() * material.reflection; g += reflectedColor.getG() * material.reflection; b += reflectedColor.getB() * material.reflection; } if (material.transparency > 0.0) { ++numColors; r += transmitedColor.getR() * material.transparency; g += transmitedColor.getG() * material.transparency; b += transmitedColor.getB() * material.transparency; } r /= numColors; g /= numColors; b /= numColors; return ColorRGB(r, g, b); } LMBov-Ray/src/Makefile0100644000175000001440000000303007637364412013517 0ustar lmbusers# # Makefile for LMBov-Ray -- the Blindness Of Vision Raytracer # # (for the g++ compiler) # # Debug flags for g++ 2.9x #CXXFLAGS=-O0 -g -mtemplate-depth-99 -Wall # Optimizations for g++ 2.9x CXXFLAGS=-O2 -mcpu=i686 -march=i686 -funroll-loops -ftemplate-depth-99 -Wall # Debug flags for g++ 3.1 #CXXFLAGS=-O0 -g -Wall # Optimizations for g++ 3.1 #CXXFLAGS=-O3 -mcpu=pentium3 -march=pentium3 -funroll-loops -mfpmath=sse -mmmx -msse -Wall OBJS=LMBov-Ray.o PNMFile.o Scene.o RayTracingTypes.o CSG.o \ SDLParser.o Quadric.o Sphere.o RayTracer.o Color.o Chronometer.o lmbovray: $(OBJS) g++ $(CXXFLAGS) $(OBJS) -o lmbovray LMBov-Ray.o: LMBov-Ray.cpp RayTracingTypes.h g++ $(CXXFLAGS) -c LMBov-Ray.cpp PNMFile.o: PNMFile.cpp PNMFile.h g++ $(CXXFLAGS) -c PNMFile.cpp Scene.o: Scene.h Scene.cpp RayTracingTypes.h TraceableThing.h g++ $(CXXFLAGS) -c Scene.cpp RayTracingTypes.o: RayTracingTypes.h RayTracingTypes.cpp g++ $(CXXFLAGS) -c RayTracingTypes.cpp SDLParser.o: SDLParser.cpp SDLParser.h g++ $(CXXFLAGS) -c SDLParser.cpp Quadric.o: Quadric.h Quadric.cpp TraceableThing.h g++ $(CXXFLAGS) -c Quadric.cpp Sphere.o: Sphere.h Sphere.cpp TraceableThing.h g++ $(CXXFLAGS) -c Sphere.cpp RayTracer.o: RayTracer.h RayTracer.cpp PNMFile.h Funcs.h g++ $(CXXFLAGS) -c RayTracer.cpp Color.o: Color.cpp Color.h g++ $(CXXFLAGS) -c Color.cpp Chronometer.o: Chronometer.h Chronometer.cpp g++ $(CXXFLAGS) -c Chronometer.cpp CSG.o: CSG.h CSG.cpp TraceableThing.h g++ $(CXXFLAGS) -c CSG.cpp LMBov-Ray/src/CSG.h0100644000175000001440000000342707637364412012656 0ustar lmbusers/******************************************************************************\ * Support for CSG operations for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _CSG_OPERATIONS_H_ #define _CSG_OPERATIONS_H_ #include #include "TraceableThing.h" /** CSG union */ class CSGUnion: public TraceableThing { public: CSGUnion(const Material& material) : TraceableThing(material) { } bool intersectWith(const Ray& ray, PointVect& ret, double& t); bool in(const Point& p); void addObject(const TraceableThingPtr& object); private: std::vector objects_; }; /** CSG intersection */ class CSGIntersection: public TraceableThing { public: CSGIntersection(const Material& material) : TraceableThing(material) { } bool intersectWith(const Ray& ray, PointVect& ret, double& t); bool in(const Point& p); void addObject(const TraceableThingPtr& object); private: std::vector objects_; }; /** CSG difference */ class CSGDifference: public TraceableThing { public: /// solid1 - solid2 CSGDifference(const Material& material, const TraceableThingPtr& object1, const TraceableThingPtr& object2) : TraceableThing(material), object1_(object1), object2_(object2) { } bool intersectWith(const Ray& ray, PointVect& ret, double& t); bool in(const Point& p); private: TraceableThingPtr object1_; TraceableThingPtr object2_; }; #endif // _CSG_OPERATIONS_H_ LMBov-Ray/src/SDLParser.cpp0100644000175000001440000003334507655302014014364 0ustar lmbusers/******************************************************************************\ * A parser for the "Scene Description Language" (with extensions) * * Leandro Motta Barros * * Based on the Spirit parser framework (spirit.sf.net) * \******************************************************************************/ #ifdef _MSC_VER #pragma warning(disable: 4786) // name truncated to 255 chars in debug info #endif #include "SDLParser.h" #include #include #include #include #include #include #include #include "Quadric.h" #include "Sphere.h" #include "CSG.h" using boost::spirit::str_p; using boost::spirit::space_p; using boost::spirit::eol_p; using boost::spirit::blank_p; using boost::spirit::ureal_p; using boost::spirit::real_p; using boost::spirit::graph_p; using boost::spirit::uint_p; using boost::spirit::repeat_p; using boost::spirit::epsilon_p; using boost::spirit::comment_p; using boost::spirit::lexeme_d; // - Semantic Actions Stuff ---------------------------------------------------- namespace { typedef std::vector::const_iterator IteratorT; // stack of parameters std::stack Params; // stack of counters of csg things std::stack CSGCounter; // stack of raytraceable things std::stack Objects; // the scene being constructed Scene TheScene; // number of extra material info used (transparency, reflection...) std::stack ExtraMaterialInfo; // - GetReadMaterial -------------------------------------------------------- Material GetReadMaterial() { double refractionIndex = 0.0; if (ExtraMaterialInfo.top() == 3) { refractionIndex = Params.top(); Params.pop(); } double transparency = 0.0; if (ExtraMaterialInfo.top() >= 2) { transparency = Params.top(); Params.pop(); } double reflection = 0.0; if (ExtraMaterialInfo.top() >= 1) { reflection = Params.top(); Params.pop(); } ExtraMaterialInfo.pop(); double n = Params.top(); Params.pop(); double ks = Params.top(); Params.pop(); double kd = Params.top(); Params.pop(); double ka = Params.top(); Params.pop(); double b = Params.top(); Params.pop(); double g = Params.top(); Params.pop(); double r = Params.top(); Params.pop(); return Material(ColorRGB(r,g,b), ka, ks, kd, n, reflection, transparency, refractionIndex); } // - PushParam -------------------------------------------------------------- void PushParam(double d) { Params.push(d); } // - SetOutputFileName ------------------------------------------------------ void SetOutputFileName(IteratorT begin, IteratorT end) { TheScene.setOutputFileName(std::string(begin, end)); // TODO: check for valid filename } // - SetEye ----------------------------------------------------------------- void SetEye(IteratorT, IteratorT) { double z = Params.top(); Params.pop(); double y = Params.top(); Params.pop(); double x = Params.top(); Params.pop(); TheScene.setEye(Point(x, y, z)); } // - SetOrtho --------------------------------------------------------------- void SetOrtho(IteratorT, IteratorT) { double y1 = Params.top(); Params.pop(); double x1 = Params.top(); Params.pop(); double y0 = Params.top(); Params.pop(); double x0 = Params.top(); Params.pop(); TheScene.setWindowLowerLeftCorner(Point(x0, y0, 0.0)); TheScene.setWindowUpperRightCorner(Point(x1, y1, 0.0)); } // - SetSize ---------------------------------------------------------------- void SetSize(IteratorT, IteratorT) { unsigned y = static_cast(Params.top()); Params.pop(); unsigned x = static_cast(Params.top()); Params.pop(); TheScene.setWindowWidth(x); TheScene.setWindowHeight(y); } // - SetBackground ---------------------------------------------------------- void SetBackground(IteratorT, IteratorT) { double b = Params.top(); Params.pop(); double g = Params.top(); Params.pop(); double r = Params.top(); Params.pop(); TheScene.setBackgroundColor(ColorRGB(r,g,b)); } // - SetAmbient ------------------------------------------------------------- void SetAmbient(double d) { TheScene.setAmbientLight(d); } // - SetSupersample --------------------------------------------------------- void SetSupersample(IteratorT begin, IteratorT end) { std::string value(begin, end); if (value == "on") TheScene.setSupersample(true); else if (value == "off") TheScene.setSupersample(false); // TODO: else can give a good error message } // - BeginCSG --------------------------------------------------------------- void BeginCSG(IteratorT, IteratorT) { CSGCounter.push(0); } // - AddUnion --------------------------------------------------------------- void AddUnion(IteratorT, IteratorT) { Material mat = GetReadMaterial(); int numObj = CSGCounter.top(); CSGCounter.pop(); boost::shared_ptr csgUnion(new CSGUnion(mat)); for (int i = 0; i < numObj; ++i) { csgUnion->addObject(Objects.top()); Objects.pop(); } Objects.push(csgUnion); ++CSGCounter.top(); } // - AddIntersection -------------------------------------------------------- void AddIntersection(IteratorT, IteratorT) { Material mat = GetReadMaterial(); int numObj = CSGCounter.top(); CSGCounter.pop(); boost::shared_ptr csgIntersection(new CSGIntersection(mat)); for (int i = 0; i < numObj; ++i) { csgIntersection->addObject(Objects.top()); Objects.pop(); } Objects.push(csgIntersection); ++CSGCounter.top(); } // - AddDifference ---------------------------------------------------------- void AddDifference(IteratorT, IteratorT) { Material mat = GetReadMaterial(); CSGCounter.pop(); TraceableThingPtr obj2 = Objects.top(); Objects.pop(); TraceableThingPtr obj1 = Objects.top(); Objects.pop(); TraceableThingPtr csgDifference(new CSGDifference(mat, obj1, obj2)); Objects.push(csgDifference); ++CSGCounter.top(); } // - SetDepth --------------------------------------------------------------- void SetDepth(int d) { TheScene.setDepth(d); } // - AddLight --------------------------------------------------------------- void AddLight(IteratorT, IteratorT) { double i = Params.top(); Params.pop(); double z = Params.top(); Params.pop(); double y = Params.top(); Params.pop(); double x = Params.top(); Params.pop(); LightPtr light(new Light(Point(x, y, z), i)); TheScene.addLight(light); } // - AddQuadric ------------------------------------------------------------- void AddQuadric(IteratorT, IteratorT) { Material mat = GetReadMaterial(); double k = Params.top(); Params.pop(); double j = Params.top(); Params.pop(); double h = Params.top(); Params.pop(); double g = Params.top(); Params.pop(); double f = Params.top(); Params.pop(); double e = Params.top(); Params.pop(); double d = Params.top(); Params.pop(); double c = Params.top(); Params.pop(); double b = Params.top(); Params.pop(); double a = Params.top(); Params.pop(); TraceableThingPtr quadric(new Quadric(mat, a, b, c, d, e, f, g, h, j, k)); Objects.push(quadric); ++CSGCounter.top(); } // - AddSphere -------------------------------------------------------------- void AddSphere(IteratorT, IteratorT) { Material mat = GetReadMaterial(); double radius = Params.top(); Params.pop(); double z = Params.top(); Params.pop(); double y = Params.top(); Params.pop(); double x = Params.top(); Params.pop(); TraceableThingPtr sphere(new Sphere(mat, Point(x, y, z), radius)); Objects.push(sphere); ++CSGCounter.top(); } // - NewEMI ----------------------------------------------------------------- void NewEMI(IteratorT, IteratorT) { ExtraMaterialInfo.push(0); } // - IncEMI ----------------------------------------------------------------- void IncEMI(double) { ++ExtraMaterialInfo.top(); } } // - The Parser Definition ----------------------------------------------------- template SDLParser::definition::definition(const SDLParser& self) { // - ---------------------------------------------------------------- scene = *(eye | output | ortho | size | background | ambient | light | supersample | depth | any_object) ; // - ----------------------------------------------------------- any_object = quadric | sphere | csg_union | csg_intersection | csg_difference ; // - ------------------------------------------------------------------- eye = ("eye" >> real_p[&PushParam] >> real_p[&PushParam] >> real_p[&PushParam])[&SetEye] ; // - --------------------------------------------------------------- output = "output" >> lexeme_d[(+(graph_p - eol_p))[&SetOutputFileName]] ; // - ----------------------------------------------------------------- ortho = ("ortho" >> real_p[&PushParam] >> real_p[&PushParam] >> real_p[&PushParam] >> real_p[&PushParam])[&SetOrtho] ; // - ----------------------------------------------------------------- size = ("size" >> uint_p[&PushParam] >> uint_p[&PushParam])[&SetSize] ; // - ----------------------------------------------------------- background = ("background" >> ureal_p[&PushParam] >> ureal_p[&PushParam] >> ureal_p[&PushParam])[&SetBackground] ; // - -------------------------------------------------------------- ambient = "ambient" >> ureal_p[&SetAmbient] ; // - ---------------------------------------------------------- supersample = str_p("supersample") >> lexeme_d[(str_p("on") | "off")[&SetSupersample] >> *blank_p >> eol_p] ; // - ---------------------------------------------------------------- depth = "depth" >> uint_p[&SetDepth] ; // - ---------------------------------------------------------------- light = ("light" >> real_p[&PushParam] >> real_p[&PushParam] >> real_p[&PushParam] >> ureal_p[&PushParam])[&AddLight] ; // - ------------------------------------------------------------- material = epsilon_p[&NewEMI] >> repeat_p(6)[real_p[&PushParam]] >> // r g b ka kd ks ureal_p[&PushParam] >> // n (specular coefficient) !(ureal_p[&IncEMI][&PushParam] >> // reflection !(ureal_p[&IncEMI][&PushParam] >> // transparency !ureal_p[&IncEMI][&PushParam])) // refraction index ; // - --------------------------------------------------------------- sphere = ("sphere" >> repeat_p(4)[real_p[&PushParam]] >> // x y z radius material)[&AddSphere] ; // - -------------------------------------------------------------- quadric = ((str_p("object") | "quadric") >> repeat_p(10)[real_p[&PushParam]] >> // quadric coefficients material)[&AddQuadric] ; // - ------------------------------------------------------------ csg_union = (str_p("union")[&BeginCSG] >> material >> '{' >> repeat_p(2, boost::spirit::more)[any_object] >> '}')[&AddUnion] ; // - ----------------------------------------------------- csg_intersection = (str_p("intersection")[&BeginCSG] >> material >> '{' >> repeat_p(2, boost::spirit::more)[any_object] >> '}')[&AddIntersection] ; // - ------------------------------------------------------- csg_difference = (str_p("difference")[&BeginCSG] >> material >> '{' >> repeat_p(2)[any_object] >> '}')[&AddDifference] ; } // - SDLParser::parseSceneFile ------------------------------------------------- Scene SDLParser::parseSceneFile() { CSGCounter.push(0); std::ifstream ifs(fileName_.c_str()); if (!ifs.is_open()) { std::string errMsg = "Error opening scene description file (" + fileName_ + ")."; throw std::runtime_error(errMsg); } ifs.unsetf(std::ios::skipws); std::vector vec; std::copy( std::istream_iterator(ifs), std::istream_iterator(), std::back_inserter(vec)); std::vector::const_iterator first = vec.begin(); std::vector::const_iterator last = vec.end(); boost::spirit::parse_info::const_iterator> info = boost::spirit::parse(first, last, *this, comment_p('#') | space_p); if (!info.full) throw std::runtime_error("Error parsing scene description file."); while (Objects.size() > 0) { TheScene.addObject(Objects.top()); Objects.pop(); } return TheScene; } LMBov-Ray/src/PNMFile.h0100644000175000001440000000427207637364412013473 0ustar lmbusers/******************************************************************************\ * PNMFile - A simple PNM image format writer * * Leandro Motta Barros * * Uses the Boost libraries (www.boost.org) * \******************************************************************************/ #ifndef _PNMFILE_H_ #define _PNMFILE_H_ #include #include #include "Color.h" /** A simple class to write images in the PNM format. * @author LMB */ class PNMFile { public: /** Constructs a \texttt{PNMFile} with all pixels in black. * @param width The image width. * @param height The image height. * @param headerMessage A single line message to be inserted to the * header of the generated images. */ PNMFile(unsigned width, unsigned height, const char* headerMessage) : pixels_(new ColorRGB[width * height]), width_(width), height_(height), headerMessage_(headerMessage) { } /** Writes the image to a file in the PNM format. * @param fileName The destination image file name. * @exception std::runtime_error Thrown if the destination file could * not be opened. */ void writeToFile(const char* fileName); /** Clips the values of red, green and blue of all pixels to the interval * $[0,1]$. */ void clipRGB(); /** Changes the color of a given pixel. * @param x The desired pixel's horizontal coordinate. * @param y The desired pixel's vertical coordinate. * @param color The new pixel's color. */ void setPixel(unsigned x, unsigned y, const ColorRGB& color); private: /// The array of pixels (stored as a ``list of lines''). boost::scoped_array pixels_; /// The image width. unsigned width_; /// The image height. unsigned height_; /// Additional message to appear in the .pnm file header std::string headerMessage_; }; #endif // _PNMFILE_H_ LMBov-Ray/src/PNMFile.cpp0100644000175000001440000000420407637364412014021 0ustar lmbusers/******************************************************************************\ * PNMFile - A simple PNM image format writer * * Leandro Motta Barros * * Uses the Boost libraries (www.boost.org) * \******************************************************************************/ #include "PNMFile.h" #include #include #include // - PNMFile::writeToFile ------------------------------------------------------ void PNMFile::writeToFile(const char* fileName) { const int MAX_GREY = 255; std::ofstream ofs(fileName); if (!ofs.is_open()) { std::string errMsg(std::string("Error opening file '") + fileName + "' for writing."); throw std::runtime_error(errMsg); } clipRGB(); // write header ofs << "P3\n" << "# PNM File created by 'PNMFile' class, by LMB\n" << "# " << headerMessage_ << '\n' << width_ << ' ' << height_ << '\n' << MAX_GREY << "\n\n"; // write data for (unsigned i = 0; i < width_ * height_; ++i) ofs << static_cast(pixels_[i].getR() * MAX_GREY) << ' ' << static_cast(pixels_[i].getG() * MAX_GREY) << ' ' << static_cast(pixels_[i].getB() * MAX_GREY) << '\n'; } // - PNMFile::clipRGB ---------------------------------------------------------- void PNMFile::clipRGB() { for (unsigned i = 0; i < width_ * height_; ++i) { const double r = pixels_[i].getR(); const double g = pixels_[i].getG(); const double b = pixels_[i].getB(); if (r > 1.0) pixels_[i].setR(1.0); if (r < 0.0) pixels_[i].setR(0.0); if (g > 1.0) pixels_[i].setG(1.0); if (g < 0.0) pixels_[i].setG(0.0); if (b > 1.0) pixels_[i].setB(1.0); if (b < 0.0) pixels_[i].setB(0.0); } } // - PNMFile::setPixel --------------------------------------------------------- void PNMFile::setPixel(unsigned x, unsigned y, const ColorRGB& color) { pixels_[y * width_ + x] = color; } LMBov-Ray/src/Chronometer.h0100644000175000001440000000157307637364412014527 0ustar lmbusers// LMBLib -- A library of useful, more or less portable C++ routines // By Leandro Motta Barros // Please note that this not the "real" source code for LMBLib. LMBLib is // written in nuweb, a literate programming system. The "real" source file // is LMBLib.w. #ifndef _LMB_CHRONOMETER_H_ #define _LMB_CHRONOMETER_H_ #ifdef __linux # include #elif defined (_WIN32) # include #else # error Sorry, only Linux and Win32 currently supported #endif namespace LMB { class Chronometer { public: Chronometer() { reset(); } unsigned long getTime(); void reset(); private: #ifdef __linux ntptimeval start_; #elif defined (_WIN32) unsigned long start_; #endif }; } #endif // _LMB_CHRONOMETER_H_ LMBov-Ray/src/RayTracingTypes.cpp0100644000175000001440000000255707637364413015671 0ustar lmbusers/******************************************************************************\ * An assortment of types used by LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #include "RayTracingTypes.h" #include #include #include "Funcs.h" // - Vector::normalize --------------------------------------------------------- void Vector::normalize() { double div = sqrt(Sqr(x) + Sqr(y) + Sqr(z)); x /= div; y /= div; z /= div; } // - Vector::length ------------------------------------------------------------ double Vector::length() const { return sqrt(Sqr(x) + Sqr(y) + Sqr(z)); } // - Vector::fromPoints -------------------------------------------------------- Vector Vector::fromPoints(const Point& from, const Point& to) { return Vector(to.x - from.x, to.y - from.y, to.z - from.z); } // - operator<< ---------------------------------------------------------------- std::ostream& operator<<(std::ostream& lhs, const Vector& rhs) { lhs << '(' << rhs.x << ',' << rhs.y << ',' << rhs.z << ')'; return lhs; } std::ostream& operator<<(std::ostream& lhs, const Ray& rhs) { lhs << '[' << rhs.origin << '<' << rhs.direction << ']'; return lhs; } LMBov-Ray/src/Color.h0100644000175000001440000000511107637364412013310 0ustar lmbusers/******************************************************************************\ * Color - Color-related stuff * * Leandro Motta Barros * * Standard C++ * \******************************************************************************/ #ifndef _COLORRGB_H_ #define _COLORRGB_H_ #include /** Stores a color as its red, green and blue components. * @author LMB */ class ColorRGB { public: /** Constructs a \texttt{ColorRGB}. * @param r The red component. * @param g The green component. * @param b The blue component. */ explicit ColorRGB(double r = 0.0, double g = 0.0, double b = 0.0) : r_(r), g_(g), b_(b) { } /** Get the color red component. * @return The color red component. */ double getR() const { return r_; } /** Get the color green component. * @return The color green component. */ double getG() const { return g_; } /** Get the color blue component. * @return The color blue component. */ double getB() const { return b_; } /** Set the color red component. * @param r The color red component. */ void setR(double r) { r_ = r; } /** Set the color green component. * @param g The color green component. */ void setG(double g) { g_ = g; } /** Set the color blue component. * @param b The color blue component. */ void setB(double b) { b_ = b; } /** Set all color components. * @param r The red component. * @param g The green component. * @param b The blue component. */ void setRGB(double r, double g, double b) { r_ = r; g_ = g; b_ = b; } private: double r_; double g_; double b_; }; /** "Scales" a color (multiply all components of a color by a double) * @param lhs The color. * @param rhs The double. * @return The "scaled" color. */ inline ColorRGB operator*(const ColorRGB& lhs, double rhs) { return ColorRGB(lhs.getR() * rhs, lhs.getG() * rhs, lhs.getB() * rhs); } /** Outputs a color (as a textual description) to an output stream. * @param lhs The destination output stream. * @param rhs The color. * @return The output stream (\textt{lhs}). */ std::ostream& operator<<(std::ostream& lhs, const ColorRGB& rhs); # endif // _COLORRGB_H_ LMBov-Ray/src/SDLParser.h0100644000175000001440000000256707655302045014037 0ustar lmbusers/******************************************************************************\ * A parser for the "Scene Description Language" (with extensions) * * Leandro Motta Barros * * Based on the Spirit parser framework (spirit.sf.net) * \******************************************************************************/ #ifndef _SDL_PARSER_H_ #define _SDL_PARSER_H_ #include #include #include "Scene.h" /// A parser for the "scene description language" class SDLParser: public boost::spirit::grammar { public: SDLParser(const char* fileName) : fileName_(fileName) { } Scene parseSceneFile(); private: std::string fileName_; // - Grammar Stuff ---------------------------------------------------------- public: template struct definition { definition(const SDLParser& self); boost::spirit::rule scene, output, eye, ortho, size, background, ambient, light, supersample, any_object, quadric, sphere, depth, csg_union, csg_intersection, csg_difference, material; const boost::spirit::rule& start() const { return scene; } }; }; #endif // _SDL_PARSER_H_ LMBov-Ray/src/Sphere.cpp0100644000175000001440000000400407637364413014014 0ustar lmbusers/******************************************************************************\ * Solid spheres for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #include "Sphere.h" #include #include // standard is not ubiquitous #include "Funcs.h" // MSVC defines some stupid macros for min and max... #ifdef _MSC_VER #ifdef min #undef min #endif #ifdef max #undef max #endif #endif // - Sphere::Sphere ------------------------------------------------------------ Sphere::Sphere(const Material& material, const Point& center, double radius) : TraceableThing(material), center_(center), radius_(radius) { } // - Sphere::intersectWith ----------------------------------------------------- bool Sphere::intersectWith(const Ray& ray, PointVect& ret, double& t) { // find the intersection point const Vector v = center_ - ray.origin; const double b = Dot(v, ray.direction); const double discr = Sqr(b) - Dot(v, v) + Sqr(radius_); if (discr < 0.0) return false; else if (discr == 0) t = b; else { const double sqrtDiscr = sqrt(discr); const double t1 = b - sqrtDiscr; // std::numeric_limits::infinity() appears to be implemented as 0.0 // in some systems (like g++ 3.1), so it is best avoided if (t1 > 0.0 && t1 <= std::numeric_limits::max()) t = t1; else { const double t2 = b + sqrtDiscr; if (t2 > 0.0 && t2 <= std::numeric_limits::max()) t = t2; else return false; } } ret.p = ray.origin + t * ray.direction; // find the normal Vector normal = ret.p - center_; normal.normalize(); if (Dot(normal, ray.direction) > 0.0) normal = -normal; ret.v = normal; return true; } LMBov-Ray/src/LMBov-Ray.cpp0100644000175000001440000000543007637364412014301 0ustar lmbusers/******************************************************************************\ * LMBovRay -- the Blindness of Vision Raytracer * * Copyright(c) by Leandro Motta Barros * * You may use this program as stated by the Cursing License * \******************************************************************************/ #ifdef _MSC_VER #pragma warning(disable: 4786) // name truncated to 255 chars in debug info #endif #include #include #include "Chronometer.h" #include "RayTracer.h" #include "SDLParser.h" int main(int argc, char* argv[]) { try { std::cout << "\nLMBov-Ray -- the Blindness of Vision Raytracer, version 0.5\n" <\n"; exit(1); } // parse the input file std::cout << "Parsing '" << argv[1] << "'...\n" << std::endl; LMB::Chronometer chronometer; SDLParser parser(argv[1]); Scene scene = parser.parseSceneFile(); double parseTime = chronometer.getTime() / 1000.0; chronometer.reset(); std::cout << "Number of light sources: " << scene.getNumLights() << '\n' << "Number of objects: " << scene.getNumObjects() << '\n' << "Supersample: " << (scene.getSupersample() ? "on (RAYSTORM!)" : "off") << '\n' << std::endl; // raytrace! std::cout << "Raytracing...\n" << std::endl; std::cout << " Cast, cast, cast your rays\n" << " Gently down the scene\n" << " Merrily, merrily, merrily, merrily\n" << " Raytracing is but a dream!\n" << std::endl; RayTracer rt(scene); rt.renderImage(); double rtTime = chronometer.getTime() / 1000.0; std::cout << "Number of rays cast: " << rt.getRayCount() << std::endl; // save as image std::cout << "\nSaving scene to '" << scene.getOutputFileName() << "'.\n" << std::endl; chronometer.reset(); rt.saveImage(); double saveTime = chronometer.getTime() / 1000.0; // done! std::cout << "Parsing time: " << parseTime << "s.\n" << "Raytracing time: " << rtTime << "s.\n" << "Image saving time: " << saveTime << "s.\n\n" << "Thanks for using LMBov-Ray!" << std::endl; } catch(std::exception& e) { std::cerr << "\nSOMETHING BAD HAPPENNED!\n" << e.what() << '\n'; } catch(...) { std::cerr << "\nSOMETHING *REALLY* BAD HAPPENNED!\n"; } exit(0); } LMBov-Ray/src/RayTracer.h0100644000175000001440000000246607637364413014141 0ustar lmbusers/******************************************************************************\ * The raytracing engine for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _RAY_TRACER_H_ #define _RAY_TRACER_H_ #include "Scene.h" #include "PNMFile.h" class RayTracer { public: RayTracer(const Scene& scene); void renderImage(); void saveImage(); unsigned long getRayCount() { return rayCount_; } private: Scene scene_; PNMFile image_; unsigned long rayCount_; ColorRGB rayTrace(const Ray& ray, int depth, double refractionIndex = 1.0); bool rayHit(const Ray& ray, PointVect& hitPointNormal, Material& hitMaterial); ColorRGB calcShade(const Material& material, const Point& hitPoint, const Vector& normal); ColorRGB RayTracer::combineColors(const Material& material, const ColorRGB& localColor, const ColorRGB& reflectedColor, const ColorRGB& transmitedColor); }; #endif // _RAY_TRACER_H_ LMBov-Ray/src/Scene.h0100644000175000001440000000611407637364413013274 0ustar lmbusers/******************************************************************************\ * A scene for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _SCENE_H_ #define _SCENE_H_ #include #include #include "RayTracingTypes.h" #include "TraceableThing.h" class Scene { public: // types typedef std::list LightContainer; typedef std::list ObjectContainer; typedef ObjectContainer::const_iterator ObjectContainerConstIter; typedef LightContainer::const_iterator LightContainerConstIter; Scene(); LightContainerConstIter lightsBegin() const { return lights_.begin(); } LightContainerConstIter lightsEnd() const { return lights_.end(); } ObjectContainerConstIter objectsBegin() const { return objects_.begin(); } ObjectContainerConstIter objectsEnd() const { return objects_.end(); } void addObject(TraceableThingPtr& obj) { objects_.push_back(obj); } void addLight(LightPtr& light) { lights_.push_back(light); } void setOutputFileName(const std::string& ofn) { outputFileName_ = ofn; } std::string getOutputFileName() const { return outputFileName_; } void setEye(const Point& eye) { eye_ = eye; } Point getEye() const { return eye_; } void setWindowLowerLeftCorner(const Point& llc) { windowLowerLeftCorner_ = llc; } Point getWindowLowerLeftCorner() const { return windowLowerLeftCorner_; } void setWindowUpperRightCorner(const Point& urc) { windowUpperRightCorner_ = urc; } Point getWindowUpperRightCorner() const { return windowUpperRightCorner_; } void setWindowWidth(unsigned ww) { windowWidth_ = ww; } unsigned getWindowWidth() const { return windowWidth_; } void setWindowHeight(unsigned wh) { windowHeight_ = wh; } unsigned getWindowHeight() const { return windowHeight_; } void setBackgroundColor(const ColorRGB& color) { backgroundColor_ = color; } ColorRGB getBackgroundColor() const { return backgroundColor_; } void setAmbientLight(double ambientLight) { ambientLight_ = ambientLight; } double getAmbientLight() { return ambientLight_; } void setSupersample(bool ss) { supersample_ = ss; } bool getSupersample() const { return supersample_; } int getNumLights() { return lights_.size(); } int getNumObjects() { return objects_.size(); } void setDepth(int d) { depth_ = d; } int getDepth() { return depth_; } private: LightContainer lights_; ObjectContainer objects_; std::string outputFileName_; Point eye_; Point windowLowerLeftCorner_; Point windowUpperRightCorner_; unsigned windowWidth_; unsigned windowHeight_; ColorRGB backgroundColor_; double ambientLight_; bool supersample_; int depth_; }; #endif // #ifndef _SCENE_H_ LMBov-Ray/src/Scene.cpp0100644000175000001440000000144307637364413013627 0ustar lmbusers/******************************************************************************\ * A scene for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifdef _MSC_VER #pragma warning(disable: 4786) // name truncated to 255 chars in debug info #endif #include "Scene.h" // - Scene::Scene -------------------------------------------------------------- Scene::Scene() : eye_(0.0, 0.0, 0.0), windowLowerLeftCorner_(0.0, 0.0, 0.0), windowUpperRightCorner_(0.0, 0.0, 0.0), windowWidth_(0), windowHeight_(0), backgroundColor_(0.0, 0.0, 0.0), ambientLight_(0.0), supersample_(false), depth_(0) { } LMBov-Ray/src/Quadric.h0100644000175000001440000000145307637364413013630 0ustar lmbusers/******************************************************************************\ * Quadrics for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _QUADRIC_H_ #define _QUADRIC_H_ #include "TraceableThing.h" /** A quadric surface */ class Quadric: public TraceableThing { public: Quadric(const Material& material, double a, double b, double c, double d, double e, double f, double g, double h, double j, double k); bool intersectWith(const Ray& ray, PointVect& ret, double& t); private: double a_, b_, c_, d_, e_, f_, g_, h_, j_, k_; }; #endif // _QUADRIC_H_ LMBov-Ray/src/Color.cpp0100644000175000001440000000115607637364412013650 0ustar lmbusers/******************************************************************************\ * Color - Color-related stuff * * Leandro Motta Barros * * Standard C++ * \******************************************************************************/ #include "Color.h" #include std::ostream& operator<<(std::ostream& lhs, const ColorRGB& rhs) { lhs << '(' << rhs.getR() << ',' << rhs.getG() << ',' << rhs.getB() << ')'; return lhs; } LMBov-Ray/src/Chronometer.cpp0100644000175000001440000000162607637364412015061 0ustar lmbusers// LMBLib -- A library of useful, more or less portable C++ routines // By Leandro Motta Barros // Please note that this not the "real" source code for LMBLib. LMBLib is // written in nuweb, a literate programming system. The "real" source file // is LMBLib.w. #include "Chronometer.h" namespace LMB { #ifdef __linux unsigned long Chronometer::getTime() { ntptimeval now; ntp_gettime (&now); return (now.time.tv_sec - start_.time.tv_sec) * 1000 + (now.time.tv_usec - start_.time.tv_usec) / 1000; } void Chronometer::reset() { ntp_gettime (&start_); } #elif defined (_WIN32) unsigned long Chronometer::getTime() { return ::GetTickCount() - start_; } void Chronometer::reset() { start_ = ::GetTickCount(); } #endif } LMBov-Ray/src/RayTracingTypes.h0100644000175000001440000000755407637364413015340 0ustar lmbusers/******************************************************************************\ * An assortment of types used by LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _RAY_TRACING_TYPES_H_ #define _RAY_TRACING_TYPES_H_ #include "Funcs.h" #include "Color.h" #include #include /** A 3D vector. * @author LMB */ class Vector { public: Vector(double xx, double yy, double zz) : x(xx), y(yy), z(zz) { } void normalize(); double length() const; Vector operator-() { return Vector(-x, -y, -z); } typedef Vector Point; static Vector fromPoints(const Point& from, const Point& to); double x; double y; double z; }; inline Vector operator+(const Vector& lhs, const Vector& rhs) { return Vector(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z); } inline Vector operator-(const Vector& lhs, const Vector& rhs) { return Vector(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); } inline Vector operator*(double lhs, const Vector& rhs) { return Vector(rhs.x * lhs, rhs.y * lhs, rhs.z * lhs); } inline Vector operator*(const Vector& lhs, double rhs) { return Vector(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs); } inline double Dot(const Vector& v1, const Vector& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } std::ostream& operator<<(std::ostream& lhs, const Vector& rhs); /** A 3D point. */ typedef Vector Point; inline double Dist(const Point& p1, const Point& p2) { return sqrt(Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y) + Sqr(p1.z - p2.z)); } /** A ray (``a half infinite'' line). */ class Ray { public: Ray(const Point& orig, const Vector& direct) : origin(orig), direction(direct) { direction.normalize(); } Point origin; Vector direction; static Ray fromPoints(const Point& p1, const Point& p2) { return Ray(p1, p2-p1); } }; std::ostream& operator<<(std::ostream& lhs, const Ray& rhs); /** A material */ class Material { public: Material(const ColorRGB& c, double ambCoef, double diffCoef, double specCoef, double specExp, double refl = 0.0, double transp = 0.0, double refr = 1.0) : color(c), ka(ambCoef), kd(diffCoef), ks(specCoef), n(specExp), reflection(refl), transparency(transp), refractionIndex(refr) { } /// Color ColorRGB color; /// Ambient reflection coefficient double ka; /// Diffuse reflection coefficient double kd; /// Specular reflection coefficient double ks; /// Specular exponent double n; /// Reflection (1.0 == perfect mirror) double reflection; // Transparency (1.0 == totally transparent; 0.0 == totally opaque) double transparency; /// Refraction index double refractionIndex; }; /** A point light source */ class Light { public: Light(const Point& pos, double intens) : position(pos), intensity(intens) { } Point position; double intensity; }; /** Stores a \texttt{Point} and a \texttt{Vector} */ class PointVect { public: PointVect() : p(Point(0.0, 0.0, 0.0)), v(Vector(0.0, 0.0, 0.0)) { } PointVect(const Point& pp, const Vector& vv) : p(pp), v(vv) { } Point p; Vector v; }; // types typedef boost::shared_ptr LightPtr; class TraceableThing; typedef boost::shared_ptr TraceableThingPtr; class Solid; typedef boost::shared_ptr SolidPtr; #endif // _RAY_TRACING_TYPES_H_ LMBov-Ray/src/TraceableThing.h0100644000175000001440000000161007637364413015107 0ustar lmbusers/******************************************************************************\ * An abstract traceable object for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _TRACEABLETHING_H_ #define _TRACEABLETHING_H_ #include "RayTracingTypes.h" /** Something that can be ray-traced */ class TraceableThing { public: TraceableThing(const Material& material) : material_(material) { } virtual ~TraceableThing() { }; virtual bool intersectWith(const Ray& ray, PointVect& ret, double& t) = 0; virtual bool in(const Point& p) { return false; } Material getMaterial() { return material_; } private: Material material_; }; #endif // _TRACEABLETHING_H_ LMBov-Ray/src/Quadric.cpp0100644000175000001440000000665007637364413014167 0ustar lmbusers/******************************************************************************\ * Quadrics for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #include "Quadric.h" #include #include #include #include // standard is not ubiquitous #include "Funcs.h" // MSVC defines some stupid macros for min and max... #ifdef _MSC_VER #ifdef min #undef min #endif #ifdef max #undef max #endif #endif // - Quadric::Quadric ---------------------------------------------------------- Quadric::Quadric(const Material& material, double a, double b, double c, double d,double e, double f, double g, double h, double j, double k) : TraceableThing(material), a_(a), b_(b), c_(c), d_(d), e_(e), f_(f), g_(g), h_(h), j_(j), k_(k) { } // - Quadric::intersectWith ---------------------------------------------------- bool Quadric::intersectWith(const Ray& ray, PointVect& ret, double& t) { assert(Equal(ray.direction.length(), 1.0)); // ray direction should be normalized const double x0 = ray.origin.x; const double y0 = ray.origin.y; const double z0 = ray.origin.z; const double xd = ray.direction.x; const double yd = ray.direction.y; const double zd = ray.direction.z; // compute coefficients const double coefA = a_*Sqr(xd) + b_*Sqr(yd) + c_*Sqr(zd) + 2*d_*xd*yd + 2*e_*yd*zd + 2*f_*xd*zd; const double coefB = 2*a_*x0*xd + 2*b_*y0*yd + 2*c_*z0*zd + 2*d_*(x0*yd + xd*y0) + 2*e_*(y0*zd + yd*z0) + 2*f_*(x0*zd + xd*z0) + 2*g_*xd + 2*h_*yd + 2*j_*zd; const double coefC = a_*Sqr(x0) + b_*Sqr(y0) + c_*Sqr(z0) + 2*d_*x0*y0 + 2*e_*y0*z0 + 2*f_*x0*y0 + 2*g_*x0 + 2*h_*y0 + 2*j_*z0 + k_; if (Equal(coefA, 0.0)) // this handles planar quadrics { if (Equal (coefB, 0.0)) return false; t = (-coefC) / coefB; if (t < 0.0) return false; } else // and this handles nonplanar quadrics { // find the roots const double discr = Sqr(coefB) - 4*coefA*coefC; if (discr < 0.0) return false; else if (discr == 0.0) t = -coefB / (2.0 * coefA); else { const double sqrtDiscr = sqrt(discr); const double t1 = (-coefB - sqrtDiscr) / (2.0 * coefA); // std::numeric_limits::infinity() appears to be implemented as 0.0 // in some systems (like g++ 3.1), so it is best avoided if (t1 > 0.0 && t1 <= std::numeric_limits::max()) t = t1; else { const double t2 = (-coefB + sqrtDiscr) / (2.0 * coefA); if (t2 > 0.0 && t2 <= std::numeric_limits::max()) t = t2; else return false; } } } // find the intersection point and the normal on this point ret.p = ray.origin + t * ray.direction; Vector normal(a_*ret.p.x + d_*ret.p.y + f_*ret.p.z + g_, b_*ret.p.y + d_*ret.p.x + e_*ret.p.z + h_, c_*ret.p.z + e_*ret.p.y + f_*ret.p.x + j_); normal.normalize(); if (Dot(normal, ray.direction) > 0.0) normal = -normal; ret.v = normal; return true; } LMBov-Ray/src/Funcs.h0100644000175000001440000000153507637364412013316 0ustar lmbusers/******************************************************************************\ * Miscelany functions for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _FUNCS_H_ #define _FUNCS_H_ #include /** Squares a number. A little note: the raytracing time of a scene with * two quadrics was about 3.3 times faster implementing this as * \texttt{x * x} than as \texttt{pow(x,2)}. */ inline double Sqr(double x) { return x * x; } /** Checks whether two numbers are equal, considering a ``delta'' as rounding * error. */ inline bool Equal(double d1, double d2, double epsilon = 1e-5) { return std::abs(d1 - d2) <= epsilon; } #endif // _FUNCS_H_ LMBov-Ray/src/Sphere.h0100644000175000001440000000145607637364413013471 0ustar lmbusers/******************************************************************************\ * Solid spheres for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #ifndef _SPHERE_H_ #define _SPHERE_H_ #include "TraceableThing.h" #include "Funcs.h" /** A solid sphere */ class Sphere: public TraceableThing { public: Sphere(const Material& material, const Point& center, double radius); bool intersectWith(const Ray& ray, PointVect& ret, double& t); bool in(const Point& p) { return Dist(center_, p) <= radius_ + 1e-10; } private: Point center_; double radius_; }; #endif // _SPHERE_H_ LMBov-Ray/src/Makefile.bcc320100644000175000001440000000262407637364412014422 0ustar lmbusers# # Makefile for LMBov-Ray -- the Blindness Of Vision Raytracer # # (for the Borland C++ Compiler 5.5.1 (free command-line tools)) # # Flags for speed optimized (-O2) code for P6 processors (-6) CXXFLAGS=-w-8027 -w-8004 -w-8026 -6 -O2 OBJS=LMBov-Ray.obj PNMFile.obj Scene.obj RayTracingTypes.obj CSG.obj \ SDLParser.obj Quadric.obj Sphere.obj RayTracer.obj Color.obj \ Chronometer.obj lmbovray.exe: $(OBJS) bcc32 $(CXXFLAGS) $(OBJS) -elmbovray.exe LMBov-Ray.obj: LMBov-Ray.cpp RayTracingTypes.h bcc32 $(CXXFLAGS) -c LMBov-Ray.cpp PNMFile.obj: PNMFile.cpp PNMFile.h bcc32 $(CXXFLAGS) -c PNMFile.cpp Scene.obj: Scene.h Scene.cpp RayTracingTypes.h TraceableThing.h bcc32 $(CXXFLAGS) -c Scene.cpp RayTracingTypes.obj: RayTracingTypes.h RayTracingTypes.cpp bcc32 $(CXXFLAGS) -c RayTracingTypes.cpp SDLParser.obj: SDLParser.cpp SDLParser.h bcc32 $(CXXFLAGS) -c SDLParser.cpp Quadric.obj: Quadric.h Quadric.cpp TraceableThing.h bcc32 $(CXXFLAGS) -c Quadric.cpp Sphere.obj: Sphere.h Sphere.cpp TraceableThing.h bcc32 $(CXXFLAGS) -c Sphere.cpp RayTracer.obj: RayTracer.h RayTracer.cpp PNMFile.h Funcs.h bcc32 $(CXXFLAGS) -c RayTracer.cpp Color.obj: Color.cpp Color.h bcc32 $(CXXFLAGS) -c Color.cpp Chronometer.obj: Chronometer.h Chronometer.cpp bcc32 $(CXXFLAGS) -c Chronometer.cpp CSG.obj: CSG.h CSG.cpp TraceableThing.h bcc32 $(CXXFLAGS) -c CSG.cpp LMBov-Ray/src/CSG.cpp0100644000175000001440000000767707637364412013224 0ustar lmbusers/******************************************************************************\ * Support for CSG operations for LMBov-Ray * * Leandro Motta Barros * \******************************************************************************/ #include "CSG.h" #include #include #include // standard is not ubiquitous #include "Funcs.h" // - CSGIntersection::intersectWith -------------------------------------------- bool CSGIntersection::intersectWith(const Ray& ray, PointVect& ret, double& t) { assert(Equal(ray.direction.length(), 1.0)); // ray direction should be normalized double smallestT = std::numeric_limits::max(); bool hasHit = false; // FIXME: I think this works only with convex things (think about a horseshoe // intersecting with a sphere) for (std::vector::const_iterator pObj = objects_.begin(); pObj != objects_.end(); ++pObj) { PointVect pvAux; double tAux; if ((*pObj)->intersectWith(ray, pvAux, tAux) && tAux < smallestT && in(pvAux.p)) { hasHit = true; smallestT = t = tAux; ret = pvAux; } } return hasHit; } // - CSGIntersection::in ------------------------------------------------------- bool CSGIntersection::in(const Point& p) { for (std::vector::const_iterator pObj = objects_.begin(); pObj != objects_.end(); ++pObj) if (!(*pObj)->in(p)) return false; return true; } // - CSGIntersection::addObject ------------------------------------------------ void CSGIntersection::addObject(const TraceableThingPtr& object) { objects_.push_back(object); } // - CSGUnion::intersectWith --------------------------------------------------- bool CSGUnion::intersectWith(const Ray& ray, PointVect& ret, double& t) { assert(Equal(ray.direction.length(), 1.0)); // ray direction should be normalized double smallestT = std::numeric_limits::max(); bool hasHit = false; for (std::vector::const_iterator pObj = objects_.begin(); pObj != objects_.end(); ++pObj) { PointVect pvAux; double tAux; if ((*pObj)->intersectWith(ray, pvAux, tAux) && tAux < smallestT) { hasHit = true; smallestT = t = tAux; ret = pvAux; } } return hasHit; } // - CSGUnion::in -------------------------------------------------------------- bool CSGUnion::in(const Point& p) { for (std::vector::const_iterator pObj = objects_.begin(); pObj != objects_.end(); ++pObj) if ((*pObj)->in(p)) return true; return false; } // - CSGUnion::addObject ------------------------------------------------------- void CSGUnion::addObject(const TraceableThingPtr& object) { objects_.push_back(object); } // FIXME: There is something wrong with the difference CSG operation. // (notice the strange "border" on the lower right corner of // 'csg.pnm') // - CSGDifference::intersectWith ---------------------------------------------- bool CSGDifference::intersectWith(const Ray& ray, PointVect& ret, double& t) { assert(Equal(ray.direction.length(), 1.0)); // ray direction should be normalized if (!object1_->intersectWith(ray, ret, t)) return false; if (object2_->in(ret.p)) // if inside the "clipper", cast ray to find its end { double newT; const bool hasHit = object2_->intersectWith(Ray(ret.p, ray.direction), ret, newT); assert(hasHit); t += newT; } return true; } // - CSGDifference::in --------------------------------------------------------- bool CSGDifference::in(const Point& p) { return object1_->in(p) && !object2_->in(p); } LMBov-Ray/SDLs/0040755000175000001440000000000007655301372012100 5ustar lmbusersLMBov-Ray/SDLs/csg.sdl0100644000175000001440000000221707637364411013362 0ustar lmbuserseye 0.0 0.0 -150.0 #size 240 180 #size 480 360 size 800 600 ortho -2.5 -1.875 2.5 1.875 # light definition # x y z intensity light -5.0 5.0 0.0 1.0 light 5.0 -5.0 0.0 1.0 light 55.0 -5.0 -100.0 1.0 background 0.0 0.0 0.0 output csg.pnm ambient 0.3 depth 3 supersample on #spheres x y z radius r g b ka kd ks n refl transp ind.refr sphere 1.7 -1.05 5.0 .8 0.1 1.0 0.1 0.9 0.9 0.1 10 sphere 0.9 -0.9 4.65 .8 1.0 0.1 0.1 0.8 0.8 0.1 10 union 0.1 0.1 1.0 0.8 0.8 0.1 10 { sphere -0.9 -1.05 5.0 .8 0.1 1.0 0.1 0.9 0.9 0.1 10 sphere -1.7 -0.9 4.65 .8 1.0 0.1 0.1 0.8 0.8 0.1 10 } intersection 0.1 0.1 1.0 0.8 0.8 0.1 10 { sphere 1.7 0.9 5.0 .8 0.1 1.0 0.1 0.9 0.9 0.1 10 sphere 0.9 1.05 4.65 .8 1.0 0.1 0.1 0.8 0.8 0.1 10 } difference 0.1 0.1 1.0 0.8 0.8 0.1 10 { sphere -0.9 0.9 5.0 .8 0.1 1.0 0.1 0.9 0.9 0.1 10 sphere -1.7 1.05 4.65 .8 1.0 0.1 0.1 0.8 0.8 0.1 10 } LMBov-Ray/SDLs/twoshadow.sdl0100644000175000001440000000115407637364412014625 0ustar lmbuserseye 0.0 0.5 3.5 size 200 200 ortho -1 -1 1 1 ambient 0.3 supersample off # light definition # x y z intensity light 0.0 1.0 1.0 1.0 light 0.3 1.0 1.0 1.0 #light 1.0 0.0 1.0 1.0 #object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 5 # #plane 1 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 30.0 0.3 0.3 0.3 0.1 0.5 0.0 5 #plane 2 #object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 5.0 0.0 0.0 1.0 0.1 0.5 0.0 5 # # background color background 0.5 0.5 0.5 output twoshadow.pnm LMBov-Ray/SDLs/onesphere.sdl0100644000175000001440000000061607637364412014600 0ustar lmbuserseye 0.0 0.0 7.0 size 200 200 ortho -1 -1 1 1 # light definition # x y z intensity light 0.0 1.0 1.0 1.0 #ambient light ambient 0.5 #object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.2 0.5 0.6 5 # background color background 0.0 0.0 0.0 output onesphere.pnm LMBov-Ray/SDLs/oneshadow.sdl0100644000175000001440000000107607637364412014600 0ustar lmbuserseye 0.0 0.5 3.5 size 200 200 ortho -1 -1 1 1 ambient 0.3 supersample off # light definition # x y z intensity light 0.0 1.0 1.0 1.0 # object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 5 # #plane 1 #object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 30.0 0.3 0.3 0.3 0.1 0.5 0.0 5 #plane 2 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 5.0 0.0 0.0 1.0 0.1 0.5 0.0 5 # # background color background 0.5 0.5 0.5 output oneshadow.pnm LMBov-Ray/SDLs/oneplanesphere.sdl0100644000175000001440000000110707637364412015614 0ustar lmbuserseye 0.0 0.0 3.5 size 200 200 ortho -1 -1 1 1 ambient 0.3 # light definition # x y z intensity light 0.0 1.0 1.0 1.0 light 1.0 0.0 1.0 1.0 #object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 5 # #plane 1 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 30.0 0.3 0.3 0.3 0.1 0.5 0.0 5 #plane 2 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 5.0 0.0 0.0 1.0 0.1 0.5 0.0 5 # # background color background 0.5 0.5 0.5 output oneplanesphere.pnm LMBov-Ray/SDLs/twoplanessphere.sdl0100644000175000001440000000111007637364412016021 0ustar lmbuserseye 0.0 0.0 5.0 size 200 200 ortho -1 -1 1 1 ambient 0.3 # light definition # x y z intensity light 0.5 0.0 1.0 1.0 light 0.6 0.0 1.0 1.0 #object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 5 # #plane 1 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 30.0 0.0 0.0 0.7 0.1 0.5 0.0 5 #plane 2 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 5.0 0.0 0.7 0.0 0.1 0.5 0.0 5 # # background color background 0.0 0.0 0.0 output twoplanessphere.pnm LMBov-Ray/SDLs/twospheres.sdl0100644000175000001440000000074107637364412015012 0ustar lmbuserseye 0.0 0.0 5.0 size 200 200 ortho -1 -1 1 1 ambient 0.2 # light definition # x y z intensity light 0.0 1.0 1.0 1.0 light 1.0 0.0 1.0 1.0 #object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 5 # object 1.0 1.0 1.0 0.0 0.0 0.0 5.0 5.0 30.0 949.0 0.0 0.0 1.0 0.1 0.5 0.4 4 # # background color back 0.0 0.0 0.0 output twospheres.pnm LMBov-Ray/SDLs/threeshadow.sdl0100644000175000001440000000115607637364412015125 0ustar lmbuserseye 0.0 0.5 3.5 size 200 200 ortho -1 -1 1 1 ambient 0.3 supersample off # light definition # x y z intensity light 0.0 1.0 1.0 1.0 light 0.3 1.0 1.0 1.0 light -0.3 1.0 1.0 1.0 #object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 5 # #plane 1 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 30.0 0.3 0.3 0.3 0.1 0.5 0.0 5 #plane 2 #object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 5.0 0.0 0.0 1.0 0.1 0.5 0.0 5 # # background color background 0.5 0.5 0.5 output threeshadow.pnm LMBov-Ray/SDLs/supersample.sdl0100644000175000001440000000107707637364412015152 0ustar lmbuserseye 0.0 0.5 3.5 size 200 200 ortho -1 -1 1 1 ambient 0.3 supersample on # light definition # x y z intensity light 0.0 1.0 1.0 1.0 # object definition # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 # object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 5 # #plane 1 #object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 30.0 0.3 0.3 0.3 0.1 0.5 0.0 5 #plane 2 object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 5.0 0.0 0.0 1.0 0.1 0.5 0.0 5 # # background color background 0.5 0.5 0.5 output supersample.pnm LMBov-Ray/SDLs/glass.sdl0100644000175000001440000000215607637364411013721 0ustar lmbuserseye 0.0 0.0 -150.0 #size 240 180 #480 360 size 480 360 ortho -2.5 -1.875 2.5 1.875 # light definition # x y z intensity light -5.0 5.0 0.0 1.0 light 5.0 -5.0 0.0 1.0 light 55.0 -5.0 -100.0 1.0 background 0.0 0.0 0.0 output glass.pnm #ambient light ambient 0.3 #spheres x y z radius r g b ka kd ks n refl transp ind.refr sphere 1.0 -0.2 5 2 0.3 0.1 0.8 0.9 0.9 0.6 10 0.2 #sphere -1.35 0.2 3.5 1 0.7 0.8 0.1 0.8 0.8 0.8 7.2 0.0 sphere -1.35 0.2 3.5 1 0.8 0.8 0.8 0.2 0.2 0.8 7.2 0.0 4.0 1.2 #sphere -1.0 0.5 3.0 0.75 0.0 0.0 1.0 0.8 0.6 0.6 22.2 #sphere -2.0 0.95 4.5 0.75 0.0 1.0 0.0 0.8 0.6 0.3 22.2 #plane 1 #object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 30.0 0.3 0.3 0.3 0.1 0.5 0.0 5 #plane 2 #object 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 5.0 0.0 0.0 1.0 0.1 0.5 0.0 5 # # Quadricas do marcelow # # a b c d e f g h j k red green blue Ka Kd Ks n # red sphere at x=0, y=0, z=-10 radius=1 #object 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 10.0 99.0 1.0 0.0 0.0 0.1 0.5 0.6 22 depth 3 supersample off LMBov-Ray/README0100644000175000001440000000554407655304267012166 0ustar lmbusersLMBov-Ray -- the Blindness Of Vision Raytracer By Leandro Motta Barros 1. About ---------- LMBov-Ray is a toy raytracer. For a real, good and free raytracer take a look at www.povray.com. What LMBov-Ray does (or tries to do): - Support quadrics and spheres (I know, spheres are quadrics. But "my" spheres are solid. They can be used with CSG, see below); - An arbitrary number of objects and (point) light sources; - Supersampling (four rays per pixel); - Reflection; - Transmission (translucency); - CSG (Constructive Solid Geometry). I don't know if the used algorithms are general (I wanted them to work with spheres); - LMBov-Ray reads files in SDL (the Scene Description Language). In the very unlikely case that you want to create your own scenes, take a look on the example scenes at the 'SDLs' directory; - Images are saved in the PNM file format. What LMBov-Ray does not: - Anything a raytracer isn't supoosed to do; - Refraction; - Texture mapping, bump mapping... - And much, much more! LMBov-Ray was created during the "Advanced Computer Graphics" course at Unisinos (www.unisinos.br), taught by Marcelo Walter (www.inf.unisinos.br/~marcelow). 2. Compiling -------------- LMBov-Ray is written in C++. It was developed and tested with GNU g++ 3.1 (under Linux) and Borland C++ 5.5.1 (under Windows). Preliminary releases used to compile with Microsoft Visual C++ 6.0 and GNU g++ 2.96. Misteriously, this very last release issues an "impossible" link error on MSVC++ and core dumps when compiled with g++ 2.96. As every modern C++ program should, LMBov-Ray uses the Boost libraries (www.boost.org), in particular smart pointers. It also uses the great Spirit parsing framework (spirit.sf.net). So, if you want to compile LMBov-Ray you'll need a good C++ compiler, Boost and Spirit. UPDATE: Since Boost 1.30, Spirit is included as part of Boost, so the source code was updated to compile using the Spirit version distributed with Boost. 3. About the sample SDL files ------------------------------- Some example SDL files are included in the 'SDLs' directory: - glass.sdl: Actually this does not look like glass, but shows reflection and transmission in action. And yes, the spheres are touching each other. - csg.sdl: The one and only CSG test scene. The "union" and "intersection" operations look ok, but there is something slightly wrong with the "difference". The other SDLs are simple examples created by professor Marcelo Walter. They are intended to test some basic features and I won't explain them here. 4. Licensing -------------- LMBov-Ray is distributed under the Cursing License, which has not yet been written :-) I'll do it as soon as I get some free time. UPDATE: I still didn't get some free time. LMB, September 02002 LMB, May 02003 (Update)