Compare commits
2
Commits
fb6b84a7b7
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ea6fd3fae | ||
|
|
3df9b0d495 |
+32
-18
@@ -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 = CLI::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>();
|
||||||
renderer->addDirectionalLight(DirectionalLight{
|
|
||||||
.direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)),
|
// Add lights from CLI (use defaults if none specified)
|
||||||
.color = glm::vec3(1, 1, 1),
|
if (cliOpts.directionalLights.empty() && cliOpts.pointLights.empty())
|
||||||
});
|
{
|
||||||
renderer->addPointLight(PointLight{});
|
// Default lights if no CLI lights specified
|
||||||
|
renderer->addDirectionalLight(DirectionalLight{
|
||||||
|
.direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)),
|
||||||
|
.color = glm::vec3(1, 1, 1),
|
||||||
|
});
|
||||||
|
renderer->addPointLight(PointLight{});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CLI::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 = CLI::toCamera(cliOpts);
|
||||||
.f = 0,
|
RenderParameter render = CLI::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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -0,0 +1,353 @@
|
|||||||
|
#include "CLI.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace CLI
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
float parseFloat(const std::string& str, const std::string& argName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return std::stof(str);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Invalid float value for " << argName << ": " << str << "\n";
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t parseUInt(const std::string& str, const std::string& argName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return static_cast<uint32_t>(std::stoul(str));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Invalid unsigned integer value for " << argName << ": " << str << "\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 parseVec3(const std::vector<std::string>& tokens, size_t offset, const std::string& argName)
|
||||||
|
{
|
||||||
|
if (offset + 3 > tokens.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: " << argName << " requires 3 float values (x y z)\n";
|
||||||
|
return glm::vec3(0, 0, 0);
|
||||||
|
}
|
||||||
|
return glm::vec3(
|
||||||
|
parseFloat(tokens[offset], argName + " x"),
|
||||||
|
parseFloat(tokens[offset + 1], argName + " y"),
|
||||||
|
parseFloat(tokens[offset + 2], argName + " z")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 parseVec2(const std::vector<std::string>& tokens, size_t offset, const std::string& argName)
|
||||||
|
{
|
||||||
|
if (offset + 2 > tokens.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: " << argName << " requires 2 float values\n";
|
||||||
|
return glm::vec2(0, 0);
|
||||||
|
}
|
||||||
|
return glm::vec2(
|
||||||
|
parseFloat(tokens[offset], argName + " x"),
|
||||||
|
parseFloat(tokens[offset + 1], argName + " y")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printHelp()
|
||||||
|
{
|
||||||
|
std::cout << R"(
|
||||||
|
Usage: RayTracer [options]
|
||||||
|
|
||||||
|
Render Parameters:
|
||||||
|
-w, --width <int> Image width (default: 1920)
|
||||||
|
-h, --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:
|
||||||
|
--help Show this help message
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
RayTracer -w 1280 -h 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;
|
||||||
|
std::vector<std::string> args;
|
||||||
|
for (int i = 1; i < argc; ++i)
|
||||||
|
{
|
||||||
|
args.push_back(argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < args.size())
|
||||||
|
{
|
||||||
|
const std::string& arg = args[i];
|
||||||
|
|
||||||
|
if (arg == "--help")
|
||||||
|
{
|
||||||
|
options.showHelp = true;
|
||||||
|
printHelp();
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
else if (arg == "--width" || arg == "-w")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --width requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.width = parseUInt(args[++i], "width");
|
||||||
|
}
|
||||||
|
else if (arg == "--height" || arg == "-h")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --height requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.height = parseUInt(args[++i], "height");
|
||||||
|
}
|
||||||
|
else if (arg == "--samples" || arg == "-s")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --samples requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.numSamples = parseUInt(args[++i], "samples");
|
||||||
|
}
|
||||||
|
else if (arg == "--bounces" || arg == "-b")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --bounces requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.maxBounces = parseUInt(args[++i], "bounces");
|
||||||
|
}
|
||||||
|
else if (arg == "--bg-color")
|
||||||
|
{
|
||||||
|
if (i + 3 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --bg-color requires 3 values (r g b)\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.backgroundColor = parseVec3(args, i + 1, "bg-color");
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
else if (arg == "--throughput")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --throughput requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.throughputThreshold = parseFloat(args[++i], "throughput");
|
||||||
|
}
|
||||||
|
else if (arg == "--output" || arg == "-o")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --output requires a file path\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.outputFile = args[++i];
|
||||||
|
}
|
||||||
|
else if (arg == "--cam-pos")
|
||||||
|
{
|
||||||
|
if (i + 3 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --cam-pos requires 3 values (x y z)\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.camPosition = parseVec3(args, i + 1, "cam-pos");
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
else if (arg == "--cam-target")
|
||||||
|
{
|
||||||
|
if (i + 3 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --cam-target requires 3 values (x y z)\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.camTarget = parseVec3(args, i + 1, "cam-target");
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
else if (arg == "--cam-focal")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --cam-focal requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.camFocalLength = parseFloat(args[++i], "cam-focal");
|
||||||
|
}
|
||||||
|
else if (arg == "--cam-aperture")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --cam-aperture requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.camAperture = parseFloat(args[++i], "cam-aperture");
|
||||||
|
}
|
||||||
|
else if (arg == "--cam-distance")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --cam-distance requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.camDistance = parseFloat(args[++i], "cam-distance");
|
||||||
|
}
|
||||||
|
else if (arg == "--cam-sensor")
|
||||||
|
{
|
||||||
|
if (i + 2 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --cam-sensor requires 2 values (w h)\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.camSensorSize = parseVec2(args, i + 1, "cam-sensor");
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
else if (arg == "--fog-emission")
|
||||||
|
{
|
||||||
|
if (i + 3 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --fog-emission requires 3 values (r g b)\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.fogEmission = parseVec3(args, i + 1, "fog-emission");
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
else if (arg == "--specular-coeff")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --specular-coeff requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.specularCoeff = parseFloat(args[++i], "specular-coeff");
|
||||||
|
}
|
||||||
|
else if (arg == "--ambient-coeff")
|
||||||
|
{
|
||||||
|
if (i + 1 >= args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --ambient-coeff requires a value\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
options.ambientCoeff = parseFloat(args[++i], "ambient-coeff");
|
||||||
|
}
|
||||||
|
else if (arg == "--dir-light")
|
||||||
|
{
|
||||||
|
if (i + 6 > args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --dir-light requires 6 values (dx dy dz r g b)\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
DirectionalLight light;
|
||||||
|
light.direction = parseVec3(args, i + 1, "dir-light direction");
|
||||||
|
light.color = parseVec3(args, i + 4, "dir-light color");
|
||||||
|
options.directionalLights.push_back(light);
|
||||||
|
i += 6;
|
||||||
|
}
|
||||||
|
else if (arg == "--point-light")
|
||||||
|
{
|
||||||
|
if (i + 7 > args.size())
|
||||||
|
{
|
||||||
|
std::cerr << "Error: --point-light requires 7 values (x y z r g b attenuation)\n";
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
PointLight light;
|
||||||
|
light.position = parseVec3(args, i + 1, "point-light position");
|
||||||
|
light.color = parseVec3(args, i + 4, "point-light color");
|
||||||
|
light.attenuation = parseFloat(args[i + 7], "point-light attenuation");
|
||||||
|
options.pointLights.push_back(light);
|
||||||
|
i += 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: Unknown argument: " << arg << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 CLI
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -14,4 +16,4 @@ target_sources(RayTracer
|
|||||||
Texture.cpp
|
Texture.cpp
|
||||||
TextureLoader.h
|
TextureLoader.h
|
||||||
TextureLoader.cpp
|
TextureLoader.cpp
|
||||||
)
|
)
|
||||||
|
|||||||
+4
-1
@@ -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;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user