Skip to content

Commit

Permalink
Saving scene WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
serhii-rieznik committed Feb 5, 2023
1 parent da91741 commit a9cad67
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 23 deletions.
120 changes: 101 additions & 19 deletions sources/etx/render/host/scene_loader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <tiny_obj_loader.hxx>
#include <jansson.h>

#include <filesystem>

namespace etx {

Pointer<Spectrums> spectrums() {
Expand Down Expand Up @@ -75,6 +77,10 @@ struct SceneRepresentationImpl {
std::vector<Material> materials;
std::vector<Emitter> emitters;

std::string json_file_name;
std::string obj_file_name;
std::string mtl_file_name;

ImagePool images;
MediumPool mediums;

Expand Down Expand Up @@ -341,6 +347,10 @@ float get_camera_fov(const Camera& camera) {
return 2.0f * atanf(camera.tan_half_fov) * 180.0f / kPi;
}

float get_camera_focal_length(const Camera& camera) {
return 0.5f * kFilmSize / camera.tan_half_fov;
}

float fov_to_focal_length(float fov) {
return 0.5f * kFilmSize / tanf(0.5f * fov);
}
Expand Down Expand Up @@ -434,13 +444,84 @@ float3 json_to_f3(json_t* a) {
return result;
}

json_t* json_float3_to_array(const float3& v) {
json_t* j = json_array();
json_array_append(j, json_real(v.x));
json_array_append(j, json_real(v.y));
json_array_append(j, json_real(v.z));
return j;
}

json_t* json_uint2_to_array(const uint2& v) {
json_t* j = json_array();
json_array_append(j, json_integer(v.x));
json_array_append(j, json_integer(v.y));
return j;
}

void SceneRepresentation::write_materials(const char* filename) {
FILE* fout = fopen(filename, "w");
if (fout == nullptr) {
log::error("Failed to write materials file: %s", filename);
return;
}

for (const auto& mmap : _private->material_mapping) {
const auto& material = _private->scene.materials[mmap.second];

// TODO : support anisotripic roughness
fprintf(fout, "newmtl %s\n", mmap.first.c_str());
fprintf(fout, "material class %s\n", material_class_to_string(material.cls));
fprintf(fout, "Pr %.3f\n", sqrtf(0.5f * (sqr(material.roughness.x) + sqr(material.roughness.y))));
fprintf(fout, "\n");
}

fclose(fout);
}

void SceneRepresentation::save_to_file(const char* filename) {
if (_private->obj_file_name.empty())
return;

FILE* fout = fopen(filename, "w");
if (fout == nullptr)
return;

auto materials_file = _private->obj_file_name + ".materials";
auto relative_obj_file = std::filesystem::relative(_private->obj_file_name, std::filesystem::path(filename).parent_path()).string();
auto relative_mtl_file = std::filesystem::relative(materials_file, std::filesystem::path(filename).parent_path()).string();
write_materials(materials_file.c_str());

auto j = json_object();
json_object_set(j, "geometry", json_string(relative_obj_file.c_str()));
json_object_set(j, "materials", json_string(relative_mtl_file.c_str()));

{
auto camera = json_object();
json_object_set(camera, "viewport", json_uint2_to_array(_private->scene.camera.image_size));
json_object_set(camera, "origin", json_float3_to_array(_private->scene.camera.position));
json_object_set(camera, "target", json_float3_to_array(_private->scene.camera.position + _private->scene.camera.direction));
json_object_set(camera, "up", json_float3_to_array(_private->scene.camera.up));
json_object_set(camera, "lens-radius", json_real(_private->scene.camera.lens_radius));
json_object_set(camera, "focal-distance", json_real(_private->scene.camera.focal_distance));
json_object_set(camera, "focal-length", json_real(get_camera_focal_length(_private->scene.camera)));
json_object_set(j, "camera", camera);
}

json_dumpf(j, fout, JSON_INDENT(2));
fclose(fout);

json_decref(j);
}

bool SceneRepresentation::load_from_file(const char* filename, uint32_t options) {
_private->cleanup();

uint32_t load_result = SceneRepresentationImpl::LoadFailed;

std::string file_to_load = filename;
std::string material_file = {};
_private->json_file_name = {};
_private->mtl_file_name = {};
_private->obj_file_name = filename;

char base_folder[2048] = {};
get_file_folder(filename, base_folder, sizeof(base_folder));
Expand Down Expand Up @@ -480,14 +561,14 @@ bool SceneRepresentation::load_from_file(const char* filename, uint32_t options)
json_decref(js);
return false;
}
file_to_load = std::string(base_folder) + json_string_value(js_value);
_private->obj_file_name = std::string(base_folder) + json_string_value(js_value);
} else if (strcmp(key, "materials") == 0) {
if (json_is_string(js_value) == false) {
log::error("`materials` in scene description should be a string (file name)");
json_decref(js);
return false;
}
material_file = json_string_value(js_value);
_private->mtl_file_name = json_string_value(js_value);
} else if (strcmp(key, "camera") == 0) {
if (json_is_object(js_value) == false) {
log::error("`camera` in scene description should be an object");
Expand Down Expand Up @@ -522,11 +603,12 @@ bool SceneRepresentation::load_from_file(const char* filename, uint32_t options)
}
}
json_decref(js);
_private->json_file_name = filename;
}

auto ext = get_file_ext(file_to_load.c_str());
auto ext = get_file_ext(_private->obj_file_name.c_str());
if (strcmp(ext, ".obj") == 0) {
load_result = _private->load_from_obj(file_to_load.c_str(), material_file.c_str());
load_result = _private->load_from_obj(_private->obj_file_name.c_str(), _private->mtl_file_name.c_str());
}

if ((load_result & SceneRepresentationImpl::LoadSucceeded) == 0) {
Expand All @@ -539,7 +621,7 @@ bool SceneRepresentation::load_from_file(const char* filename, uint32_t options)
}
cam.cls = camera_cls;
if (use_focal_len) {
camera_fov = 0.5f * focal_length_to_fov(camera_focal_len) * 180.0f / kPi;
camera_fov = focal_length_to_fov(camera_focal_len) * 180.0f / kPi;
}
update_camera(cam, camera_pos, camera_view, camera_up, viewport, camera_fov);
}
Expand Down Expand Up @@ -676,20 +758,20 @@ Material::Class material_string_to_class(const char* s) {

void material_class_to_string(Material::Class cls, const char** str) {
static const char* names[] = {
"Diffuse",
"Plastic",
"Conductor",
"Dielectric",
"Thinfilm",
"Mirror",
"Boundary",
"Coating",
"Velvet",
"Subsurface",
"Undefined",
"diffuse",
"plastic",
"conductor",
"dielectric",
"thinfilm",
"mirror",
"boundary",
"coating",
"velvet",
"subsurface",
"undefined",
};
static_assert(sizeof(names) / sizeof(names[0]) == uint32_t(Material::Class::Count) + 1);
*str = cls < Material::Class::Count ? names[uint32_t(cls)] : "Undefined";
*str = cls < Material::Class::Count ? names[uint32_t(cls)] : "undefined";
}

const char* material_class_to_string(Material::Class cls) {
Expand Down
3 changes: 3 additions & 0 deletions sources/etx/render/host/scene_loader.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ struct SceneRepresentation {
~SceneRepresentation();

bool load_from_file(const char* filename, uint32_t options);
void save_to_file(const char* filename);
void write_materials(const char* filename);

Scene& mutable_scene();
Scene* mutable_scene_pointer();
Expand All @@ -38,6 +40,7 @@ struct SceneRepresentation {
Camera build_camera(const float3& origin, const float3& target, const float3& up, const uint2& viewport, float fov, float lens_radius, float focal_distance);
void update_camera(Camera& camera, const float3& origin, const float3& target, const float3& up, const uint2& viewport, float fov);
float get_camera_fov(const Camera& camera);
float get_camera_focal_length(const Camera& camera);
float fov_to_focal_length(float fov);
float focal_length_to_fov(float focal_len);

Expand Down
13 changes: 13 additions & 0 deletions sources/raytracer/app.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ void RTApplication::init() {
ui.callbacks.reference_image_selected = std::bind(&RTApplication::on_referenece_image_selected, this, std::placeholders::_1);
ui.callbacks.save_image_selected = std::bind(&RTApplication::on_save_image_selected, this, std::placeholders::_1, std::placeholders::_2);
ui.callbacks.scene_file_selected = std::bind(&RTApplication::on_scene_file_selected, this, std::placeholders::_1);
ui.callbacks.save_scene_file_selected = std::bind(&RTApplication::on_save_scene_file_selected, this, std::placeholders::_1);
ui.callbacks.integrator_selected = std::bind(&RTApplication::on_integrator_selected, this, std::placeholders::_1);
ui.callbacks.preview_selected = std::bind(&RTApplication::on_preview_selected, this);
ui.callbacks.run_selected = std::bind(&RTApplication::on_run_selected, this);
Expand Down Expand Up @@ -186,6 +187,11 @@ void RTApplication::load_scene_file(const std::string& file_name, uint32_t optio
}
}

void RTApplication::save_scene_file(const std::string& file_name) {
log::info("Saving %s..", file_name.c_str());
scene.save_to_file(file_name.c_str());
}

void RTApplication::on_referenece_image_selected(std::string file_name) {
log::warning("Loading reference image %s...", file_name.c_str());

Expand Down Expand Up @@ -271,6 +277,13 @@ void RTApplication::on_scene_file_selected(std::string file_name) {
load_scene_file(file_name, SceneRepresentation::LoadEverything, false);
}

void RTApplication::on_save_scene_file_selected(std::string file_name) {
if (strlen(get_file_ext(file_name.c_str())) == 0) {
file_name += ".json";
}
save_scene_file(file_name);
}

void RTApplication::on_integrator_selected(Integrator* i) {
if (_current_integrator == i) {
return;
Expand Down
5 changes: 4 additions & 1 deletion sources/raytracer/app.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ struct RTApplication {
void frame();
void cleanup();
void process_event(const sapp_event*);
void load_scene_file(const std::string&, uint32_t options, bool start_rendering);

private:
void load_scene_file(const std::string&, uint32_t options, bool start_rendering);
void save_scene_file(const std::string&);

void on_referenece_image_selected(std::string);
void on_save_image_selected(std::string, SaveImageMode);
void on_scene_file_selected(std::string);
void on_save_scene_file_selected(std::string);
void on_integrator_selected(Integrator*);
void on_preview_selected();
void on_run_selected();
Expand Down
14 changes: 11 additions & 3 deletions sources/raytracer/ui.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ void UI::build(double dt, const char* status) {
if (igMenuItemEx("Reload Materials", nullptr, "Ctrl+M", false, false)) {
}
igSeparator();
if (igMenuItemEx("Save...", nullptr, nullptr, false, false)) {
if (igMenuItemEx("Save...", nullptr, nullptr, false, true)) {
save_scene_file();
}
igEndMenu();
}
Expand Down Expand Up @@ -391,7 +392,7 @@ void UI::build(double dt, const char* status) {

float3 pos = camera.position;
float3 target = camera.position + camera.direction;
float focal_len = fov_to_focal_length(2.0f * get_camera_fov(camera) * kPi / 180.0f);
float focal_len = get_camera_focal_length(camera);

igText("Lens size");
changed = changed || igDragFloat("##lens", &camera.lens_radius, 0.01f, 0.0f, 2.0, "%.3f", ImGuiSliderFlags_None);
Expand All @@ -403,7 +404,7 @@ void UI::build(double dt, const char* status) {
if (changed && callbacks.camera_changed) {
camera.lens_radius = fmaxf(camera.lens_radius, 0.0f);
camera.focal_distance = fmaxf(camera.focal_distance, 0.0f);
update_camera(camera, pos, target, float3{0.0f, 1.0f, 0.0f}, camera.image_size, 0.5f * focal_length_to_fov(focal_len) * 180.0f / kPi);
update_camera(camera, pos, target, float3{0.0f, 1.0f, 0.0f}, camera.image_size, focal_length_to_fov(focal_len) * 180.0f / kPi);
callbacks.camera_changed();
}
} else {
Expand Down Expand Up @@ -567,6 +568,13 @@ void UI::select_scene_file() {
}
}

void UI::save_scene_file() {
auto selected_file = save_file({"Scene description", "*.json"});
if ((selected_file.empty() == false) && callbacks.save_scene_file_selected) {
callbacks.save_scene_file_selected(selected_file);
}
}

void UI::save_image(SaveImageMode mode) {
auto selected_file = save_file({
mode == SaveImageMode::TonemappedLDR ? "PNG images" : "EXR images",
Expand Down
2 changes: 2 additions & 0 deletions sources/raytracer/ui.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct UI {
std::function<void(std::string)> reference_image_selected;
std::function<void(std::string, SaveImageMode)> save_image_selected;
std::function<void(std::string)> scene_file_selected;
std::function<void(std::string)> save_scene_file_selected;
std::function<void(Integrator*)> integrator_selected;
std::function<void(bool)> stop_selected;
std::function<void()> preview_selected;
Expand All @@ -56,6 +57,7 @@ struct UI {
private:
bool build_options(Options&);
void select_scene_file();
void save_scene_file();
void save_image(SaveImageMode mode);
void load_image();
bool build_material(Material&);
Expand Down

0 comments on commit a9cad67

Please sign in to comment.