8 changed files with 326 additions and 24 deletions
+2
View File
@@ -18,6 +18,7 @@ find_package(glm CONFIG REQUIRED)
find_package(Ktx CONFIG REQUIRED) find_package(Ktx CONFIG REQUIRED)
find_package(imgui CONFIG REQUIRED) find_package(imgui CONFIG REQUIRED)
find_package(slang CONFIG REQUIRED) find_package(slang CONFIG REQUIRED)
find_package(CLI11 CONFIG REQUIRED)
add_executable(RayTracer "") add_executable(RayTracer "")
target_include_directories(RayTracer PUBLIC src/) target_include_directories(RayTracer PUBLIC src/)
@@ -28,6 +29,7 @@ target_link_libraries(RayTracer PUBLIC GLEW::GLEW)
target_link_libraries(RayTracer PUBLIC glm::glm) target_link_libraries(RayTracer PUBLIC glm::glm)
target_link_libraries(RayTracer PUBLIC KTX::ktx) target_link_libraries(RayTracer PUBLIC KTX::ktx)
target_link_libraries(RayTracer PUBLIC slang::slang) target_link_libraries(RayTracer PUBLIC slang::slang)
target_link_libraries(RayTracer PUBLIC CLI11::CLI11)
if(APPLE) if(APPLE)
target_include_directories(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/arm64-osx/include) target_include_directories(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/arm64-osx/include)
+27 -13
View File
@@ -2,32 +2,46 @@
#include "cpu/CPURenderer.h" #include "cpu/CPURenderer.h"
#include "metal/MetalRenderer.h" #include "metal/MetalRenderer.h"
#include "util/ModelLoader.h" #include "util/ModelLoader.h"
#include "util/CLI.h"
#include <imgui.h> #include <imgui.h>
int main() int main(int argc, const char* argv[])
{ {
// Parse command-line arguments
CLIOptions cliOpts = AppCLI::parseArgs(argc, argv);
// If help was requested, just exit after printing
if (cliOpts.showHelp)
{
return 0;
}
std::unique_ptr<Renderer> renderer = std::make_unique<MetalRenderer>(); std::unique_ptr<Renderer> renderer = std::make_unique<MetalRenderer>();
// Add lights from CLI (use defaults if none specified)
if (cliOpts.directionalLights.empty() && cliOpts.pointLights.empty())
{
// Default lights if no CLI lights specified
renderer->addDirectionalLight(DirectionalLight{ renderer->addDirectionalLight(DirectionalLight{
.direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)), .direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)),
.color = glm::vec3(1, 1, 1), .color = glm::vec3(1, 1, 1),
}); });
renderer->addPointLight(PointLight{}); renderer->addPointLight(PointLight{});
}
else
{
AppCLI::applyLights(renderer.get(), cliOpts);
}
renderer->addModels(ModelLoader::loadModel("../res/models/stanford-bunny.obj"), renderer->addModels(ModelLoader::loadModel("../res/models/stanford-bunny.obj"),
glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f))); glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)));
renderer->generate(); renderer->generate();
Camera camera = Camera{
.position = glm::vec3(2, 1, 2), // Create camera and render parameters from CLI options
.target = glm::vec3(0, 0, 0), Camera camera = AppCLI::toCamera(cliOpts);
.f = 0, RenderParameter render = AppCLI::toRenderParameter(cliOpts);
.A = 0,
.S_O = 6,
};
RenderParameter render = RenderParameter{
.width = 1920,
.height = 1080,
.numSamples = 10000,
};
renderer->startRender(camera, render); renderer->startRender(camera, render);
while (true) while (true)
+3 -3
View File
@@ -195,10 +195,10 @@ void MetalRenderer::render(Camera camera, RenderParameter parameter)
.f = camera.f, .f = camera.f,
.cameraForward = camera.target - camera.position, .cameraForward = camera.target - camera.position,
.S_O = camera.S_O, .S_O = camera.S_O,
.fogEmm = glm::vec3(0, 0, 0), .fogEmm = camera.fogEmm,
.ks = 0, .ks = camera.ks,
.A = camera.A, .A = camera.A,
.ka = 0, .ka = camera.ka,
.sensorSize = camera.sensorSize, .sensorSize = camera.sensorSize,
.width = parameter.width, .width = parameter.width,
.height = parameter.height, .height = parameter.height,
+225
View File
@@ -0,0 +1,225 @@
#include "CLI.h"
#include <CLI/CLI.hpp>
#include <iostream>
namespace AppCLI
{
void printHelp()
{
std::cout << R"(
Usage: RayTracer [options]
Render Parameters:
-w, --width <int> Image width (default: 1920)
--height <int> Image height (default: 1080)
-s, --samples <int> Number of samples per pixel (default: 10000)
-b, --bounces <int> Maximum ray bounces (default: 4)
--bg-color <r> <g> <b> Background/sky color (default: 0.05 0.05 0.1)
--throughput <float> Minimum throughput threshold (default: 0.01)
-o, --output <file> Output image file path (PGM format)
Camera Parameters:
--cam-pos <x> <y> <z> Camera position (default: 2 1 2)
--cam-target <x> <y> <z> Camera target (default: 0 0 0)
--cam-focal <float> Focal length (default: 0.7)
--cam-aperture <float> Aperture size (default: 0.35)
--cam-distance <float> Subject distance S_O (default: 20)
--cam-sensor <w> <h> Sensor size (default: 0.036 0.024)
Camera Shading Parameters:
--fog-emission <r> <g> <b> Fog emission color (default: 0 0 0)
--specular-coeff <float> Specular coefficient ks (default: 0)
--ambient-coeff <float> Ambient coefficient ka (default: 0)
Light Parameters:
--dir-light <dx> <dy> <dz> <r> <g> <b>
Add directional light (direction + color)
--point-light <x> <y> <z> <r> <g> <b> <att>
Add point light (position + color + attenuation)
Other:
-h, --help Show this help message
Examples:
RayTracer -w 1280 --height 720 -s 1000
RayTracer --cam-pos 3 2 3 --cam-focal 0.5
RayTracer --dir-light -0.4 -0.3 -0.2 1 1 1
RayTracer --point-light 0 5 0 1 0.5 0 0.5
RayTracer --fog-emission 0.1 0.2 0.3 --specular-coeff 0.5 --ambient-coeff 0.2
RayTracer -b 8 --bg-color 0.1 0.1 0.2 -o output.pgm
)";
}
CLIOptions parseArgs(int argc, const char* argv[])
{
CLIOptions options;
::CLI::App app{"RayTracer - A Path Tracing Renderer"};
app.set_help_flag("-h,--help", "Show this help message");
// Render parameters
app.add_option_group("Render Parameters")->add_option(
"-w,--width", options.width, "Image width");
app.add_option("--height", options.height, "Image height");
app.add_option("-s,--samples", options.numSamples, "Number of samples per pixel");
app.add_option("-b,--bounces", options.maxBounces, "Maximum ray bounces");
app.add_option("--throughput", options.throughputThreshold, "Minimum throughput threshold");
app.add_option("-o,--output", options.outputFile, "Output image file path");
// Background color (3 floats)
std::vector<float> bgColor(3, 0.0f);
app.add_option("--bg-color", bgColor, "Background/sky color (r g b)")
->expected(3);
// Camera parameters
std::vector<float> camPos(3, 0.0f);
app.add_option("--cam-pos", camPos, "Camera position (x y z)")
->expected(3);
std::vector<float> camTarget(3, 0.0f);
app.add_option("--cam-target", camTarget, "Camera target (x y z)")
->expected(3);
app.add_option("--cam-focal", options.camFocalLength, "Focal length");
app.add_option("--cam-aperture", options.camAperture, "Aperture size");
app.add_option("--cam-distance", options.camDistance, "Subject distance S_O");
std::vector<float> camSensor(2, 0.0f);
app.add_option("--cam-sensor", camSensor, "Sensor size (w h)")
->expected(2);
// Camera shading parameters
std::vector<float> fogEmission(3, 0.0f);
app.add_option("--fog-emission", fogEmission, "Fog emission color (r g b)")
->expected(3);
app.add_option("--specular-coeff", options.specularCoeff, "Specular coefficient ks");
app.add_option("--ambient-coeff", options.ambientCoeff, "Ambient coefficient ka");
// Light parameters - using TakeAll policy to allow multiple occurrences
std::vector<std::vector<float>> dirLightArgs;
app.add_option("--dir-light", dirLightArgs, "Add directional light (dx dy dz r g b)")
->expected(6)
->multi_option_policy(::CLI::MultiOptionPolicy::TakeAll);
std::vector<std::vector<float>> pointLightArgs;
app.add_option("--point-light", pointLightArgs, "Add point light (x y z r g b attenuation)")
->expected(7)
->multi_option_policy(::CLI::MultiOptionPolicy::TakeAll);
// Parse arguments
bool helpRequested = false;
try
{
app.parse(argc, argv);
}
catch (const ::CLI::CallForHelp& e)
{
helpRequested = true;
}
catch (const ::CLI::CallForAllHelp& e)
{
helpRequested = true;
}
catch (const ::CLI::ParseError& e)
{
std::cerr << e.what() << std::endl;
return options;
}
// Check if help was requested
if (helpRequested || app.get_help_ptr()->count() > 0)
{
options.showHelp = true;
printHelp();
return options;
}
// Process background color
if (bgColor.size() == 3)
{
options.backgroundColor = glm::vec3(bgColor[0], bgColor[1], bgColor[2]);
}
// Process camera position
if (camPos.size() == 3)
{
options.camPosition = glm::vec3(camPos[0], camPos[1], camPos[2]);
}
// Process camera target
if (camTarget.size() == 3)
{
options.camTarget = glm::vec3(camTarget[0], camTarget[1], camTarget[2]);
}
// Process camera sensor size
if (camSensor.size() == 2)
{
options.camSensorSize = glm::vec2(camSensor[0], camSensor[1]);
}
// Process fog emission
if (fogEmission.size() == 3)
{
options.fogEmission = glm::vec3(fogEmission[0], fogEmission[1], fogEmission[2]);
}
// Process directional lights
for (const auto& args : dirLightArgs)
{
if (args.size() == 6)
{
DirectionalLight light;
light.direction = glm::vec3(args[0], args[1], args[2]);
light.color = glm::vec3(args[3], args[4], args[5]);
options.directionalLights.push_back(light);
}
}
// Process point lights
for (const auto& args : pointLightArgs)
{
if (args.size() == 7)
{
PointLight light;
light.position = glm::vec3(args[0], args[1], args[2]);
light.color = glm::vec3(args[3], args[4], args[5]);
light.attenuation = args[6];
options.pointLights.push_back(light);
}
}
return options;
}
Camera toCamera(const CLIOptions& opts)
{
return Camera{
.position = opts.camPosition,
.target = opts.camTarget,
.sensorSize = opts.camSensorSize,
.S_O = opts.camDistance,
.f = opts.camFocalLength,
.A = opts.camAperture,
.fogEmm = opts.fogEmission,
.ks = opts.specularCoeff,
.ka = opts.ambientCoeff
};
}
RenderParameter toRenderParameter(const CLIOptions& opts)
{
return RenderParameter{
.width = opts.width,
.height = opts.height,
.numSamples = opts.numSamples
};
}
void applyLights(Renderer* renderer, const CLIOptions& opts)
{
for (const auto& dirLight : opts.directionalLights)
{
renderer->addDirectionalLight(dirLight);
}
for (const auto& pointLight : opts.pointLights)
{
renderer->addPointLight(pointLight);
}
}
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "Camera.h"
#include "scene/Renderer.h"
#include <string>
#include <vector>
#include <glm/glm.hpp>
struct CLIOptions
{
// Render parameters
uint32_t width = 1920;
uint32_t height = 1080;
uint32_t numSamples = 10000;
uint32_t maxBounces = 4;
glm::vec3 backgroundColor = glm::vec3(0.05f, 0.05f, 0.1f);
float throughputThreshold = 0.01f;
std::string outputFile;
// Camera parameters
glm::vec3 camPosition = glm::vec3(2, 1, 2);
glm::vec3 camTarget = glm::vec3(0, 0, 0);
float camFocalLength = 0.7f;
float camAperture = 0.35f;
float camDistance = 20.0f;
glm::vec2 camSensorSize = glm::vec2(0.036f, 0.024f);
// Camera shading parameters
glm::vec3 fogEmission = glm::vec3(0, 0, 0);
float specularCoeff = 0.0f;
float ambientCoeff = 0.0f;
// Light parameters
std::vector<DirectionalLight> directionalLights;
std::vector<PointLight> pointLights;
bool showHelp = false;
};
namespace AppCLI
{
// Parse command-line arguments and return CLIOptions
CLIOptions parseArgs(int argc, const char* argv[]);
// Print help message
void printHelp();
// Convert CLIOptions to Camera struct
Camera toCamera(const CLIOptions& opts);
// Convert CLIOptions to RenderParameter struct
RenderParameter toRenderParameter(const CLIOptions& opts);
// Apply lights from CLIOptions to renderer
void applyLights(Renderer* renderer, const CLIOptions& opts);
}
+2
View File
@@ -3,6 +3,8 @@ target_sources(RayTracer
BRDF.h BRDF.h
BRDF.cpp BRDF.cpp
Camera.h Camera.h
CLI.h
CLI.cpp
Material.h Material.h
Material.cpp Material.cpp
Model.h Model.h
+3
View File
@@ -9,4 +9,7 @@ struct Camera
float S_O = 20; float S_O = 20;
float f = 0.7; float f = 0.7;
float A = 0.35; float A = 0.35;
glm::vec3 fogEmm = glm::vec3(0, 0, 0);
float ks = 0;
float ka = 0;
}; };
+1
View File
@@ -5,6 +5,7 @@
"features": [ "glfw-binding", "opengl3-binding", "metal-binding" ] "features": [ "glfw-binding", "opengl3-binding", "metal-binding" ]
}, },
"assimp", "assimp",
"cli11",
"ktx", "ktx",
"glfw3", "glfw3",
"glew", "glew",