Guest User

Untitled

a guest
May 21st, 2018
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.27 KB | None | 0 0
  1. // description: A business as usual raytracer that specializes in tracing spheres
  2. // references: Peter Shirley's raytracing series
  3.  
  4. // compile: clang++ -std=c++14 -Wall -Oz Spherical.cpp -o Spherical
  5. // compile(debug): clang++ -DDEBUG_MODE -std=c++14 -g2 -O0 Spherical.cpp -o Spherical
  6. // run: ./Spherical [seed, default=0]
  7.  
  8. #include <vector>
  9. #include <cstdlib> // atoi, time, exit status
  10. #include <limit> // epsilon
  11. #include <iostream>
  12. #include <functional> // closures
  13. #include <random> // uniform_real_dist<T>
  14.  
  15. #include <glm/glm.hpp>
  16.  
  17. using namespace std;
  18. using namespace glm;
  19.  
  20. class RandomNumberGenerator {
  21. public:
  22. explicit RandomNumberGenerator(unsigned int seed = 0)
  23. : mSeed(seed) {
  24.  
  25. }
  26.  
  27. unsigned int getSeed() const {
  28. return mSeed;
  29. }
  30.  
  31. void setSeed(unsigned int seed) {
  32. mSeed = seed;
  33. }
  34.  
  35. float getRandomFloat(int low, int high) {
  36. mt19937 mt (mSeed);
  37. random_device rd (mt);
  38. uniform_real_distribution<float> dist (low, high);
  39. return dist(rd);
  40. }
  41.  
  42. int getRandomInt(int low, int high) {
  43. mt19937 mt (mSeed);
  44. random_device rd (mt);
  45. uniform_real_distribution<int> dist (low, high);
  46. return dist(rd);
  47. }
  48.  
  49. private:
  50. unsigned int mSeed;
  51. }; // class RandomNumberGenerator
  52.  
  53. typedef RandomNumberGenerator Rng;
  54.  
  55. class Ray {
  56. vec3 origin, direction;
  57. explicit Ray(const vec3 &o, const vec3 &d)
  58. : origin(o), direction(d) {
  59.  
  60. }
  61. }; // class Ray
  62.  
  63. class Camera {
  64. vec3 eye, front, up;
  65.  
  66. explicit Camera(const glm::vec3 &eye,
  67. const glm::vec3 &front,
  68. const glm::vec3 &up)
  69. : eye(eye), front(front), up(up) {
  70.  
  71. }
  72.  
  73. void computeCameraCoordinates() {
  74. glm::vec3 front (glm::normalize(camera->getTarget() - camera->getEye()));
  75. glm::vec3 right (glm::normalize(glm::cross(front, camera->getUp())));
  76. glm::vec3 up (glm::cross(front, right));
  77. float tanHalfFov = glm::tan(glm::radians(camera->getFieldOfView() * 0.5f));
  78. float aspectRatio = static_cast<float>(resWidth) / static_cast<float>(resHeight);
  79. }
  80. }; // class Camera
  81.  
  82. class Sphere {
  83. vec3 position;
  84. float radius;
  85. vec3 ambient, diffuse, specular;
  86. float shiny, reflectivity, indexOfRefraction;
  87. bool isLightSource;
  88. }; // class Sphere
  89.  
  90. class Scene {
  91. public:
  92. static constexpr unsigned int RecursiveTraceLimit = 10;
  93. static constexpr unsigned int FrameWidth = 1980, FrameHeight = 1020;
  94.  
  95. explicit Scene(unsigned int seed)
  96. : rng(seed)
  97. , pixels(FrameWidth * FrameHeight) {
  98.  
  99. }
  100.  
  101. void buildScene() {
  102. const std::size_t TotalSpheres = 400;
  103. for (unsigned int index = 0; index != TOTAL_SPHERES; ++index) {
  104. glm::vec3 ambient (rng.getRandomFloat(0.09f, 1.0f),
  105. rng.getRandomFloat(0.09f, 1.0f), rng.getRandomFloat(0.09f, 1.0f));
  106. glm::vec3 diffuse (Utils::getRandomFloat(0.1f, 0.90f),
  107. Utils::getRandomFloat(0.09f, 0.9f), Utils::getRandomFloat(0.09f, 0.9f));
  108. glm::vec3 specular (Utils::getRandomFloat(0.5f, 1.0f),
  109. Utils::getRandomFloat(0.5f, 1.0f), Utils::getRandomFloat(0.5f, 1.0f));
  110.  
  111. float shiny = rng.getRandomFloat(10.0f, 300.0f);
  112. float refl = rng.getRandomFloat(0.05f, 1.0f);
  113.  
  114. Material material (ambient, diffuse, specular,
  115. rng.getRandomFloat(10.0f, 300.0f),
  116. rng.getRandomFloat(0.05f, 1.0f),
  117. rng.getRandomFloat(0.05f, 1.0f));
  118.  
  119. float angle = static_cast<float>(index) / static_cast<float>(TOTAL_SPHERES) * 360.0f;
  120. float displacement = Utils::getRandomFloat(-offset, offset);
  121.  
  122. float xpos = glm::sin(angle) * imgCircleRadius + displacement;
  123. displacement = rng::getRandomFloat(-offset, offset);
  124. float y = std::abs(displacement) * 7.5f; // y value has smaller displacement
  125. displacement = rng::getRandomFloat(-offset, offset);
  126. float z = glm::cos(angle) * imgCircleRadius + displacement;
  127.  
  128. glm::vec3 center = glm::vec3(xpos, y, z);
  129.  
  130. float radius = rng.getRandomFloat(5.0f, 12.0f);
  131. spheres.emplace_back(center, radius, ambient, diffuse, specular, shiny, refl);
  132. }
  133. int pixels = 0;
  134. for (unsigned int i = 0; i != resHeight; ++i)
  135. {
  136. for (unsigned int j = 0; j != resWidth; ++j, ++pixels)
  137. {
  138. pixelColor = glm::vec3(0.0f);
  139.  
  140. if (samples > 0)
  141. {
  142. for (int p = 0; p != samples; ++p)
  143. {
  144. for (int q = 0; q != samples; ++q)
  145. {
  146. float normalizedY = (static_cast<float>(i + (p + 0.5f) / samples) / static_cast<float>(resHeight - 1) * 2.0f - 1.0f) * tanHalfFov;
  147. float normalizedX = (static_cast<float>(j + (q + 0.5f) / samples) / static_cast<float>(resWidth - 1) * 2.0f - 1.0f) * aspectRatio * tanHalfFov;
  148. glm::vec3 imagePoint = camera->getEye() + front + (normalizedX * right) + (normalizedY * up);
  149. Ray ray (camera->getEye(), glm::normalize(imagePoint - camera->getEye()));
  150. pixelColor += mRayTracer.trace(mScene, ray, mScene.getRayBounces());
  151. }
  152. }
  153. pixelColor /= static_cast<float>(samples * samples);
  154. }
  155. else
  156. {
  157. float normalizedY = (static_cast<float>(i) / static_cast<float>(resHeight - 1) * 2.0f - 1.0f) * tanHalfFov;
  158. float normalizedX = (static_cast<float>(j) / static_cast<float>(resWidth - 1) * 2.0f - 1.0f) * aspectRatio * tanHalfFov;
  159. glm::vec3 imagePoint = camera->getEye() + front + (normalizedX * right) + (normalizedY * up);
  160. Ray ray (camera->getEye(), glm::normalize(imagePoint - camera->getEye()));
  161. pixelColor += trace(mScene, ray, mScene.getRayBounces());
  162. }
  163.  
  164. mFrameBuffer.at(pixels) = pixelColor;
  165. }
  166. }
  167. }
  168.  
  169. void trace(unsigned int traceCount = 0) {
  170. static constexpr float Epsilon = std::numeric_limits<float>::epsilon();
  171.  
  172. static auto phongShading(float shadow) {
  173. glm::vec3 ambient, diffuse, specular;
  174.  
  175. return ambient + shadow * (diffuse + specular);
  176. }
  177.  
  178. // using namespace glm;
  179. vec3 finalColor (0);
  180.  
  181. glm::vec3 finalColor (0.0f);
  182. static constexpr float colorFrac = 0.9999f; // fraction to add to final color
  183.  
  184. for (int i = 0; i != maxRayBounces; ++i)
  185. {
  186. auto& camera = scene.getCamera();
  187. auto& primitives = scene.getPrimitives();
  188. auto& lights = scene.getLights();
  189.  
  190. IPrimitive* hitPrimitive = nullptr;
  191. float tClosest = camera->getFarPlane();
  192. float tHit = 0.0f;
  193.  
  194. // iterate through the objects and look for closest intersection
  195. for (auto& primitive : primitives)
  196. {
  197. if (primitive->intersect(ray, tHit) && (tHit > scEpsilon) && (tHit < tClosest))
  198. {
  199. tClosest = tHit;
  200. hitPrimitive = primitive.get();
  201. }
  202. }
  203.  
  204. if (!hitPrimitive)
  205. {
  206. finalColor += colorFrac * scene.getBackgroundColor();
  207. break;
  208. }
  209.  
  210. // otherwise there is a hit, so find the color @ the intersection point
  211. glm::vec3 intPoint (ray.origin + (ray.direction * tClosest));
  212. glm::vec3 intNormal = hitPrimitive->getNormal(intPoint);
  213.  
  214. // make sure we didn't intersect from inside the hit primitive
  215. if (glm::dot(ray.direction, intNormal) > 0.0f)
  216. intNormal *= -1.0f;
  217.  
  218. Material primitiveMaterial = hitPrimitive->getMaterial();
  219.  
  220. if (hitPrimitive->getType() == IPrimitive::Type::PLANE)
  221. {
  222. primitiveMaterial = checkerboard(primitiveMaterial, intPoint);
  223. }
  224.  
  225. glm::vec3 localColor (0.0f);
  226.  
  227. // now compute phong shading
  228. for (auto& light : lights)
  229. {
  230. float shadow = 1.0f;
  231. glm::vec3 lightDir = glm::normalize(glm::vec3(light->getPosition()) - intPoint);
  232. Ray lightRay (intPoint + (intNormal * scEpsilon), lightDir);
  233. // check if color is in shadow
  234. for (auto& primitive : primitives)
  235. {
  236. if (primitive->intersect(lightRay, tHit) && (tHit > scEpsilon))
  237. {
  238. if (primitive->getType() == IPrimitive::Type::PLANE)
  239. {
  240. break;
  241. }
  242. shadow = 0.15f;
  243. }
  244. }
  245.  
  246. glm::vec3 reflectDir = glm::normalize(glm::reflect(lightDir, intNormal));
  247.  
  248. localColor += phongShading(light, primitiveMaterial, ray.direction, lightDir, intNormal, reflectDir, shadow);
  249. } // end lights
  250.  
  251. finalColor += localColor * (1.0f - primitiveMaterial.getReflectiveness()) * colorFrac;
  252.  
  253. colorFrac *= primitiveMaterial.getReflectiveness();
  254.  
  255. // compute reflections
  256. if (primitiveMaterial.getReflectiveness() > 0.0f)
  257. {
  258. glm::vec3 reflectDir = glm::normalize(glm::reflect(ray.direction, intNormal));
  259. Ray reflectRay (intPoint + (intNormal * scEpsilon), reflectDir);
  260. ray = reflectRay;
  261. }
  262.  
  263. // compute refractions
  264. if (primitiveMaterial.getIndexOfRefraction() > 0.0f)
  265. {
  266. // float ior = primitiveMaterial.getIndexOfRefraction();
  267. // glm::vec3 refractDir = glm::normalize(glm::refract(ray.direction, intNormal, ior));
  268. // Ray refractRay (intPoint + (refractDir * scEpsilon), refractDir);
  269. // ray = refractRay;
  270.  
  271. // float ior = primitiveMaterial.getIndexOfRefraction();
  272. // float cosIntersect = -1.0f * glm::dot(intNormal, ray.direction);
  273. // float cosT2 = 1.0f - ior * ior * (1.0f - cosIntersect * cosIntersect);
  274. // if (cosT2 > 0.0f)
  275. // {
  276. // float iorFactor = ior * cosIntersect - glm::sqrt(cosT2);
  277. // glm::vec3 refractDir = glm::normalize(glm::vec3(ray.direction * ior + intNormal * iorFactor));
  278. // Ray refractRay (intPoint + (refractDir * scEpsilon), refractDir);
  279. // ray = refractRay;
  280. // }
  281. }
  282.  
  283. if (colorFrac < 0.05f)
  284. break;
  285. } // end ray bounce for loop
  286.  
  287. return finalColor;
  288. }
  289.  
  290. // PPM format
  291. void printPixelsInPpmFormat() const {
  292. cout << "\nP6\n255\n" << endl;
  293. for (auto &pixel : pixels) {
  294. cout << pixel.x * 255.0 << \
  295. " " << pixel.y * 255.0 << \
  296. " " << pixel.z * 255.0 << endl;
  297. }
  298. }
  299.  
  300. private:
  301. Rng rng;
  302. Camera camera;
  303. vector<Sphere> spheres;
  304. vector<vec3> pixels;
  305.  
  306. }; // class Scene
  307.  
  308. void handleArgumentsAndSetSeed(int argc, char **argv, unsigned int &seed) {
  309. if (argc == 1) {
  310. #if defined(DEBUG_MODE)
  311. cout << "Tracing with default seed" << endl;
  312. #endif
  313. }
  314. else if (argc == 2) {
  315. seed = atoi(argv[1]);
  316. } else {
  317. #if defined(DEBUG_MODE)
  318. cerr << "Arguments are incorrent. Expect \'./Spherical [seed]\'" << endl;
  319. #endif
  320. }
  321. }
  322.  
  323. int main(int argc, char **argv) {
  324. const unsigned int seed = 0;
  325. handleArgumentsAndSetSeed(argc, argv, seed);
  326.  
  327. time(nullptr);
  328.  
  329. #if defined(DEBUG_MODE)
  330. cout << "Starting raytracer. Seed: " << seed << endl;
  331. #endif
  332.  
  333. Scene scene (seed);
  334. scene.buildScene();
  335. scene.printPixelsInPpmFormat();
  336.  
  337. return EXIT_SUCCESS;
  338. }
Add Comment
Please, Sign In to add comment