Commit c2535f0f authored by TheNumbat's avatar TheNumbat
Browse files

upstream changes

parent 8b8ee1f1
#include "../lib/log.h"
#include "font.dat"
#include "gl.h"
#include "platform.h"
#include "font.dat"
#include <glad/glad.h>
#include <imgui/imgui.h>
#include <imgui/imgui_impl_sdl.h>
#include <imgui/imgui_impl_opengl3.h>
#include <imgui/imgui_impl_sdl.h>
#ifdef _WIN32
#include <ShellScalingApi.h>
#include <ConsoleApi.h>
#include <ShellScalingApi.h>
extern "C" {
__declspec(dllexport) bool NvOptimusEnablement = true;
__declspec(dllexport) bool AmdPowerXpressRequestHighPerformance = true;
__declspec(dllexport) bool NvOptimusEnablement = true;
__declspec(dllexport) bool AmdPowerXpressRequestHighPerformance = true;
}
#else
#include <sys/ioctl.h>
......@@ -41,22 +41,18 @@ void Platform::remove_console() {
#endif
}
Platform::Platform() {
platform_init();
}
Platform::Platform() { platform_init(); }
Platform::~Platform() {
platform_shutdown();
}
Platform::~Platform() { platform_shutdown(); }
void Platform::platform_init() {
#ifdef _WIN32
if(SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) != S_OK)
if (SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) != S_OK)
warn("Failed to set process DPI aware.");
#endif
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
die("Failed to initialize SDL: %s", SDL_GetError());
}
......@@ -66,38 +62,39 @@ void Platform::platform_init() {
Vec2 wsize = Vec2(1280, 720);
window = SDL_CreateWindow("Scotty3D", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, (int)wsize.x, (int)wsize.y,
window = SDL_CreateWindow("Scotty3D", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
(int)wsize.x, (int)wsize.y,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
if(!window) {
if (!window) {
die("Failed to create window: %s", SDL_GetError());
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
gl_context = SDL_GL_CreateContext(window);
if(!gl_context) {
if (!gl_context) {
info("Failed to create OpenGL 4.5 context, trying 4.1 (%s)", SDL_GetError());
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
gl_context = SDL_GL_CreateContext(window);
if(!gl_context) {
if (!gl_context) {
warn("Failed to create OpenGL 4.1 context, trying 3.3 (%s)", SDL_GetError());
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
gl_context = SDL_GL_CreateContext(window);
if(!gl_context) {
if (!gl_context) {
die("Failed to create Opengl 3.3 context: %s", SDL_GetError());
}
}
}
SDL_GL_MakeCurrent(window, gl_context);
if(SDL_GL_SetSwapInterval(-1))
if (SDL_GL_SetSwapInterval(-1))
SDL_GL_SetSwapInterval(1);
if(!gladLoadGL()) {
if (!gladLoadGL()) {
die("Failed to load OpenGL functions.");
}
......@@ -113,14 +110,15 @@ void Platform::set_dpi() {
float dpi;
int index = SDL_GetWindowDisplayIndex(window);
if(index < 0) {
if (index < 0) {
return;
}
if(SDL_GetDisplayDPI(index, nullptr, &dpi, nullptr)) {
if (SDL_GetDisplayDPI(index, nullptr, &dpi, nullptr)) {
return;
}
float scale = window_draw().x / window_size().x;
if(prev_dpi == dpi && prev_scale == scale) return;
if (prev_dpi == dpi && prev_scale == scale)
return;
ImGuiStyle style;
ImGui::StyleColorsDark(&style);
......@@ -132,7 +130,7 @@ void Platform::set_dpi() {
#endif
ImGui::GetStyle() = style;
ImGuiIO& IO = ImGui::GetIO();
ImGuiIO &IO = ImGui::GetIO();
ImFontConfig config;
config.FontDataOwnedByAtlas = false;
IO.IniFilename = nullptr;
......@@ -141,7 +139,7 @@ void Platform::set_dpi() {
IO.Fonts->AddFontFromMemoryTTF(font_ttf, font_ttf_len, 14.0f * scale, &config);
IO.FontGlobalScale = 1.0f / scale;
#else
IO.Fonts->AddFontFromMemoryTTF(font_ttf, font_ttf_len, 14.0f / 96.0f * dpi , &config);
IO.Fonts->AddFontFromMemoryTTF(font_ttf, font_ttf_len, 14.0f / 96.0f * dpi, &config);
#endif
IO.Fonts->Build();
ImGui_ImplOpenGL3_DestroyDeviceObjects();
......@@ -150,9 +148,7 @@ void Platform::set_dpi() {
prev_scale = scale;
}
bool Platform::is_down(SDL_Scancode key) {
return keybuf[key];
}
bool Platform::is_down(SDL_Scancode key) { return keybuf[key]; }
void Platform::platform_shutdown() {
......@@ -183,7 +179,7 @@ void Platform::begin_frame() {
ImGui::NewFrame();
}
void Platform::strcpy(char* dst, const char* src, size_t limit) {
void Platform::strcpy(char *dst, const char *src, size_t limit) {
#ifdef _WIN32
strncpy_s(dst, limit, src, limit - 1);
#else
......@@ -192,18 +188,18 @@ void Platform::strcpy(char* dst, const char* src, size_t limit) {
#endif
}
void Platform::loop(App& app) {
void Platform::loop(App &app) {
bool running = true;
while(running) {
while (running) {
set_dpi();
SDL_Event e;
while(SDL_PollEvent(&e)) {
while (SDL_PollEvent(&e)) {
ImGui_ImplSDL2_ProcessEvent(&e);
switch(e.type) {
switch (e.type) {
case SDL_QUIT: {
running = false;
} break;
......@@ -218,9 +214,7 @@ void Platform::loop(App& app) {
}
}
Vec2 Platform::scale(Vec2 pt) {
return pt * window_draw() / window_size();
}
Vec2 Platform::scale(Vec2 pt) { return pt * window_draw() / window_size(); }
Vec2 Platform::window_size() {
int w, h;
......@@ -234,13 +228,9 @@ Vec2 Platform::window_draw() {
return Vec2((float)w, (float)h);
}
void Platform::grab_mouse() {
SDL_SetWindowGrab(window, SDL_TRUE);
}
void Platform::grab_mouse() { SDL_SetWindowGrab(window, SDL_TRUE); }
void Platform::ungrab_mouse() {
SDL_SetWindowGrab(window, SDL_FALSE);
}
void Platform::ungrab_mouse() { SDL_SetWindowGrab(window, SDL_FALSE); }
Vec2 Platform::get_mouse() {
int x, y;
......@@ -258,6 +248,4 @@ void Platform::release_mouse() {
SDL_SetRelativeMouseMode(SDL_FALSE);
}
void Platform::set_mouse(Vec2 pos) {
SDL_WarpMouseInWindow(window, (int)pos.x, (int)pos.y);
}
void Platform::set_mouse(Vec2 pos) { SDL_WarpMouseInWindow(window, (int)pos.x, (int)pos.y); }
......@@ -3,15 +3,15 @@
#include <SDL2/SDL.h>
#include "../lib/mathlib.h"
#include "../app.h"
#include "../lib/mathlib.h"
class Platform {
public:
Platform();
~Platform();
void loop(App& app);
void loop(App &app);
Vec2 window_draw();
Vec2 window_size();
......@@ -27,7 +27,7 @@ public:
static void remove_console();
static int console_width();
static void strcpy(char* dest, const char* src, size_t limit);
static void strcpy(char *dest, const char *src, size_t limit);
private:
float prev_dpi = 0.0f;
......@@ -39,7 +39,7 @@ private:
void begin_frame();
void complete_frame();
SDL_Window* window = nullptr;
SDL_Window *window = nullptr;
SDL_GLContext gl_context = nullptr;
const Uint8* keybuf = nullptr;
const Uint8 *keybuf = nullptr;
};
......@@ -18,9 +18,7 @@ struct BSDF_Sample {
Vec3 direction;
float pdf;
void transform(const Mat4& T) {
direction = T.rotate(direction);
}
void transform(const Mat4 &T) { direction = T.rotate(direction); }
};
struct BSDF_Lambertian {
......@@ -46,8 +44,8 @@ struct BSDF_Mirror {
struct BSDF_Refract {
BSDF_Refract(Spectrum transmittance, float ior) :
transmittance(transmittance), index_of_refraction(ior) {}
BSDF_Refract(Spectrum transmittance, float ior)
: transmittance(transmittance), index_of_refraction(ior) {}
BSDF_Sample sample(Vec3 out_dir) const;
Spectrum evaluate(Vec3 out_dir, Vec3 in_dir) const;
......@@ -58,8 +56,8 @@ struct BSDF_Refract {
struct BSDF_Glass {
BSDF_Glass(Spectrum transmittance, Spectrum reflectance, float ior) :
transmittance(transmittance), reflectance(reflectance), index_of_refraction(ior) {}
BSDF_Glass(Spectrum transmittance, Spectrum reflectance, float ior)
: transmittance(transmittance), reflectance(reflectance), index_of_refraction(ior) {}
BSDF_Sample sample(Vec3 out_dir) const;
Spectrum evaluate(Vec3 out_dir, Vec3 in_dir) const;
......@@ -82,59 +80,42 @@ struct BSDF_Diffuse {
class BSDF {
public:
BSDF(BSDF_Lambertian&& b) : underlying(std::move(b)) {}
BSDF(BSDF_Mirror&& b) : underlying(std::move(b)) {}
BSDF(BSDF_Glass&& b) : underlying(std::move(b)) {}
BSDF(BSDF_Diffuse&& b) : underlying(std::move(b)) {}
BSDF(BSDF_Refract&& b) : underlying(std::move(b)) {}
BSDF(BSDF_Lambertian &&b) : underlying(std::move(b)) {}
BSDF(BSDF_Mirror &&b) : underlying(std::move(b)) {}
BSDF(BSDF_Glass &&b) : underlying(std::move(b)) {}
BSDF(BSDF_Diffuse &&b) : underlying(std::move(b)) {}
BSDF(BSDF_Refract &&b) : underlying(std::move(b)) {}
BSDF(const BSDF& src) = delete;
BSDF& operator=(const BSDF& src) = delete;
BSDF& operator=(BSDF&& src) = default;
BSDF(BSDF&& src) = default;
BSDF(const BSDF &src) = delete;
BSDF &operator=(const BSDF &src) = delete;
BSDF &operator=(BSDF &&src) = default;
BSDF(BSDF &&src) = default;
BSDF_Sample sample(Vec3 out_dir) const {
return std::visit(overloaded {
[&out_dir](const auto& b) {
return b.sample(out_dir);
}
}, underlying);
return std::visit(overloaded{[&out_dir](const auto &b) { return b.sample(out_dir); }},
underlying);
}
Spectrum evaluate(Vec3 out_dir, Vec3 in_dir) const {
return std::visit(overloaded {
[&out_dir, &in_dir](const auto& b) {
return b.evaluate(out_dir, in_dir);
}
}, underlying);
return std::visit(
overloaded{[&out_dir, &in_dir](const auto &b) { return b.evaluate(out_dir, in_dir); }},
underlying);
}
bool is_discrete() const {
return std::visit(overloaded {
[](const BSDF_Lambertian&) {
return false;
},
[](const BSDF_Mirror&) {
return true;
},
[](const BSDF_Glass&) {
return true;
},
[](const BSDF_Diffuse&) {
return false;
},
[](const BSDF_Refract&) {
return true;
}
}, underlying);
return std::visit(overloaded{[](const BSDF_Lambertian &) { return false; },
[](const BSDF_Mirror &) { return true; },
[](const BSDF_Glass &) { return true; },
[](const BSDF_Diffuse &) { return false; },
[](const BSDF_Refract &) { return true; }},
underlying);
}
private:
std::variant<BSDF_Lambertian, BSDF_Mirror, BSDF_Glass,
BSDF_Diffuse, BSDF_Refract> underlying;
std::variant<BSDF_Lambertian, BSDF_Mirror, BSDF_Glass, BSDF_Diffuse, BSDF_Refract> underlying;
};
Vec3 reflect(Vec3 dir);
Vec3 refract(Vec3 out_dir, float index_of_refraction, bool& was_internal);
Vec3 refract(Vec3 out_dir, float index_of_refraction, bool &was_internal);
}
\ No newline at end of file
} // namespace PT
......@@ -8,17 +8,16 @@
namespace PT {
template<typename Primitive>
class BVH {
template <typename Primitive> class BVH {
public:
BVH() = default;
BVH(std::vector<Primitive>&& primitives, size_t max_leaf_size = 1);
void build(std::vector<Primitive>&& primitives, size_t max_leaf_size = 1);
BVH(std::vector<Primitive> &&primitives, size_t max_leaf_size = 1);
void build(std::vector<Primitive> &&primitives, size_t max_leaf_size = 1);
BBox bbox() const;
Trace hit(const Ray& ray) const;
Trace hit(const Ray &ray) const;
size_t visualize(GL::Lines& lines, GL::Lines& active, size_t level, const Mat4& trans) const;
size_t visualize(GL::Lines &lines, GL::Lines &active, size_t level, const Mat4 &trans) const;
std::vector<Primitive> destructure();
void clear();
......@@ -37,11 +36,10 @@ private:
std::vector<Primitive> primitives;
};
}
} // namespace PT
#ifdef SCOTTY3D_BUILD_REF
#include "../reference/bvh.cpp"
#else
#include "../student/bvh.cpp"
#endif
......@@ -36,7 +36,7 @@ struct Env_Sphere {
struct Env_Map {
Env_Map(HDR_Image&& img) : image(std::move(img)), sampler(image) {}
Env_Map(HDR_Image &&img) : image(std::move(img)), sampler(image) {}
Light_Sample sample() const;
Spectrum sample_direction(Vec3 dir) const;
......@@ -47,49 +47,34 @@ struct Env_Map {
class Env_Light {
public:
Env_Light(Env_Hemisphere&& l) : underlying(std::move(l)) {}
Env_Light(Env_Sphere&& l) : underlying(std::move(l)) {}
Env_Light(Env_Map&& l) : underlying(std::move(l)) {}
Env_Light(Env_Hemisphere &&l) : underlying(std::move(l)) {}
Env_Light(Env_Sphere &&l) : underlying(std::move(l)) {}
Env_Light(Env_Map &&l) : underlying(std::move(l)) {}
Env_Light(const Env_Light& src) = delete;
Env_Light& operator=(const Env_Light& src) = delete;
Env_Light& operator=(Env_Light&& src) = default;
Env_Light(Env_Light&& src) = default;
Env_Light(const Env_Light &src) = delete;
Env_Light &operator=(const Env_Light &src) = delete;
Env_Light &operator=(Env_Light &&src) = default;
Env_Light(Env_Light &&src) = default;
Light_Sample sample(Vec3) const {
return std::visit(overloaded {
[](const Env_Hemisphere& h) {
return h.sample();
},
[](const Env_Sphere& h) {
return h.sample();
},
[](const Env_Map& h) {
return h.sample();
}
}, underlying);
return std::visit(overloaded{[](const Env_Hemisphere &h) { return h.sample(); },
[](const Env_Sphere &h) { return h.sample(); },
[](const Env_Map &h) { return h.sample(); }},
underlying);
}
Spectrum sample_direction(Vec3 dir) const {
return std::visit(overloaded {
[&dir](const Env_Hemisphere& h) {
return h.sample_direction(dir);
},
[&dir](const Env_Sphere& h) {
return h.sample_direction(dir);
},
[&dir](const Env_Map& h) {
return h.sample_direction(dir);
}
}, underlying);
return std::visit(
overloaded{[&dir](const Env_Hemisphere &h) { return h.sample_direction(dir); },
[&dir](const Env_Sphere &h) { return h.sample_direction(dir); },
[&dir](const Env_Map &h) { return h.sample_direction(dir); }},
underlying);
}
bool is_discrete() const {
return false;
}
bool is_discrete() const { return false; }
private:
std::variant<Env_Hemisphere, Env_Sphere, Env_Map> underlying;
};
}
\ No newline at end of file
} // namespace PT
\ No newline at end of file
......@@ -23,12 +23,13 @@ Light_Sample Point_Light::sample(Vec3 from) const {
Light_Sample Spot_Light::sample(Vec3 from) const {
Light_Sample ret;
float angle = std::atan2(Vec2(from.x,from.z).norm(),from.y);
float angle = std::atan2(Vec2(from.x, from.z).norm(), from.y);
angle = std::abs(Degrees(angle));
ret.direction = -from.unit();
ret.distance = from.norm();
ret.pdf = 1.0f;
ret.radiance = (1.0f - smoothstep(angle_bounds.x / 2.0f, angle_bounds.y / 2.0f, angle)) * radiance;
ret.radiance =
(1.0f - smoothstep(angle_bounds.x / 2.0f, angle_bounds.y / 2.0f, angle)) * radiance;
return ret;
}
......@@ -50,4 +51,4 @@ Light_Sample Rect_Light::sample(Vec3 from) const {
return ret;
}
}
} // namespace PT
......@@ -5,8 +5,8 @@
#include "../lib/mathlib.h"
#include "../lib/spectrum.h"
#include "../util/hdr_image.h"
#include "../scene/object.h"
#include "../util/hdr_image.h"
#include "samplers.h"
......@@ -19,9 +19,7 @@ struct Light_Sample {
float distance;
float pdf;
void transform(const Mat4& T) {
direction = T.rotate(direction);
}
void transform(const Mat4 &T) { direction = T.rotate(direction); }
};
struct Directional_Light {
......@@ -68,58 +66,48 @@ struct Rect_Light {
class Light {
public:
Light(Directional_Light&& l, Scene_ID id, const Mat4& T = Mat4::I)
Light(Directional_Light &&l, Scene_ID id, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), underlying(std::move(l)) {
has_trans = trans != Mat4::I;
}
Light(Point_Light&& l, Scene_ID id, const Mat4& T = Mat4::I)
Light(Point_Light &&l, Scene_ID id, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), underlying(std::move(l)) {
has_trans = trans != Mat4::I;
}
Light(Spot_Light&& l, Scene_ID id, const Mat4& T = Mat4::I)
Light(Spot_Light &&l, Scene_ID id, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), underlying(std::move(l)) {
has_trans = trans != Mat4::I;
}
Light(Rect_Light&& l, Scene_ID id, const Mat4& T = Mat4::I)
Light(Rect_Light &&l, Scene_ID id, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), underlying(std::move(l)) {
has_trans = trans != Mat4::I;
}
Light(const Light& src) = delete;
Light& operator=(const Light& src) = delete;
Light& operator=(Light&& src) = default;
Light(Light&& src) = default;
Light(const Light &src) = delete;
Light &operator=(const Light &src) = delete;
Light &operator=(Light &&src) = default;
Light(Light &&src) = default;
Light_Sample sample(Vec3 from) const {
if(has_trans) from = itrans * from;
Light_Sample ret = std::visit(overloaded {
[&from](const auto& l) {
return l.sample(from);
}
}, underlying);
if(has_trans) ret.transform(trans);
if (has_trans)
from = itrans * from;
Light_Sample ret =
std::visit(overloaded{[&from](const auto &l) { return l.sample(from); }}, underlying);
if (has_trans)
ret.transform(trans);
return ret;
}
bool is_discrete() const {
return std::visit(overloaded {
[](const Directional_Light&) {
return true;
},
[](const Point_Light&) {
return true;
},
[](const Spot_Light&) {
return true;
},
[](const Rect_Light&) {
return false;
}
}, underlying);
return std::visit(overloaded{[](const Directional_Light &) { return true; },
[](const Point_Light &) { return true; },
[](const Spot_Light &) { return true; },
[](const Rect_Light &) { return false; }},
underlying);
}
Scene_ID id() const { return _id; }
void set_trans(const Mat4& T) {
void set_trans(const Mat4 &T) {
trans = T;
itrans = T.inverse();
has_trans = trans != Mat4::I;
......@@ -132,4 +120,4 @@ private:
std::variant<Directional_Light, Point_Light, Spot_Light, Rect_Light> underlying;
};
}
\ No newline at end of file
} // namespace PT
......@@ -6,36 +6,32 @@
namespace PT {
template<typename Primitive>
class List {
template <typename Primitive> class List {
public:
List() {}
List(std::vector<Primitive>&& primitives) : prims(primitives) {}
List(std::vector<Primitive> &&primitives) : prims(primitives) {}
BBox bbox() const {
BBox ret;
for(const auto& p : prims) {
for (const auto &p : prims) {
ret.enclose(p.bbox());
}
return ret;
}
Trace hit(const Ray& ray) const {
Trace hit(const Ray &ray) const {
Trace ret;
for(const auto& p : prims) {
for (const auto &p : prims) {
Trace test = p.hit(ray);
ret = Trace::min(ret, test);
}
return ret;
}
void append(Primitive&& prim) {
prims.push_back(std::move(prim));
}
void append(Primitive &&prim) { prims.push_back(std::move(prim)); }
private:
std::vector<Primitive> prims;
};
}
} // namespace PT
#pragma once
#include <variant>
#include "../lib/mathlib.h"
#include "../scene/object.h"
#include <variant>
#include "trace.h"
#include "bvh.h"
#include "list.h"
#include "shapes.h"
#include "trace.h"
#include "tri_mesh.h"
namespace PT {
class Object {
public:
Object(Shape&& shape, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m),
underlying(std::move(shape)) {
Object(Shape &&shape, Scene_ID id, unsigned int m = 0, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(shape)) {
has_trans = trans != Mat4::I;
}
Object(Tri_Mesh&& tri_mesh, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m),
underlying(std::move(tri_mesh)) {
Object(Tri_Mesh &&tri_mesh, Scene_ID id, unsigned int m = 0, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(tri_mesh)) {
has_trans = trans != Mat4::I;
}
Object(List<Object>&& list, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m),
underlying(std::move(list)) {
Object(List<Object> &&list, Scene_ID id, unsigned int m = 0, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(list)) {
has_trans = trans != Mat4::I;
}
Object(BVH<Object>&& bvh, Scene_ID id, unsigned int m = 0, const Mat4& T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m),
underlying(std::move(bvh)) {
Object(BVH<Object> &&bvh, Scene_ID id, unsigned int m = 0, const Mat4 &T = Mat4::I)
: trans(T), itrans(T.inverse()), _id(id), material(m), underlying(std::move(bvh)) {
has_trans = trans != Mat4::I;
}
Object(const Object& src) = delete;
Object& operator=(const Object& src) = delete;
Object& operator=(Object&& src) = default;
Object(Object&& src) = default;
Object(const Object &src) = delete;
Object &operator=(const Object &src) = delete;
Object &operator=(Object &&src) = default;
Object(Object &&src) = default;
BBox bbox() const {
BBox box = std::visit(overloaded {
[](const auto& o) {
return o.bbox();
}
}, underlying);
if(has_trans) box.transform(trans);
BBox box = std::visit(overloaded{[](const auto &o) { return o.bbox(); }}, underlying);
if (has_trans)
box.transform(trans);
return box;
}
Trace hit(Ray ray) const {
if(has_trans) ray.transform(itrans);
Trace ret = std::visit(overloaded {
[&ray](const auto& o) {
return o.hit(ray);
}
}, underlying);
if(ret.hit) {
if (has_trans)
ray.transform(itrans);
Trace ret =
std::visit(overloaded{[&ray](const auto &o) { return o.hit(ray); }}, underlying);
if (ret.hit) {
ret.material = material;
if(has_trans) ret.transform(trans, itrans.T());
if (has_trans)
ret.transform(trans, itrans.T());
}
return ret;
}
size_t visualize(GL::Lines& lines, GL::Lines& active, size_t level, const Mat4& vtrans) const {
size_t visualize(GL::Lines &lines, GL::Lines &active, size_t level, const Mat4 &vtrans) const {
Mat4 next = has_trans ? vtrans * trans : vtrans;
return std::visit(overloaded {
[&](const BVH<Object>& bvh) {
return bvh.visualize(lines, active, level, next);
},
[&](const Tri_Mesh& mesh) {
return mesh.visualize(lines, active, level, next);
},
[](const auto&) { return size_t(0); }
}, underlying);
return std::visit(
overloaded{
[&](const BVH<Object> &bvh) { return bvh.visualize(lines, active, level, next); },
[&](const Tri_Mesh &mesh) { return mesh.visualize(lines, active, level, next); },
[](const auto &) { return size_t(0); }},
underlying);
}
Scene_ID id() const { return _id; }
void set_trans(const Mat4& T) {
void set_trans(const Mat4 &T) {
trans = T;
itrans = T.inverse();
has_trans = trans != Mat4::I;
......@@ -93,4 +82,4 @@ private:
std::variant<Tri_Mesh, Shape, BVH<Object>, List<Object>> underlying;
};
}
\ No newline at end of file
} // namespace PT
\ No newline at end of file
#include "pathtracer.h"
#include "../gui/render.h"
#include "../geometry/util.h"
#include "../gui/render.h"
#include <SDL2/SDL.h>
#include <thread>
namespace PT {
Pathtracer::Pathtracer(Gui::Widget_Render& gui, Vec2 screen_dim) :
thread_pool(std::thread::hardware_concurrency()),
gui(gui), camera(screen_dim)
{
Pathtracer::Pathtracer(Gui::Widget_Render &gui, Vec2 screen_dim)
: thread_pool(std::thread::hardware_concurrency()), gui(gui), camera(screen_dim) {
accumulator_samples = 0;
total_epochs = 0;
completed_epochs = 0;
......@@ -20,53 +18,54 @@ Pathtracer::Pathtracer(Gui::Widget_Render& gui, Vec2 screen_dim) :
n_area_samples = 0;
}
Pathtracer::~Pathtracer() {
thread_pool.stop();
}
Pathtracer::~Pathtracer() { thread_pool.stop(); }
void Pathtracer::refit_scene(Scene& layout_scene) {
void Pathtracer::refit_scene(Scene &layout_scene) {
std::unordered_map<Scene_ID, Object> obj_map;
std::vector<Object> objs = scene.destructure();
for(auto& o : objs) obj_map.insert({o.id(), std::move(o)});
for (auto &o : objs)
obj_map.insert({o.id(), std::move(o)});
std::set<Scene_ID> light_ids;
for(auto& l : lights) light_ids.insert(l.id());
for (auto &l : lights)
light_ids.insert(l.id());
layout_scene.for_items([&](const Scene_Item& item) {
layout_scene.for_items([&](const Scene_Item &item) {
auto entry = obj_map.find(item.id());
if(entry != obj_map.end()) {
if (entry != obj_map.end()) {
entry->second.set_trans(item.pose().transform());
if(light_ids.count(entry->first)) {
if (light_ids.count(entry->first)) {
obj_map.erase(entry);
}
}
});
objs.clear();
for(auto& o : obj_map) objs.push_back(std::move(o.second));
for (auto &o : obj_map)
objs.push_back(std::move(o.second));
build_lights(layout_scene, objs);
scene.build(std::move(objs));
}
void Pathtracer::build_lights(Scene& layout_scene, std::vector<Object>& objs) {
void Pathtracer::build_lights(Scene &layout_scene, std::vector<Object> &objs) {
lights.clear();
env_light.reset();
layout_scene.for_items([&, this](const Scene_Item& item) {
if(item.is<Scene_Light>()) {
layout_scene.for_items([&, this](const Scene_Item &item) {
if (item.is<Scene_Light>()) {
const Scene_Light& light = item.get<Scene_Light>();
const Scene_Light &light = item.get<Scene_Light>();
Spectrum r = light.radiance();
switch(light.opt.type) {
switch (light.opt.type) {
case Light_Type::directional: {
lights.push_back(Light(Directional_Light(r), light.id(), light.pose.transform()));
} break;
case Light_Type::sphere: {
if(light.opt.has_emissive_map) {
if (light.opt.has_emissive_map) {
env_light = Env_Light(Env_Map(light.emissive_copy()));
} else {
env_light = Env_Light(Env_Sphere(r));
......@@ -79,14 +78,16 @@ void Pathtracer::build_lights(Scene& layout_scene, std::vector<Object>& objs) {
lights.push_back(Light(Point_Light(r), light.id(), light.pose.transform()));
} break;
case Light_Type::spot: {
lights.push_back(Light(Spot_Light(r, light.opt.angle_bounds), light.id(), light.pose.transform()));
lights.push_back(Light(Spot_Light(r, light.opt.angle_bounds), light.id(),
light.pose.transform()));
} break;
case Light_Type::rectangle: {
lights.push_back(Light(Rect_Light(r, light.opt.size), light.id(), light.pose.transform()));
lights.push_back(
Light(Rect_Light(r, light.opt.size), light.id(), light.pose.transform()));
unsigned int idx = 0;
auto entry = mat_cache.find(light.id());
if(entry != mat_cache.end()) {
if (entry != mat_cache.end()) {
idx = (unsigned int)entry->second;
materials[entry->second] = BSDF(BSDF_Diffuse(r));
} else {
......@@ -94,15 +95,18 @@ void Pathtracer::build_lights(Scene& layout_scene, std::vector<Object>& objs) {
mat_cache[light.id()] = materials.size();
materials.push_back(BSDF(BSDF_Diffuse(r)));
}
objs.push_back(Object(std::move(Util::quad_mesh(light.opt.size.x, light.opt.size.y)), light.id(), idx, light.pose.transform()));
objs.push_back(
Object(std::move(Util::quad_mesh(light.opt.size.x, light.opt.size.y)),
light.id(), idx, light.pose.transform()));
} break;
default: return;
default:
return;
}
}
});
}
void Pathtracer::build_scene(Scene& layout_scene) {
void Pathtracer::build_scene(Scene &layout_scene) {
// It would be nice to let the interface be usable here (as with
// the path-tracing part), but this would cause too much hassle with
......@@ -122,15 +126,14 @@ void Pathtracer::build_scene(Scene& layout_scene) {
materials.clear();
mat_cache.clear();
layout_scene.for_items([&, this](Scene_Item& item) {
layout_scene.for_items([&, this](Scene_Item &item) {
if (item.is<Scene_Object>()) {
if(item.is<Scene_Object>()) {
Scene_Object& obj = item.get<Scene_Object>();
Scene_Object &obj = item.get<Scene_Object>();
unsigned int idx = (unsigned int)materials.size();
const Material::Options& opt = obj.material.opt;
const Material::Options &opt = obj.material.opt;
switch(opt.type) {
switch (opt.type) {
case Material_Type::lambertian: {
materials.push_back(BSDF(BSDF_Lambertian(opt.albedo)));
} break;
......@@ -146,19 +149,21 @@ void Pathtracer::build_scene(Scene& layout_scene) {
case Material_Type::diffuse_light: {
materials.push_back(BSDF(BSDF_Diffuse(obj.material.emissive())));
} break;
default: return;
default:
return;
}
thread_pool.enqueue([&, idx]() {
if(obj.is_shape()) {
if (obj.is_shape()) {
Shape shape(obj.opt.shape);
std::lock_guard<std::mutex> lock(obj_mut);
obj_list.push_back(Object(std::move(shape), obj.id(), idx, obj.pose.transform()));
obj_list.push_back(
Object(std::move(shape), obj.id(), idx, obj.pose.transform()));
} else {
Tri_Mesh mesh(obj.posed_mesh());
std::lock_guard<std::mutex> lock(obj_mut);
obj_list.push_back(Object(std::move(mesh), obj.id(), idx, obj.pose.transform()));
obj_list.push_back(
Object(std::move(mesh), obj.id(), idx, obj.pose.transform()));
}
});
}
......@@ -179,19 +184,18 @@ void Pathtracer::set_sizes(size_t w, size_t h, size_t samples, size_t area_sampl
accumulator.resize(out_w, out_h);
}
void Pathtracer::log_ray(const Ray& ray, float t, Spectrum color) {
gui.log_ray(ray, t, color);
}
void Pathtracer::log_ray(const Ray &ray, float t, Spectrum color) { gui.log_ray(ray, t, color); }
void Pathtracer::accumulate(const HDR_Image& sample) {
void Pathtracer::accumulate(const HDR_Image &sample) {
std::lock_guard<std::mutex> lock(accumulator_mut);
accumulator_samples++;
for(size_t j = 0; j < out_h; j++) {
for(size_t i = 0; i < out_w; i++) {
Spectrum& s = accumulator.at(i, j);
s += (sample.at(i, j) - s) * (1.0f / accumulator_samples);
for (size_t j = 0; j < out_h; j++) {
for (size_t i = 0; i < out_w; i++) {
Spectrum &s = accumulator.at(i, j);
const Spectrum &n = sample.at(i, j);
s += (n - s) * (1.0f / accumulator_samples);
}
}
}
......@@ -199,12 +203,14 @@ void Pathtracer::accumulate(const HDR_Image& sample) {
void Pathtracer::do_trace(size_t samples) {
HDR_Image sample(out_w, out_h);
for(size_t j = 0; j < out_h; j++) {
for(size_t i = 0; i < out_w; i++) {
for (size_t j = 0; j < out_h; j++) {
for (size_t i = 0; i < out_w; i++) {
size_t sampled = 0;
for(size_t s = 0; s < samples; s++) {
for (size_t s = 0; s < samples; s++) {
Spectrum p = trace_pixel(i, j);
if(p.valid()) {
if (p.valid()) {
sample.at(i, j) += p;
sampled++;
}
......@@ -215,11 +221,9 @@ void Pathtracer::do_trace(size_t samples) {
accumulate(sample);
}
bool Pathtracer::in_progress() const {
return completed_epochs.load() < total_epochs.load();
}
bool Pathtracer::in_progress() const { return completed_epochs.load() < total_epochs.load(); }
std::pair<float,float> Pathtracer::completion_time() const {
std::pair<float, float> Pathtracer::completion_time() const {
double freq = (double)SDL_GetPerformanceFrequency();
return {(float)(build_time / freq), (float)(render_time / freq)};
}
......@@ -228,11 +232,11 @@ float Pathtracer::progress() const {
return (float)completed_epochs.load() / (float)total_epochs.load();
}
size_t Pathtracer::visualize_bvh(GL::Lines& lines, GL::Lines& active, size_t depth) {
size_t Pathtracer::visualize_bvh(GL::Lines &lines, GL::Lines &active, size_t depth) {
return scene.visualize(lines, active, depth, Mat4::I);
}
void Pathtracer::begin_render(Scene& layout_scene, const Camera& cam, bool refit) {
void Pathtracer::begin_render(Scene &layout_scene, const Camera &cam, bool refit) {
size_t n_threads = std::thread::hardware_concurrency();
size_t samples_per_epoch = std::max(size_t(1), n_samples / (n_threads * 10));
......@@ -243,19 +247,21 @@ void Pathtracer::begin_render(Scene& layout_scene, const Camera& cam, bool refit
total_epochs = n_samples / samples_per_epoch + !!(n_samples % samples_per_epoch);
build_time = SDL_GetPerformanceCounter();
if(refit) refit_scene(layout_scene);
else build_scene(layout_scene);
if (refit)
refit_scene(layout_scene);
else
build_scene(layout_scene);
render_time = SDL_GetPerformanceCounter();
build_time = render_time - build_time;
camera = cam;
for(size_t s = 0; s < n_samples; s += samples_per_epoch) {
for (size_t s = 0; s < n_samples; s += samples_per_epoch) {
size_t samples = (s + samples_per_epoch) > n_samples ? n_samples - s : samples_per_epoch;
thread_pool.enqueue([samples, this]() {
do_trace(samples);
completed_epochs++;
if(completed_epochs.load() == total_epochs.load()) {
if (completed_epochs.load() == total_epochs.load()) {
Uint64 done = SDL_GetPerformanceCounter();
render_time = done - render_time;
}
......@@ -272,13 +278,11 @@ void Pathtracer::cancel() {
total_epochs = 0;
}
const HDR_Image& Pathtracer::get_output() {
return accumulator;
}
const HDR_Image &Pathtracer::get_output() { return accumulator; }
const GL::Tex2D& Pathtracer::get_output_texture(float exposure) {
const GL::Tex2D &Pathtracer::get_output_texture(float exposure) {
std::lock_guard<std::mutex> lock(accumulator_mut);
return accumulator.get_texture(exposure);
}
}
} // namespace PT
#pragma once
#include <mutex>
#include <atomic>
#include <mutex>
#include <unordered_map>
#include "../lib/mathlib.h"
#include "../scene/scene.h"
#include "../util/hdr_image.h"
#include "../util/thread_pool.h"
#include "../scene/scene.h"
#include "bsdf.h"
#include "env_light.h"
#include "light.h"
#include "object.h"
#include "bsdf.h"
namespace Gui { class Widget_Render; }
namespace Gui {
class Widget_Render;
}
namespace PT {
class Pathtracer {
public:
Pathtracer(Gui::Widget_Render& gui, Vec2 screen_dim);
Pathtracer(Gui::Widget_Render &gui, Vec2 screen_dim);
~Pathtracer();
void set_sizes(size_t w, size_t h, size_t pixel_samples, size_t area_samples, size_t depth);
const HDR_Image& get_output();
const GL::Tex2D& get_output_texture(float exposure);
size_t visualize_bvh(GL::Lines& lines, GL::Lines& active, size_t level);
const HDR_Image &get_output();
const GL::Tex2D &get_output_texture(float exposure);
size_t visualize_bvh(GL::Lines &lines, GL::Lines &active, size_t level);
void begin_render(Scene& scene, const Camera& camera, bool refit = false);
void begin_render(Scene &scene, const Camera &camera, bool refit = false);
void cancel();
bool in_progress() const;
float progress() const;
std::pair<float,float> completion_time() const;
std::pair<float, float> completion_time() const;
private:
// Internal
void build_scene(Scene& scene);
void refit_scene(Scene& scene);
void build_lights(Scene& scene, std::vector<Object>& objs);
void build_scene(Scene &scene);
void refit_scene(Scene &scene);
void build_lights(Scene &scene, std::vector<Object> &objs);
void do_trace(size_t samples);
void accumulate(const HDR_Image& sample);
void accumulate(const HDR_Image &sample);
bool tonemap();
Gui::Widget_Render& gui;
Gui::Widget_Render &gui;
unsigned long long render_time, build_time;
Thread_Pool thread_pool;
......@@ -55,8 +57,8 @@ private:
/// Relevant to student
Spectrum trace_pixel(size_t x, size_t y);
Spectrum trace_ray(const Ray& ray);
void log_ray(const Ray& ray, float t, Spectrum color = Spectrum{1.0f});
Spectrum trace_ray(const Ray &ray);
void log_ray(const Ray &ray, float t, Spectrum color = Spectrum{1.0f});
BVH<Object> scene;
std::vector<Light> lights;
......@@ -68,4 +70,4 @@ private:
size_t out_w, out_h, n_samples, n_area_samples, max_depth;
};
}
} // namespace PT
......@@ -6,64 +6,66 @@
namespace Samplers {
// These samplers are discrete. Note they output a probability _mass_ function
struct Point {
// These samplers are discrete. Note they output a probability _mass_ function
struct Point {
Point(Vec3 point) : point(point) {}
Vec3 sample(float& pmf) const;
Vec3 sample(float &pmf) const;
Vec3 point;
};
};
struct Two_Points {
struct Two_Points {
Two_Points(Vec3 p1, Vec3 p2, float p_p1) : p1(p1), p2(p2), prob(p_p1) {}
Vec3 sample(float& pmf) const;
Vec3 sample(float &pmf) const;
Vec3 p1, p2;
float prob;
};
};
using Direction = Point;
using Two_Directions = Two_Points;
using Direction = Point;
using Two_Directions = Two_Points;
// These are continuous. Note they output a probabilty _density_ function
namespace Rect {
// These are continuous. Note they output a probabilty _density_ function
namespace Rect {
struct Uniform {
struct Uniform {
Uniform(Vec2 size = Vec2(1.0f)) : size(size) {}
Vec2 sample(float& pdf) const;
Vec2 sample(float &pdf) const;
Vec2 size;
};
}
};
namespace Hemisphere {
} // namespace Rect
struct Uniform {
namespace Hemisphere {
struct Uniform {
Uniform() = default;
Vec3 sample(float& pdf) const;
};
Vec3 sample(float &pdf) const;
};
struct Cosine {
struct Cosine {
Cosine() = default;
Vec3 sample(float& pdf) const;
};
}
Vec3 sample(float &pdf) const;
};
} // namespace Hemisphere
namespace Sphere {
namespace Sphere {
struct Uniform {
struct Uniform {
Uniform() = default;
Vec3 sample(float& pdf) const;
Vec3 sample(float &pdf) const;
Hemisphere::Uniform hemi;
};
};
struct Image {
Image(const HDR_Image& image);
Vec3 sample(float& pdf) const;
struct Image {
Image(const HDR_Image &image);
Vec3 sample(float &pdf) const;
size_t w = 0, h = 0;
std::vector<float> pdf, cdf;
float total = 0.0f;
};
};
}
};
} // namespace Sphere
} // namespace Samplers
#pragma once
#include <variant>
#include "../lib/mathlib.h"
#include "trace.h"
#include <variant>
namespace PT {
enum class Shape_Type : int {
none,
sphere,
count
};
extern const char* Shape_Type_Names[(int)Shape_Type::count];
enum class Shape_Type : int { none, sphere, count };
extern const char *Shape_Type_Names[(int)Shape_Type::count];
class Sphere {
public:
......@@ -20,57 +16,39 @@ public:
Sphere(float radius) : radius(radius) {}
BBox bbox() const;
Trace hit(const Ray& ray) const;
Trace hit(const Ray &ray) const;
float radius = 1.0f;
bool operator!=(const Sphere& s) const {
return radius != s.radius;
}
bool operator!=(const Sphere &s) const { return radius != s.radius; }
};
class Shape {
public:
Shape() = default;
Shape(Sphere&& sphere) : underlying(std::move(sphere)) {}
Shape(Sphere &&sphere) : underlying(std::move(sphere)) {}
Shape(const Shape& src) = default;
Shape& operator=(const Shape& src) = default;
Shape& operator=(Shape&& src) = default;
Shape(Shape&& src) = default;
Shape(const Shape &src) = default;
Shape &operator=(const Shape &src) = default;
Shape &operator=(Shape &&src) = default;
Shape(Shape &&src) = default;
BBox bbox() const {
return std::visit(overloaded {
[](const auto& o) {
return o.bbox();
}
}, underlying);
return std::visit(overloaded{[](const auto &o) { return o.bbox(); }}, underlying);
}
Trace hit(Ray ray) const {
return std::visit(overloaded {
[&ray](const auto& o) {
return o.hit(ray);
}
}, underlying);
return std::visit(overloaded{[&ray](const auto &o) { return o.hit(ray); }}, underlying);
}
template<typename T>
T& get() {
return std::get<T>(underlying);
}
template <typename T> T &get() { return std::get<T>(underlying); }
template<typename T>
const T& get() const {
return std::get<T>(underlying);
}
template <typename T> const T &get() const { return std::get<T>(underlying); }
bool operator!=(const Shape& c) const {
return underlying != c.underlying;
}
bool operator!=(const Shape &c) const { return underlying != c.underlying; }
private:
std::variant<Sphere> underlying;
};
}
} // namespace PT
......@@ -12,20 +12,23 @@ struct Trace {
Vec3 position, normal;
int material = 0;
static Trace min(const Trace& l, const Trace& r) {
if(l.hit && r.hit) {
if(l.time < r.time) return l;
static Trace min(const Trace &l, const Trace &r) {
if (l.hit && r.hit) {
if (l.time < r.time)
return l;
return r;
}
if(l.hit) return l;
if(r.hit) return r;
if (l.hit)
return l;
if (r.hit)
return r;
return {};
}
void transform(const Mat4& transform, const Mat4& norm) {
void transform(const Mat4 &transform, const Mat4 &norm) {
position = transform * position;
normal = norm.rotate(normal);
}
};
}
} // namespace PT
......@@ -4,8 +4,8 @@
#include "../lib/mathlib.h"
#include "../platform/gl.h"
#include "trace.h"
#include "bvh.h"
#include "trace.h"
namespace PT {
......@@ -17,33 +17,33 @@ struct Tri_Mesh_Vert {
class Triangle {
public:
BBox bbox() const;
Trace hit(const Ray& ray) const;
Trace hit(const Ray &ray) const;
size_t visualize(GL::Lines&, GL::Lines&, size_t, const Mat4&) const { return size_t(0); }
size_t visualize(GL::Lines &, GL::Lines &, size_t, const Mat4 &) const { return size_t(0); }
private:
Triangle(Tri_Mesh_Vert* verts, unsigned int v0, unsigned int v1, unsigned int v2);
Triangle(Tri_Mesh_Vert *verts, unsigned int v0, unsigned int v1, unsigned int v2);
unsigned int v0, v1, v2;
Tri_Mesh_Vert* vertex_list;
Tri_Mesh_Vert *vertex_list;
friend class Tri_Mesh;
};
class Tri_Mesh {
public:
Tri_Mesh() = default;
Tri_Mesh(const GL::Mesh& mesh);
Tri_Mesh(const GL::Mesh &mesh);
BBox bbox() const;
Trace hit(const Ray& ray) const;
Trace hit(const Ray &ray) const;
size_t visualize(GL::Lines& lines, GL::Lines& active, size_t level, const Mat4& trans) const;
size_t visualize(GL::Lines &lines, GL::Lines &active, size_t level, const Mat4 &trans) const;
void build(const GL::Mesh& mesh);
void build(const GL::Mesh &mesh);
private:
std::vector<Tri_Mesh_Vert> verts;
BVH<Triangle> triangles;
};
}
} // namespace PT
......@@ -6,20 +6,13 @@
#include <sstream>
const char* Light_Type_Names[(int)Light_Type::count] = {
"Directional",
"Sphere",
"Hemisphere",
"Point",
"Spot",
"Rectangle"
};
Scene_Light::Scene_Light(Light_Type type, Scene_ID id, Pose p, std::string n) :
pose(p), _id(id), _lines(1.0f)
{
const char *Light_Type_Names[(int)Light_Type::count] = {"Directional", "Sphere", "Hemisphere",
"Point", "Spot", "Rectangle"};
Scene_Light::Scene_Light(Light_Type type, Scene_ID id, Pose p, std::string n)
: pose(p), _id(id), _lines(1.0f) {
opt.type = type;
if(n.size()) {
if (n.size()) {
snprintf(opt.name, max_name_len, "%s", n.c_str());
} else {
snprintf(opt.name, max_name_len, "%s Light %d", Light_Type_Names[(int)type], id);
......@@ -31,35 +24,27 @@ bool Scene_Light::is_env() const {
}
void Scene_Light::set_time(float time) {
if(lanim.splines.any()) {
if (lanim.splines.any()) {
lanim.at(time, opt);
}
dirty();
}
void Scene_Light::emissive_clear() {
opt.has_emissive_map = false;
}
void Scene_Light::emissive_clear() { opt.has_emissive_map = false; }
HDR_Image Scene_Light::emissive_copy() const {
return _emissive.copy();
}
HDR_Image Scene_Light::emissive_copy() const { return _emissive.copy(); }
std::string Scene_Light::emissive_load(std::string file) {
std::string err = _emissive.load_from(file);
if(err.empty()) {
if (err.empty()) {
opt.has_emissive_map = true;
}
return err;
}
std::string Scene_Light::emissive_loaded() const {
return _emissive.loaded_from();
}
std::string Scene_Light::emissive_loaded() const { return _emissive.loaded_from(); }
const GL::Tex2D& Scene_Light::emissive_texture() const {
return _emissive.get_texture();
}
const GL::Tex2D &Scene_Light::emissive_texture() const { return _emissive.get_texture(); }
BBox Scene_Light::bbox() const {
BBox box = _mesh.bbox();
......@@ -67,13 +52,11 @@ BBox Scene_Light::bbox() const {
return box;
}
Scene_Light::Scene_Light(Scene_Light&& src) : _lines(1.0f) {
*this = std::move(src);
}
Scene_Light::Scene_Light(Scene_Light &&src) : _lines(1.0f) { *this = std::move(src); }
void Scene_Light::regen_mesh() {
switch(opt.type) {
switch (opt.type) {
case Light_Type::spot: {
Vec3 col(opt.spectrum.r, opt.spectrum.g, opt.spectrum.b);
_lines = Util::spotlight_mesh(col, opt.angle_bounds.x, opt.angle_bounds.y);
......@@ -88,42 +71,42 @@ void Scene_Light::regen_mesh() {
case Light_Type::rectangle: {
_mesh = Util::quad_mesh(opt.size.x, opt.size.y);
} break;
default: break;
default:
break;
}
_dirty = false;
}
void Scene_Light::dirty() {
_dirty = true;
}
void Scene_Light::dirty() { _dirty = true; }
Spectrum Scene_Light::radiance() const {
return opt.spectrum * opt.intensity;
}
Spectrum Scene_Light::radiance() const { return opt.spectrum * opt.intensity; }
void Scene_Light::render(const Mat4& view, bool depth_only, bool posed) {
void Scene_Light::render(const Mat4 &view, bool depth_only, bool posed) {
if(_dirty) regen_mesh();
if (_dirty)
regen_mesh();
Renderer& renderer = Renderer::get();
Renderer &renderer = Renderer::get();
Spectrum s = opt.spectrum;
s.make_srgb();
Vec3 col(s.r,s.g,s.b);
Vec3 col(s.r, s.g, s.b);
Mat4 rot = view;
rot.cols[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
Mat4 T = posed ? pose.transform() : Mat4::I;
if(opt.type == Light_Type::spot && !depth_only)
if (opt.type == Light_Type::spot && !depth_only)
renderer.lines(_lines, view, T);
if(opt.type == Light_Type::hemisphere) {
if (opt.type == Light_Type::hemisphere) {
renderer.skydome(rot, col, 0.0f);
} else if(opt.type == Light_Type::sphere) {
if(opt.has_emissive_map) renderer.skydome(rot, col, -1.1f, _emissive.get_texture());
else renderer.skydome(rot, col, -1.1f);
} else if (opt.type == Light_Type::sphere) {
if (opt.has_emissive_map)
renderer.skydome(rot, col, -1.1f, _emissive.get_texture());
else
renderer.skydome(rot, col, -1.1f);
} else {
Renderer::MeshOpt opts;
opts.modelview = view * T;
......@@ -135,13 +118,14 @@ void Scene_Light::render(const Mat4& view, bool depth_only, bool posed) {
}
}
bool operator!=(const Scene_Light::Options& l, const Scene_Light::Options& r) {
return l.type != r.type || std::string(l.name) != std::string(r.name) || l.spectrum != r.spectrum ||
l.intensity != r.intensity || l.angle_bounds != r.angle_bounds || l.size != r.size ||
bool operator!=(const Scene_Light::Options &l, const Scene_Light::Options &r) {
return l.type != r.type || std::string(l.name) != std::string(r.name) ||
l.spectrum != r.spectrum || l.intensity != r.intensity ||
l.angle_bounds != r.angle_bounds || l.size != r.size ||
l.has_emissive_map != r.has_emissive_map;
}
void Scene_Light::Anim_Light::at(float t, Options& o) const {
void Scene_Light::Anim_Light::at(float t, Options &o) const {
auto [s, i, a, sz] = splines.at(t);
o.spectrum = s;
o.intensity = i;
......
......@@ -8,34 +8,26 @@
#include "../rays/samplers.h"
#include "../util/hdr_image.h"
#include "pose.h"
#include "object.h"
#include "pose.h"
enum class Light_Type : int {
directional,
sphere,
hemisphere,
point,
spot,
rectangle,
count
};
extern const char* Light_Type_Names[(int)Light_Type::count];
enum class Light_Type : int { directional, sphere, hemisphere, point, spot, rectangle, count };
extern const char *Light_Type_Names[(int)Light_Type::count];
class Scene_Light {
public:
Scene_Light(Light_Type type, Scene_ID id, Pose p, std::string n = {});
Scene_Light(const Scene_Light& src) = delete;
Scene_Light(Scene_Light&& src);
Scene_Light(const Scene_Light &src) = delete;
Scene_Light(Scene_Light &&src);
~Scene_Light() = default;
void operator=(const Scene_Light& src) = delete;
Scene_Light& operator=(Scene_Light&& src) = default;
void operator=(const Scene_Light &src) = delete;
Scene_Light &operator=(Scene_Light &&src) = default;
Scene_ID id() const {return _id;}
Scene_ID id() const { return _id; }
BBox bbox() const;
void render(const Mat4& view, bool depth_only = false, bool posed = true);
void render(const Mat4 &view, bool depth_only = false, bool posed = true);
void dirty();
Spectrum radiance() const;
......@@ -45,7 +37,7 @@ public:
std::string emissive_loaded() const;
HDR_Image emissive_copy() const;
const GL::Tex2D& emissive_texture() const;
const GL::Tex2D &emissive_texture() const;
void emissive_clear();
bool is_env() const;
......@@ -61,7 +53,7 @@ public:
};
struct Anim_Light {
void at(float t, Options& o) const;
void at(float t, Options &o) const;
void set(float t, Options o);
Splines<Spectrum, float, Vec2, Vec2> splines;
};
......@@ -81,4 +73,4 @@ private:
HDR_Image _emissive;
};
bool operator!=(const Scene_Light::Options& l, const Scene_Light::Options& r);
bool operator!=(const Scene_Light::Options &l, const Scene_Light::Options &r);
#include "material.h"
const char* Material_Type_Names[(int)Material_Type::count] = {
"Lambertian",
"Mirror",
"Refract",
"Glass",
"Diffuse Light"
};
const char *Material_Type_Names[(int)Material_Type::count] = {"Lambertian", "Mirror", "Refract",
"Glass", "Diffuse Light"};
bool operator!=(const Material::Options& l, const Material::Options& r) {
bool operator!=(const Material::Options &l, const Material::Options &r) {
return l.albedo != r.albedo || l.emissive != r.emissive || l.ior != r.ior ||
l.reflectance != r.reflectance || l.transmittance != r.transmittance ||
l.type != r.type || l.intensity != r.intensity;
......@@ -17,7 +12,7 @@ bool operator!=(const Material::Options& l, const Material::Options& r) {
Vec3 Material::layout_color() const {
Vec3 color;
switch(opt.type) {
switch (opt.type) {
case Material_Type::lambertian: {
color = opt.albedo.to_vec();
} break;
......@@ -31,14 +26,13 @@ Vec3 Material::layout_color() const {
case Material_Type::diffuse_light: {
color = opt.emissive.to_vec();
} break;
default: break;
default:
break;
}
return color;
}
Spectrum Material::emissive() const {
return opt.emissive * opt.intensity;
}
Spectrum Material::emissive() const { return opt.emissive * opt.intensity; }
Material Material::copy() const {
Material ret;
......
......@@ -3,26 +3,19 @@
#include "../lib/spectrum.h"
enum class Material_Type : int {
lambertian,
mirror,
refract,
glass,
diffuse_light,
count
};
extern const char* Material_Type_Names[(int)Material_Type::count];
enum class Material_Type : int { lambertian, mirror, refract, glass, diffuse_light, count };
extern const char *Material_Type_Names[(int)Material_Type::count];
class Material {
public:
Material() = default;
Material(Material_Type type) { opt.type = type; }
Material(const Material& src) = delete;
Material(Material&& src) = default;
Material(const Material &src) = delete;
Material(Material &&src) = default;
~Material() = default;
void operator=(const Material& src) = delete;
Material& operator=(Material&& src) = default;
void operator=(const Material &src) = delete;
Material &operator=(Material &&src) = default;
// TODO: decide how to handle texture resources. should probably use a texture repository
// and also integrate that into the envmaps
......@@ -44,5 +37,4 @@ public:
Options opt;
};
bool operator!=(const Material::Options& l, const Material::Options& r);
bool operator!=(const Material::Options &l, const Material::Options &r);
......@@ -3,45 +3,38 @@
#include <sstream>
#include "../gui/render.h"
#include "../geometry/util.h"
#include "../gui/render.h"
#include "renderer.h"
Scene_Object::Scene_Object(Scene_ID id, Pose p, GL::Mesh&& m, std::string n) :
pose(p),
_id(id),
armature(id),
_mesh(std::move(m)) {
Scene_Object::Scene_Object(Scene_ID id, Pose p, GL::Mesh &&m, std::string n)
: pose(p), _id(id), armature(id), _mesh(std::move(m)) {
set_skel_dirty();
editable = false;
if(n.size()) {
if (n.size()) {
snprintf(opt.name, max_name_len, "%s", n.c_str());
} else {
snprintf(opt.name, max_name_len, "Object %d", id);
}
}
Scene_Object::Scene_Object(Scene_ID id, Pose p, Halfedge_Mesh&& m, std::string n) :
pose(p),
_id(id),
armature(id),
halfedge(std::move(m)),
_mesh() {
Scene_Object::Scene_Object(Scene_ID id, Pose p, Halfedge_Mesh &&m, std::string n)
: pose(p), _id(id), armature(id), halfedge(std::move(m)), _mesh() {
set_mesh_dirty();
if(n.size()) {
if (n.size()) {
snprintf(opt.name, max_name_len, "%s", n.c_str());
} else {
snprintf(opt.name, max_name_len, "Object %d", id);
}
}
const GL::Mesh& Scene_Object::posed_mesh() {
const GL::Mesh &Scene_Object::posed_mesh() {
sync_anim_mesh();
if(armature.has_bones()) {
if (armature.has_bones()) {
return _anim_mesh;
}
return _mesh;
......@@ -49,83 +42,78 @@ const GL::Mesh& Scene_Object::posed_mesh() {
void Scene_Object::try_make_editable(PT::Shape_Type prev) {
switch(prev) {
switch (prev) {
case PT::Shape_Type::sphere: {
_mesh = Util::sphere_mesh(opt.shape.get<PT::Sphere>().radius, 2);
} break;
case PT::Shape_Type::none:
case PT::Shape_Type::count: break;
case PT::Shape_Type::count:
break;
}
std::string err = halfedge.from_mesh(_mesh);
if(err.empty())
if (err.empty())
editable = true;
mesh_dirty = true;
skel_dirty = true;
}
bool Scene_Object::is_shape() const {
return opt.shape_type != PT::Shape_Type::none;
}
bool Scene_Object::is_shape() const { return opt.shape_type != PT::Shape_Type::none; }
void Scene_Object::set_time(float time) {
if(anim.splines.any()) pose = anim.at(time);
if(armature.set_time(time)) set_pose_dirty();
if (anim.splines.any())
pose = anim.at(time);
if (armature.set_time(time))
set_pose_dirty();
}
bool Scene_Object::is_editable() const {
return editable && opt.shape_type == PT::Shape_Type::none;
}
void Scene_Object::copy_mesh(Halfedge_Mesh& out) {
halfedge.copy_to(out);
}
void Scene_Object::copy_mesh(Halfedge_Mesh &out) { halfedge.copy_to(out); }
void Scene_Object::set_mesh(Halfedge_Mesh& in) {
void Scene_Object::set_mesh(Halfedge_Mesh &in) {
in.copy_to(halfedge);
set_mesh_dirty();
}
Halfedge_Mesh::ElementRef Scene_Object::set_mesh(Halfedge_Mesh& in, unsigned int eid) {
Halfedge_Mesh::ElementRef Scene_Object::set_mesh(Halfedge_Mesh &in, unsigned int eid) {
auto e = in.copy_to(halfedge, eid);
set_mesh_dirty();
return e;
}
void Scene_Object::take_mesh(Halfedge_Mesh&& in) {
void Scene_Object::take_mesh(Halfedge_Mesh &&in) {
halfedge = std::move(in);
set_mesh_dirty();
}
Halfedge_Mesh& Scene_Object::get_mesh() {
return halfedge;
}
Halfedge_Mesh &Scene_Object::get_mesh() { return halfedge; }
const Halfedge_Mesh& Scene_Object::get_mesh() const {
return halfedge;
}
const Halfedge_Mesh &Scene_Object::get_mesh() const { return halfedge; }
void Scene_Object::sync_anim_mesh() {
sync_mesh();
if(skel_dirty && armature.has_bones()) {
if (skel_dirty && armature.has_bones()) {
vertex_joints.clear();
armature.find_joints(_mesh, vertex_joints);
}
if(pose_dirty && armature.has_bones()) {
if (pose_dirty && armature.has_bones()) {
armature.skin(_mesh, _anim_mesh, vertex_joints);
if(!opt.smooth_normals) {
auto& verts = _anim_mesh.edit_verts();
auto& idxs = _anim_mesh.edit_indices();
for(size_t i = 0; i < idxs.size(); i += 3) {
if (!opt.smooth_normals) {
auto &verts = _anim_mesh.edit_verts();
auto &idxs = _anim_mesh.edit_indices();
for (size_t i = 0; i < idxs.size(); i += 3) {
Vec3 v0 = verts[idxs[i]].pos;
Vec3 v1 = verts[idxs[i+1]].pos;
Vec3 v2 = verts[idxs[i+2]].pos;
Vec3 v1 = verts[idxs[i + 1]].pos;
Vec3 v2 = verts[idxs[i + 2]].pos;
Vec3 n = cross(v1 - v0, v2 - v0).unit();
verts[idxs[i]].norm = n;
verts[idxs[i+1]].norm = n;
verts[idxs[i+2]].norm = n;
verts[idxs[i + 1]].norm = n;
verts[idxs[i + 2]].norm = n;
}
}
}
......@@ -134,17 +122,15 @@ void Scene_Object::sync_anim_mesh() {
void Scene_Object::sync_mesh() {
if(editable && mesh_dirty) {
if (editable && mesh_dirty) {
halfedge.to_mesh(_mesh, !opt.smooth_normals);
mesh_dirty = false;
} else if(mesh_dirty && is_shape()) {
} else if (mesh_dirty && is_shape()) {
mesh_dirty = false;
}
}
void Scene_Object::set_pose_dirty() {
pose_dirty = true;
}
void Scene_Object::set_pose_dirty() { pose_dirty = true; }
void Scene_Object::set_skel_dirty() {
skel_dirty = true;
......@@ -163,8 +149,8 @@ BBox Scene_Object::bbox() {
sync_anim_mesh();
BBox box;
if(opt.shape_type == PT::Shape_Type::none) {
if(armature.has_bones())
if (opt.shape_type == PT::Shape_Type::none) {
if (armature.has_bones())
box = _anim_mesh.bbox();
else
box = _mesh.bbox();
......@@ -175,10 +161,12 @@ BBox Scene_Object::bbox() {
return box;
}
void Scene_Object::render(const Mat4& view, bool solid, bool depth_only, bool posed, bool do_anim) {
void Scene_Object::render(const Mat4 &view, bool solid, bool depth_only, bool posed, bool do_anim) {
if(do_anim) sync_anim_mesh();
else sync_mesh();
if (do_anim)
sync_anim_mesh();
else
sync_mesh();
Renderer::MeshOpt opts;
opts.id = _id;
......@@ -188,7 +176,7 @@ void Scene_Object::render(const Mat4& view, bool solid, bool depth_only, bool po
opts.sel_color = material.layout_color();
opts.modelview = posed ? view * pose.transform() : view;
switch(opt.shape_type) {
switch (opt.shape_type) {
case PT::Shape_Type::sphere: {
opts.wireframe = false;
opts.modelview = opts.modelview * Mat4::scale(Vec3{opt.shape.get<PT::Sphere>().radius});
......@@ -197,18 +185,19 @@ void Scene_Object::render(const Mat4& view, bool solid, bool depth_only, bool po
case PT::Shape_Type::none: {
opts.wireframe = opt.wireframe;
if(do_anim && armature.has_bones()) {
if (do_anim && armature.has_bones()) {
Renderer::get().mesh(_anim_mesh, opts);
} else {
Renderer::get().mesh(_mesh, opts);
}
} break;
case PT::Shape_Type::count: break;
case PT::Shape_Type::count:
break;
}
}
bool operator!=(const Scene_Object::Options& l, const Scene_Object::Options& r) {
bool operator!=(const Scene_Object::Options &l, const Scene_Object::Options &r) {
return std::string(l.name) != std::string(r.name) || l.shape_type != r.shape_type ||
l.smooth_normals != r.smooth_normals || l.wireframe != r.wireframe || l.shape != r.shape;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment