EX02 Working impl, still kind of WIP
This commit is contained in:
parent
fb25c80d0a
commit
2bf4dd0cf7
3 changed files with 217 additions and 6 deletions
|
@ -2,17 +2,27 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "argParse.hpp"
|
#include "argParse.hpp"
|
||||||
|
#include "rayTracer.hpp"
|
||||||
|
|
||||||
void printHelp() {
|
void printHelp() {
|
||||||
std::cout << "Usage:\n"
|
std::cout << "Usage:\n"
|
||||||
"-h | --help Display this help message\n"
|
"-h | --help Display this help message\n"
|
||||||
"-t <integer>\n"
|
"-t <integer>\n"
|
||||||
" | --threads <integer> Set the number of threads to use (default 1)"
|
" | --threads <integer> Set the number of threads to use (default 1)\n"
|
||||||
|
"--width <integer> Set the width 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"
|
||||||
|
" | --output <filename> Set the output filename for the image"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
int threadCount = 1;
|
int threadCount = 1;
|
||||||
|
unsigned int outputWidth = 1600;
|
||||||
|
unsigned int outputHeight = 1600;
|
||||||
|
float sphereRadius = 1.5f;
|
||||||
|
std::string outputFile = "raytrace_out";
|
||||||
|
|
||||||
{
|
{
|
||||||
auto results = Ex02::ArgParse::parseArgs(
|
auto results = Ex02::ArgParse::parseArgs(
|
||||||
|
@ -25,6 +35,11 @@ int main(int argc, char **argv) {
|
||||||
{ // double args
|
{ // double args
|
||||||
"-t",
|
"-t",
|
||||||
"--threads",
|
"--threads",
|
||||||
|
"--width",
|
||||||
|
"--height",
|
||||||
|
"--radius",
|
||||||
|
"-o",
|
||||||
|
"--output",
|
||||||
});
|
});
|
||||||
|
|
||||||
if(auto iter = results.find("-h"); iter != results.end()) {
|
if(auto iter = results.find("-h"); iter != results.end()) {
|
||||||
|
@ -58,7 +73,6 @@ int main(int argc, char **argv) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(threadCount <= 0) {
|
if(threadCount <= 0) {
|
||||||
std::cout << "ERROR: Thread count set to invalid value ("
|
std::cout << "ERROR: Thread count set to invalid value ("
|
||||||
<< threadCount
|
<< threadCount
|
||||||
|
@ -66,7 +80,73 @@ int main(int argc, char **argv) {
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
if(auto iter = results.find("--width"); iter != results.end()) {
|
||||||
|
try {
|
||||||
|
outputWidth = std::stoul(iter->second);
|
||||||
|
} catch (const std::invalid_argument &e) {
|
||||||
|
std::cout << "ERROR: Failed to parse width (invalid)"
|
||||||
|
<< std::endl;
|
||||||
|
return 3;
|
||||||
|
} catch (const std::out_of_range &e) {
|
||||||
|
std::cout << "ERROR: Failed to parse width (out of range)"
|
||||||
|
<< std::endl;
|
||||||
|
return 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if(outputWidth == 0) {
|
||||||
|
std::cout << "ERROR: width cannot be 0" << std::endl;
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
if(auto iter = results.find("--height"); iter != results.end()) {
|
||||||
|
try {
|
||||||
|
outputHeight = std::stoul(iter->second);
|
||||||
|
} catch (const std::invalid_argument &e) {
|
||||||
|
std::cout << "ERROR: Failed to parse height (invalid)"
|
||||||
|
<< std::endl;
|
||||||
|
return 5;
|
||||||
|
} catch (const std::out_of_range &e) {
|
||||||
|
std::cout << "ERROR: Failed to parse height (out of range)"
|
||||||
|
<< std::endl;
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(outputHeight == 0) {
|
||||||
|
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()) {
|
||||||
|
outputFile = iter->second;
|
||||||
|
}
|
||||||
|
if(outputFile.empty()) {
|
||||||
|
std::cout << "ERROR: Output filename is empty" << std::endl;
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pixels = Ex02::RT::renderGraySphere(
|
||||||
|
outputWidth, outputHeight, sphereRadius, threadCount);
|
||||||
|
|
||||||
|
Ex02::RT::writeGrayscaleToFile(pixels, outputWidth, outputFile);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "rayTracer.hpp"
|
#include "rayTracer.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
@ -15,7 +16,7 @@ glm::vec3 Ex02::RT::Internal::defaultSpherePos() {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Ex02::RT::Internal::defaultLightPos() {
|
glm::vec3 Ex02::RT::Internal::defaultLightPos() {
|
||||||
return glm::vec3{1.0f, 1.0f, 1.0f};
|
return glm::vec3{1.0f, 1.0f, 0.0f};
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4x4 Ex02::RT::Internal::defaultMVP() {
|
glm::mat4x4 Ex02::RT::Internal::defaultMVP() {
|
||||||
|
@ -31,13 +32,65 @@ glm::mat4x4 Ex02::RT::Internal::defaultMVP() {
|
||||||
glm::vec3{0.0f, 1.0f, 0.0f});
|
glm::vec3{0.0f, 1.0f, 0.0f});
|
||||||
|
|
||||||
// model pushes back by 2 units
|
// model pushes back by 2 units
|
||||||
mvp *= glm::translate(
|
mvp = glm::translate(
|
||||||
glm::identity<glm::mat4x4>(),
|
mvp,
|
||||||
glm::vec3{0.0f, 0.0f, -2.0f});
|
glm::vec3{0.0f, 0.0f, 2.0f});
|
||||||
|
|
||||||
return mvp;
|
return mvp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<glm::vec3> Ex02::RT::Internal::rayToSphere(
|
||||||
|
glm::vec3 rayPos,
|
||||||
|
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 =
|
||||||
|
rayDir.x * tempVec.x
|
||||||
|
+ rayDir.y * tempVec.y
|
||||||
|
+ rayDir.z * tempVec.z;
|
||||||
|
float delta = temp * temp;
|
||||||
|
temp =
|
||||||
|
tempVec.x * tempVec.x
|
||||||
|
+ tempVec.y * tempVec.y
|
||||||
|
+ tempVec.z * tempVec.z
|
||||||
|
- sphereRadius * sphereRadius;
|
||||||
|
delta -= temp;
|
||||||
|
|
||||||
|
if(delta < 0.0f) {
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
temp =
|
||||||
|
rayDir.x * tempVec.x
|
||||||
|
+ rayDir.y * tempVec.y
|
||||||
|
+ rayDir.z * tempVec.z;
|
||||||
|
float dist = -temp - std::sqrt(delta);
|
||||||
|
if(dist < 0.0f) {
|
||||||
|
dist = -temp + std::sqrt(delta);
|
||||||
|
if(dist < 0.0f) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {rayPos + rayDir * dist};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float Ex02::RT::Internal::angleBetweenRays(glm::vec3 a, glm::vec3 b) {
|
||||||
|
float dot = a.x * b.x + a.y * b.y + a.z * b.z;
|
||||||
|
float amag = std::sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
|
||||||
|
float bmag = std::sqrt(b.x * b.x + b.y * b.y + b.z * b.z);
|
||||||
|
|
||||||
|
return std::acos(dot / amag / bmag);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> Ex02::RT::renderGraySphere(
|
std::vector<unsigned char> Ex02::RT::renderGraySphere(
|
||||||
unsigned int outputWidth,
|
unsigned int outputWidth,
|
||||||
unsigned int outputHeight,
|
unsigned int outputHeight,
|
||||||
|
@ -47,6 +100,66 @@ std::vector<unsigned char> Ex02::RT::renderGraySphere(
|
||||||
glm::vec3 lightPos,
|
glm::vec3 lightPos,
|
||||||
glm::mat4x4 mvp) {
|
glm::mat4x4 mvp) {
|
||||||
std::vector<unsigned char> grayscalePixels;
|
std::vector<unsigned char> grayscalePixels;
|
||||||
|
grayscalePixels.resize(outputWidth * outputHeight);
|
||||||
|
|
||||||
|
// glm::vec3 tr_spherePos = mvp * glm::vec4{spherePos, 1.0f};
|
||||||
|
// glm::vec3 tr_lightPos = mvp * glm::vec4{lightPos, 1.0f};
|
||||||
|
glm::vec3 tr_spherePos = glm::vec3{0.0f, 0.0f, -2.0f};
|
||||||
|
glm::vec3 tr_lightPos = glm::vec3{1.0f, 1.0f, 0.0f};
|
||||||
|
glm::vec3 rayPos{0.0f, 0.0f, 0.0f};
|
||||||
|
if(threadCount == 1) {
|
||||||
|
for(unsigned int j = 0; j < outputHeight; ++j) {
|
||||||
|
float offsetY = ((float)j - ((float)outputHeight / 2.0f));
|
||||||
|
for(unsigned int i = 0; i < outputWidth; ++i) {
|
||||||
|
float offsetX = ((float)i - ((float)outputWidth / 2.0f));
|
||||||
|
glm::vec3 rayDir = glm::vec3{
|
||||||
|
offsetX, offsetY, -EX02_RAY_TRACER_DRAW_PLANE};
|
||||||
|
auto rayResult = Internal::rayToSphere(
|
||||||
|
rayPos, rayDir, tr_spherePos, sphereRadius);
|
||||||
|
if(rayResult) {
|
||||||
|
glm::vec3 toLight = *rayResult - tr_lightPos;
|
||||||
|
toLight /= std::sqrt(
|
||||||
|
toLight.x * toLight.x
|
||||||
|
+ toLight.y * toLight.y
|
||||||
|
+ toLight.z * toLight.z);
|
||||||
|
glm::vec3 toLightPos = *rayResult + toLight * 2.4f;
|
||||||
|
auto collResult = Internal::rayToSphere(
|
||||||
|
toLightPos, toLight, tr_spherePos, sphereRadius);
|
||||||
|
if(collResult) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 resultToLight = tr_lightPos - *rayResult;
|
||||||
|
glm::vec3 resultToOrigin = rayPos - *rayResult;
|
||||||
|
float angle = Internal::angleBetweenRays(
|
||||||
|
resultToLight,
|
||||||
|
resultToOrigin);
|
||||||
|
if(angle <= PI && angle >= 0.0f) {
|
||||||
|
grayscalePixels.at(i + j * outputWidth) =
|
||||||
|
(1.0f - angle / PI) * 255.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
|
||||||
return grayscalePixels;
|
return grayscalePixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
#ifndef EX02_RAY_TRACER_HPP
|
#ifndef EX02_RAY_TRACER_HPP
|
||||||
#define EX02_RAY_TRACER_HPP
|
#define EX02_RAY_TRACER_HPP
|
||||||
|
|
||||||
|
#define EX02_RAY_TRACER_DRAW_PLANE 500.0f
|
||||||
#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
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <glm/vec3.hpp>
|
#include <glm/vec3.hpp>
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
|
@ -18,6 +21,16 @@ namespace Internal {
|
||||||
glm::vec3 defaultSpherePos();
|
glm::vec3 defaultSpherePos();
|
||||||
glm::vec3 defaultLightPos();
|
glm::vec3 defaultLightPos();
|
||||||
glm::mat4x4 defaultMVP();
|
glm::mat4x4 defaultMVP();
|
||||||
|
|
||||||
|
std::optional<glm::vec3> rayToSphere(
|
||||||
|
glm::vec3 rayPos,
|
||||||
|
glm::vec3 rayDir,
|
||||||
|
glm::vec3 spherePos,
|
||||||
|
float sphereRadius);
|
||||||
|
|
||||||
|
float angleBetweenRays(
|
||||||
|
glm::vec3 a,
|
||||||
|
glm::vec3 b);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> renderGraySphere(
|
std::vector<unsigned char> renderGraySphere(
|
||||||
|
@ -30,6 +43,11 @@ std::vector<unsigned char> renderGraySphere(
|
||||||
glm::mat4x4 mvp = Internal::defaultMVP()
|
glm::mat4x4 mvp = Internal::defaultMVP()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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