Refactorings
This commit is contained in:
parent
653f0cafcb
commit
48c5d42c74
3 changed files with 123 additions and 81 deletions
|
@ -11,7 +11,6 @@ void printHelp() {
|
||||||
" | --threads <integer> Set the number of threads to use (default 1)\n"
|
" | --threads <integer> Set the number of threads to use (default 1)\n"
|
||||||
"--width <integer> Set the width of the output image\n"
|
"--width <integer> Set the width of the output image\n"
|
||||||
"--height <integer> Set the height of the output image\n"
|
"--height <integer> Set the height of the output image\n"
|
||||||
"--radius <float> Set the radius of the sphere\n"
|
|
||||||
"-o <filename>\n"
|
"-o <filename>\n"
|
||||||
" | --output <filename> Set the output filename for the image"
|
" | --output <filename> Set the output filename for the image"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
@ -21,7 +20,6 @@ int main(int argc, char **argv) {
|
||||||
int threadCount = 1;
|
int threadCount = 1;
|
||||||
unsigned int outputWidth = 1600;
|
unsigned int outputWidth = 1600;
|
||||||
unsigned int outputHeight = 1600;
|
unsigned int outputHeight = 1600;
|
||||||
float sphereRadius = 1.5f;
|
|
||||||
std::string outputFile = "raytrace_out";
|
std::string outputFile = "raytrace_out";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -37,7 +35,6 @@ int main(int argc, char **argv) {
|
||||||
"--threads",
|
"--threads",
|
||||||
"--width",
|
"--width",
|
||||||
"--height",
|
"--height",
|
||||||
"--radius",
|
|
||||||
"-o",
|
"-o",
|
||||||
"--output",
|
"--output",
|
||||||
});
|
});
|
||||||
|
@ -114,24 +111,6 @@ int main(int argc, char **argv) {
|
||||||
std::cout << "ERROR: height cannot be 0" << std::endl;
|
std::cout << "ERROR: height cannot be 0" << std::endl;
|
||||||
return 8;
|
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()) {
|
if(auto iter = results.find("-o"); iter != results.end()) {
|
||||||
outputFile = iter->second;
|
outputFile = iter->second;
|
||||||
} else if(auto iter = results.find("--output"); iter != results.end()) {
|
} 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(
|
auto pixels = Ex02::RT::renderGraySphere(
|
||||||
outputWidth, outputHeight, sphereRadius, threadCount);
|
outputWidth, outputHeight, threadCount);
|
||||||
|
|
||||||
Ex02::RT::writeGrayscaleToFile(pixels, outputWidth, outputFile);
|
pixels.writeToFile(outputFile);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,43 @@
|
||||||
|
|
||||||
const float PI = std::acos(-1.0f);
|
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() {
|
glm::vec3 Ex02::RT::Internal::defaultSpherePos() {
|
||||||
return glm::vec3{0.0f, 0.0f, -2.5f};
|
return glm::vec3{0.0f, 0.0f, -2.5f};
|
||||||
}
|
}
|
||||||
|
@ -44,13 +81,6 @@ std::optional<glm::vec3> Ex02::RT::Internal::rayToSphere(
|
||||||
glm::vec3 rayDir,
|
glm::vec3 rayDir,
|
||||||
glm::vec3 spherePos,
|
glm::vec3 spherePos,
|
||||||
float sphereRadius) {
|
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
|
// check if there is collision
|
||||||
glm::vec3 tempVec = rayPos - spherePos;
|
glm::vec3 tempVec = rayPos - spherePos;
|
||||||
float temp =
|
float temp =
|
||||||
|
@ -96,15 +126,44 @@ float Ex02::RT::Internal::angleBetweenRays(glm::vec3 a, glm::vec3 b) {
|
||||||
return std::acos(dot / amag / bmag);
|
return std::acos(dot / amag / bmag);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> 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 outputWidth,
|
||||||
unsigned int outputHeight,
|
unsigned int outputHeight,
|
||||||
float sphereRadius,
|
|
||||||
int threadCount,
|
int threadCount,
|
||||||
glm::vec3 spherePos,
|
glm::vec3 spherePos,
|
||||||
glm::vec3 lightPos) {
|
glm::vec3 lightPos) {
|
||||||
std::vector<unsigned char> grayscalePixels;
|
Image image(outputWidth, outputHeight);
|
||||||
grayscalePixels.resize(outputWidth * outputHeight);
|
|
||||||
glm::vec3 rayPos{0.0f, 0.0f, 0.0f};
|
glm::vec3 rayPos{0.0f, 0.0f, 0.0f};
|
||||||
float lightFalloffStart = 4.5f;
|
float lightFalloffStart = 4.5f;
|
||||||
float lightFalloffEnd = 7.0f;
|
float lightFalloffEnd = 7.0f;
|
||||||
|
@ -115,33 +174,27 @@ std::vector<unsigned char> Ex02::RT::renderGraySphere(
|
||||||
float offsetX = ((float)i + 0.5f - ((float)outputWidth / 2.0f));
|
float offsetX = ((float)i + 0.5f - ((float)outputWidth / 2.0f));
|
||||||
glm::vec3 rayDir = glm::vec3{
|
glm::vec3 rayDir = glm::vec3{
|
||||||
offsetX, offsetY, -(float)outputHeight * EX02_RAY_TRACER_VIEW_RATIO};
|
offsetX, offsetY, -(float)outputHeight * EX02_RAY_TRACER_VIEW_RATIO};
|
||||||
auto rayResult = Internal::rayToSphere(
|
auto rayResult = Internal::rayToSphereVisible(
|
||||||
rayPos, rayDir, spherePos, sphereRadius);
|
rayPos, rayDir,
|
||||||
|
spherePos, EX02_RAY_TRACER_GRAY_SPHERE_RADIUS,
|
||||||
|
lightPos);
|
||||||
if(rayResult) {
|
if(rayResult) {
|
||||||
glm::vec3 toLight = lightPos - *rayResult;
|
glm::vec3 *toLight = &std::get<1>(rayResult.value());
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
float dist = std::sqrt(
|
float dist = std::sqrt(
|
||||||
toLightCached.x * toLightCached.x
|
toLight->x * toLight->x
|
||||||
+ toLightCached.y * toLightCached.y
|
+ toLight->y * toLight->y
|
||||||
+ toLightCached.z * toLightCached.z);
|
+ toLight->z * toLight->z);
|
||||||
if(dist < lightFalloffStart) {
|
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) {
|
} else if(dist >= lightFalloffStart && dist <= lightFalloffEnd) {
|
||||||
grayscalePixels.at(i + j * outputWidth) =
|
image.getPixel(i, j).r =
|
||||||
(1.0f - (dist - lightFalloffStart)
|
(1.0f - (dist - lightFalloffStart)
|
||||||
/ (lightFalloffEnd - lightFalloffStart))
|
/ (lightFalloffEnd - lightFalloffStart))
|
||||||
* 255.0f;
|
* 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<unsigned char> Ex02::RT::renderGraySphere(
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
|
||||||
return grayscalePixels;
|
return image;
|
||||||
}
|
|
||||||
|
|
||||||
void Ex02::RT::writeGrayscaleToFile(
|
|
||||||
const std::vector<unsigned char> &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';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
#define EX02_RAY_TRACER_DEFAULT_NEAR_PLANE 0.2f
|
#define EX02_RAY_TRACER_DEFAULT_NEAR_PLANE 0.2f
|
||||||
#define EX02_RAY_TRACER_DEFAULT_FAR_PLANE 4.0f
|
#define EX02_RAY_TRACER_DEFAULT_FAR_PLANE 4.0f
|
||||||
#define EX02_RAY_TRACER_COLL_INCREMENT 2.0f
|
#define EX02_RAY_TRACER_COLL_INCREMENT 2.0f
|
||||||
|
#define EX02_RAY_TRACER_GRAY_SPHERE_RADIUS 1.5f
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include <glm/vec3.hpp>
|
#include <glm/vec3.hpp>
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
|
@ -17,10 +19,32 @@
|
||||||
namespace Ex02 {
|
namespace Ex02 {
|
||||||
namespace RT {
|
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<Pixel> data;
|
||||||
|
};
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
glm::vec3 defaultSpherePos();
|
glm::vec3 defaultSpherePos();
|
||||||
glm::vec3 defaultLightPos();
|
glm::vec3 defaultLightPos();
|
||||||
|
|
||||||
|
// returns pos of collision
|
||||||
std::optional<glm::vec3> rayToSphere(
|
std::optional<glm::vec3> rayToSphere(
|
||||||
glm::vec3 rayPos,
|
glm::vec3 rayPos,
|
||||||
glm::vec3 rayDir,
|
glm::vec3 rayDir,
|
||||||
|
@ -30,22 +54,25 @@ namespace Internal {
|
||||||
float angleBetweenRays(
|
float angleBetweenRays(
|
||||||
glm::vec3 a,
|
glm::vec3 a,
|
||||||
glm::vec3 b);
|
glm::vec3 b);
|
||||||
|
|
||||||
|
// first vec3 is result from rayToSphere(), second is ray to light source
|
||||||
|
typedef std::optional<std::tuple<glm::vec3, glm::vec3>> RTSVisibleType;
|
||||||
|
RTSVisibleType rayToSphereVisible(
|
||||||
|
glm::vec3 rayPos,
|
||||||
|
glm::vec3 rayDir,
|
||||||
|
glm::vec3 spherePos,
|
||||||
|
float sphereRadius,
|
||||||
|
glm::vec3 lightPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> renderGraySphere(
|
Image renderGraySphere(
|
||||||
unsigned int outputWidth,
|
unsigned int outputWidth,
|
||||||
unsigned int outputHeight,
|
unsigned int outputHeight,
|
||||||
float sphereRadius,
|
|
||||||
int threadCount = 1,
|
int threadCount = 1,
|
||||||
glm::vec3 spherePos = Internal::defaultSpherePos(),
|
glm::vec3 spherePos = Internal::defaultSpherePos(),
|
||||||
glm::vec3 lightPos = Internal::defaultLightPos()
|
glm::vec3 lightPos = Internal::defaultLightPos()
|
||||||
);
|
);
|
||||||
|
|
||||||
void writeGrayscaleToFile(
|
|
||||||
const std::vector<unsigned char> &pixels,
|
|
||||||
unsigned int outputWidth,
|
|
||||||
std::string filename);
|
|
||||||
|
|
||||||
} // namespace RT
|
} // namespace RT
|
||||||
} // namespace Ex02
|
} // namespace Ex02
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue