From 48c5d42c74525acbcdc27c076bd38ce0847716af Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Mon, 23 Aug 2021 18:30:20 +0900 Subject: [PATCH] Refactorings --- example02_threaded_raytracing/src/main.cpp | 25 +--- .../src/rayTracer.cpp | 138 +++++++++++------- .../src/rayTracer.hpp | 41 +++++- 3 files changed, 123 insertions(+), 81 deletions(-) diff --git a/example02_threaded_raytracing/src/main.cpp b/example02_threaded_raytracing/src/main.cpp index a5657b2..1da026f 100644 --- a/example02_threaded_raytracing/src/main.cpp +++ b/example02_threaded_raytracing/src/main.cpp @@ -11,7 +11,6 @@ void printHelp() { " | --threads Set the number of threads to use (default 1)\n" "--width Set the width of the output image\n" "--height Set the height of the output image\n" - "--radius Set the radius of the sphere\n" "-o \n" " | --output Set the output filename for the image" << std::endl; @@ -21,7 +20,6 @@ int main(int argc, char **argv) { int threadCount = 1; unsigned int outputWidth = 1600; unsigned int outputHeight = 1600; - float sphereRadius = 1.5f; std::string outputFile = "raytrace_out"; { @@ -37,7 +35,6 @@ int main(int argc, char **argv) { "--threads", "--width", "--height", - "--radius", "-o", "--output", }); @@ -114,24 +111,6 @@ int main(int argc, char **argv) { std::cout << "ERROR: height cannot be 0" << std::endl; return 8; } - if(auto iter = results.find("--radius"); iter != results.end()) { - try { - sphereRadius = stof(iter->second); - } catch (const std::invalid_argument &e) { - std::cout << "ERROR: Failed to parse radius (invalid)" - << std::endl; - return 9; - } catch (const std::out_of_range &e) { - std::cout << "ERROR: Failed to parse radius (out_of_range)" - << std::endl; - return 10; - } - } - if(sphereRadius <= 0.0f) { - std::cout << "ERROR: radius must be positive and non-zero" - << std::endl; - return 11; - } if(auto iter = results.find("-o"); iter != results.end()) { outputFile = iter->second; } else if(auto iter = results.find("--output"); iter != results.end()) { @@ -144,9 +123,9 @@ int main(int argc, char **argv) { } auto pixels = Ex02::RT::renderGraySphere( - outputWidth, outputHeight, sphereRadius, threadCount); + outputWidth, outputHeight, threadCount); - Ex02::RT::writeGrayscaleToFile(pixels, outputWidth, outputFile); + pixels.writeToFile(outputFile); return 0; } diff --git a/example02_threaded_raytracing/src/rayTracer.cpp b/example02_threaded_raytracing/src/rayTracer.cpp index e5de0e5..4e04da4 100644 --- a/example02_threaded_raytracing/src/rayTracer.cpp +++ b/example02_threaded_raytracing/src/rayTracer.cpp @@ -9,6 +9,43 @@ const float PI = std::acos(-1.0f); +Ex02::RT::Pixel::Pixel() : + r(0), + g(0), + b(0) +{} + +Ex02::RT::Image::Image(unsigned int width, unsigned int height) : + width(width) +{ + data.resize(width * height); +} + +Ex02::RT::Pixel& Ex02::RT::Image::getPixel( + unsigned int x, unsigned int y) { + return data.at(x + y * width); +} + +const Ex02::RT::Pixel& Ex02::RT::Image::getPixel( + unsigned int x, unsigned int y) const { + return data.at(x + y * width); +} + +void Ex02::RT::Image::writeToFile(const std::string &filename) const { + std::ofstream out(filename + ".ppm"); + out << "P3\n" << width << ' ' << data.size() / width << " 255" + << '\n'; + + for(unsigned int j = 0; j < data.size() / width; ++j) { + for(unsigned int i = 0; i < width; ++i) { + out << (int)data.at(i + j * width).r << ' ' + << (int)data.at(i + j * width).g << ' ' + << (int)data.at(i + j * width).b << ' '; + } + out << '\n'; + } +} + glm::vec3 Ex02::RT::Internal::defaultSpherePos() { return glm::vec3{0.0f, 0.0f, -2.5f}; } @@ -44,13 +81,6 @@ std::optional Ex02::RT::Internal::rayToSphere( glm::vec3 rayDir, glm::vec3 spherePos, float sphereRadius) { - // ensure rayDir is a unit vector - float rayDirLength = std::sqrt( - rayDir.x * rayDir.x - + rayDir.y * rayDir.y - + rayDir.z * rayDir.z); - rayDir /= rayDirLength; - // check if there is collision glm::vec3 tempVec = rayPos - spherePos; float temp = @@ -96,15 +126,44 @@ float Ex02::RT::Internal::angleBetweenRays(glm::vec3 a, glm::vec3 b) { return std::acos(dot / amag / bmag); } -std::vector Ex02::RT::renderGraySphere( +Ex02::RT::Internal::RTSVisibleType Ex02::RT::Internal::rayToSphereVisible( + glm::vec3 rayPos, + glm::vec3 rayDir, + glm::vec3 spherePos, + float sphereRadius, + glm::vec3 lightPos) { + glm::vec3 rayDirUnit = rayDir / std::sqrt( + rayDir.x * rayDir.x + + rayDir.y * rayDir.y + + rayDir.z * rayDir.z); + + auto collPos = rayToSphere(rayPos, rayDirUnit, spherePos, sphereRadius); + if(collPos) { + glm::vec3 toLight = lightPos - *collPos; + glm::vec3 toLightUnit = toLight / std::sqrt( + toLight.x * toLight.x + + toLight.y * toLight.y + + toLight.z * toLight.z); + glm::vec3 toLightPos = *collPos + toLight / 3.0f; + auto collResult = Internal::rayToSphere( + toLightPos, toLightUnit, spherePos, sphereRadius); + if(collResult) { + return {}; + } else { + return {{*collPos, toLight}}; + } + } else { + return {}; + } +} + +Ex02::RT::Image Ex02::RT::renderGraySphere( unsigned int outputWidth, unsigned int outputHeight, - float sphereRadius, int threadCount, glm::vec3 spherePos, glm::vec3 lightPos) { - std::vector grayscalePixels; - grayscalePixels.resize(outputWidth * outputHeight); + Image image(outputWidth, outputHeight); glm::vec3 rayPos{0.0f, 0.0f, 0.0f}; float lightFalloffStart = 4.5f; float lightFalloffEnd = 7.0f; @@ -115,33 +174,27 @@ std::vector Ex02::RT::renderGraySphere( float offsetX = ((float)i + 0.5f - ((float)outputWidth / 2.0f)); glm::vec3 rayDir = glm::vec3{ offsetX, offsetY, -(float)outputHeight * EX02_RAY_TRACER_VIEW_RATIO}; - auto rayResult = Internal::rayToSphere( - rayPos, rayDir, spherePos, sphereRadius); + auto rayResult = Internal::rayToSphereVisible( + rayPos, rayDir, + spherePos, EX02_RAY_TRACER_GRAY_SPHERE_RADIUS, + lightPos); if(rayResult) { - glm::vec3 toLight = lightPos - *rayResult; - glm::vec3 toLightCached = toLight; - toLight /= std::sqrt( - toLight.x * toLight.x - + toLight.y * toLight.y - + toLight.z * toLight.z); - glm::vec3 toLightPos = *rayResult + toLight; - auto collResult = Internal::rayToSphere( - toLightPos, toLight, spherePos, sphereRadius); - if(collResult) { - continue; - } - + glm::vec3 *toLight = &std::get<1>(rayResult.value()); float dist = std::sqrt( - toLightCached.x * toLightCached.x - + toLightCached.y * toLightCached.y - + toLightCached.z * toLightCached.z); + toLight->x * toLight->x + + toLight->y * toLight->y + + toLight->z * toLight->z); if(dist < lightFalloffStart) { - grayscalePixels.at(i + j * outputWidth) = 255; + image.getPixel(i, j).r = 255; + image.getPixel(i, j).g = 255; + image.getPixel(i, j).b = 255; } else if(dist >= lightFalloffStart && dist <= lightFalloffEnd) { - grayscalePixels.at(i + j * outputWidth) = + image.getPixel(i, j).r = (1.0f - (dist - lightFalloffStart) - / (lightFalloffEnd - lightFalloffStart)) - * 255.0f; + / (lightFalloffEnd - lightFalloffStart)) + * 255.0f; + image.getPixel(i, j).g = image.getPixel(i, j).r; + image.getPixel(i, j).b = image.getPixel(i, j).r; } } } @@ -149,22 +202,5 @@ std::vector Ex02::RT::renderGraySphere( } else { } - return grayscalePixels; -} - -void Ex02::RT::writeGrayscaleToFile( - const std::vector &pixels, - unsigned int outputWidth, - std::string filename) { - std::ofstream out(filename + ".pgm"); - out << "P2\n" << outputWidth << ' ' << pixels.size() / outputWidth << " 255" - << '\n'; - - for(unsigned int j = 0; j < pixels.size() / outputWidth; ++j) { - for(unsigned int i = 0; i < outputWidth; ++i) { - out << (int)pixels.at(i + j * outputWidth) - << ' '; - } - out << '\n'; - } + return image; } diff --git a/example02_threaded_raytracing/src/rayTracer.hpp b/example02_threaded_raytracing/src/rayTracer.hpp index f42779a..95609a3 100644 --- a/example02_threaded_raytracing/src/rayTracer.hpp +++ b/example02_threaded_raytracing/src/rayTracer.hpp @@ -5,10 +5,12 @@ #define EX02_RAY_TRACER_DEFAULT_NEAR_PLANE 0.2f #define EX02_RAY_TRACER_DEFAULT_FAR_PLANE 4.0f #define EX02_RAY_TRACER_COLL_INCREMENT 2.0f +#define EX02_RAY_TRACER_GRAY_SPHERE_RADIUS 1.5f #include #include #include +#include #include #include @@ -17,10 +19,32 @@ namespace Ex02 { namespace RT { +struct Pixel { + Pixel(); + + unsigned char r,g,b; +}; + +class Image { +public: + Image(unsigned int width, unsigned int height); + + Pixel& getPixel(unsigned int x, unsigned int y); + const Pixel& getPixel(unsigned int x, unsigned int y) const; + + void writeToFile(const std::string &filename) const; + +private: + unsigned int width; + std::vector data; +}; + namespace Internal { + glm::vec3 defaultSpherePos(); glm::vec3 defaultLightPos(); + // returns pos of collision std::optional rayToSphere( glm::vec3 rayPos, glm::vec3 rayDir, @@ -30,22 +54,25 @@ namespace Internal { float angleBetweenRays( glm::vec3 a, glm::vec3 b); + + // first vec3 is result from rayToSphere(), second is ray to light source + typedef std::optional> RTSVisibleType; + RTSVisibleType rayToSphereVisible( + glm::vec3 rayPos, + glm::vec3 rayDir, + glm::vec3 spherePos, + float sphereRadius, + glm::vec3 lightPos); } -std::vector renderGraySphere( +Image renderGraySphere( unsigned int outputWidth, unsigned int outputHeight, - float sphereRadius, int threadCount = 1, glm::vec3 spherePos = Internal::defaultSpherePos(), glm::vec3 lightPos = Internal::defaultLightPos() ); -void writeGrayscaleToFile( - const std::vector &pixels, - unsigned int outputWidth, - std::string filename); - } // namespace RT } // namespace Ex02