2026-08-09 16:18:57 +02:00
|
|
|
#include "CLI.h"
|
2026-08-09 17:12:54 +02:00
|
|
|
#include <CLI/CLI.hpp>
|
2026-08-09 16:18:57 +02:00
|
|
|
#include <iostream>
|
|
|
|
|
|
2026-08-09 17:12:54 +02:00
|
|
|
namespace AppCLI
|
2026-08-09 16:18:57 +02:00
|
|
|
{
|
|
|
|
|
void printHelp()
|
|
|
|
|
{
|
|
|
|
|
std::cout << R"(
|
|
|
|
|
Usage: RayTracer [options]
|
|
|
|
|
|
|
|
|
|
Render Parameters:
|
|
|
|
|
-w, --width <int> Image width (default: 1920)
|
2026-08-09 17:12:54 +02:00
|
|
|
--height <int> Image height (default: 1080)
|
2026-08-09 16:18:57 +02:00
|
|
|
-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:
|
2026-08-09 17:12:54 +02:00
|
|
|
-h, --help Show this help message
|
2026-08-09 16:18:57 +02:00
|
|
|
|
|
|
|
|
Examples:
|
2026-08-09 17:12:54 +02:00
|
|
|
RayTracer -w 1280 --height 720 -s 1000
|
2026-08-09 16:18:57 +02:00
|
|
|
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;
|
2026-08-09 17:12:54 +02:00
|
|
|
::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
|
2026-08-09 16:18:57 +02:00
|
|
|
{
|
2026-08-09 17:12:54 +02:00
|
|
|
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;
|
2026-08-09 16:18:57 +02:00
|
|
|
}
|
|
|
|
|
|
2026-08-09 17:12:54 +02:00
|
|
|
// Check if help was requested
|
|
|
|
|
if (helpRequested || app.get_help_ptr()->count() > 0)
|
2026-08-09 16:18:57 +02:00
|
|
|
{
|
2026-08-09 17:12:54 +02:00
|
|
|
options.showHelp = true;
|
|
|
|
|
printHelp();
|
|
|
|
|
return options;
|
|
|
|
|
}
|
2026-08-09 16:18:57 +02:00
|
|
|
|
2026-08-09 17:12:54 +02:00
|
|
|
// 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)
|
2026-08-09 16:18:57 +02:00
|
|
|
{
|
|
|
|
|
DirectionalLight light;
|
2026-08-09 17:12:54 +02:00
|
|
|
light.direction = glm::vec3(args[0], args[1], args[2]);
|
|
|
|
|
light.color = glm::vec3(args[3], args[4], args[5]);
|
2026-08-09 16:18:57 +02:00
|
|
|
options.directionalLights.push_back(light);
|
|
|
|
|
}
|
2026-08-09 17:12:54 +02:00
|
|
|
}
|
2026-08-09 16:18:57 +02:00
|
|
|
|
2026-08-09 17:12:54 +02:00
|
|
|
// 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);
|
|
|
|
|
}
|
2026-08-09 16:18:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|