Skip to content

Commit

Permalink
Lights outside the scene for path tracing (#1065)
Browse files Browse the repository at this point in the history
  • Loading branch information
xelatihy authored Sep 2, 2020
1 parent fd081e8 commit 6669856
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 116 deletions.
26 changes: 14 additions & 12 deletions apps/ysceneitrace/ysceneitrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ struct app_state {
sceneio_camera* iocamera = nullptr;
trace_camera* camera = nullptr;

// rendering objects
trace_lights* lights = new trace_lights{};

// options
trace_params params = {};

Expand Down Expand Up @@ -91,13 +94,12 @@ struct app_state {
string loader_error = "";

~app_state() {
if (render_state) {
trace_stop(render_state);
delete render_state;
}
if (scene) delete scene;
if (ioscene) delete ioscene;
if (glimage) delete glimage;
if (render_state) trace_stop(render_state);
delete render_state;
delete scene;
delete lights;
delete ioscene;
delete glimage;
}
};

Expand Down Expand Up @@ -245,7 +247,7 @@ void reset_display(app_state* app) {
app->status = "render";
app->render_counter = 0;
trace_start(
app->render_state, app->scene, app->camera, app->params,
app->render_state, app->scene, app->camera, app->lights, app->params,
[app](const string& message, int sample, int nsamples) {
app->current = sample;
app->total = nsamples;
Expand Down Expand Up @@ -288,8 +290,8 @@ void load_scene_async(app_states* apps, const string& filename,
app->scene, app->ioscene, app->camera, app->iocamera, progress_cb);
tesselate_shapes(app->scene, progress_cb);
init_bvh(app->scene, app->params);
init_lights(app->scene);
if (app->scene->lights.empty() && is_sampler_lit(app->params)) {
init_lights(app->lights, app->scene);
if (app->lights->lights.empty() && is_sampler_lit(app->params)) {
app->params.sampler = trace_sampler_type::eyelight;
}
});
Expand Down Expand Up @@ -588,7 +590,7 @@ void draw_widgets(gui_window* win, app_states* apps, const gui_input& input) {
set_frame(environment, ioenvironment->frame);
set_emission(environment, ioenvironment->emission,
get_texture(ioenvironment->emission_tex));
init_lights(app->scene);
init_lights(app->lights, app->scene);
reset_display(app);
}
end_header(win);
Expand Down Expand Up @@ -664,7 +666,7 @@ void draw_widgets(gui_window* win, app_states* apps, const gui_input& input) {
set_normalmap(material, get_texture(iomaterial->normal_tex));
set_scattering(material, iomaterial->scattering, iomaterial->scanisotropy,
get_texture(iomaterial->scattering_tex));
init_lights(app->scene);
init_lights(app->lights, app->scene);
reset_display(app);
}
end_header(win);
Expand Down
18 changes: 10 additions & 8 deletions apps/ysceneitraces/ysceneitraces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ struct app_state {
trace_camera* camera = nullptr;
vector<string> camera_names = {};

// rendering objects
trace_lights* lights = new trace_lights{};

// rendering state
image<vec4f> render = {};
image<vec4f> display = {};
Expand All @@ -72,11 +75,10 @@ struct app_state {
std::atomic<int> total = 0;

~app_state() {
if (render_state) {
trace_stop(render_state);
delete render_state;
}
if (scene) delete scene;
if (render_state) trace_stop(render_state);
delete render_state;
delete lights;
delete scene;
if (glimage) delete glimage;
}
};
Expand All @@ -88,7 +90,7 @@ void reset_display(app_state* app) {
// start render
app->render_counter = 0;
trace_start(
app->render_state, app->scene, app->camera, app->params,
app->render_state, app->scene, app->camera, app->lights, app->params,
[app](const string& message, int sample, int nsamples) {
app->current = sample;
app->total = nsamples;
Expand Down Expand Up @@ -281,10 +283,10 @@ int main(int argc, const char* argv[]) {
init_bvh(app->scene, app->params, print_progress);

// init renderer
init_lights(app->scene, print_progress);
init_lights(app->lights, app->scene, print_progress);

// fix renderer type if no lights
if (app->scene->lights.empty() && is_sampler_lit(app->params)) {
if (app->lights->lights.empty() && is_sampler_lit(app->params)) {
print_info("no lights presents, switching to eyelight shader");
app->params.sampler = trace_sampler_type::eyelight;
}
Expand Down
16 changes: 9 additions & 7 deletions apps/yscenetrace/yscenetrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,16 +214,18 @@ int main(int argc, const char* argv[]) {
init_bvh(scene, params, print_progress);

// init renderer
init_lights(scene, print_progress);
auto lights_guard = std::make_unique<trace_lights>();
auto lights = lights_guard.get();
init_lights(lights, scene, print_progress);

// fix renderer type if no lights
if (scene->lights.empty() && is_sampler_lit(params)) {
if (lights->lights.empty() && is_sampler_lit(params)) {
print_info("no lights presents, switching to eyelight shader");
params.sampler = trace_sampler_type::eyelight;
}

// render
auto render = trace_image(scene, camera, params, print_progress,
auto render = trace_image(scene, camera, lights, params, print_progress,
[save_batch, imfilename](
const image<vec4f>& render, int sample, int samples) {
if (!save_batch) return;
Expand Down Expand Up @@ -253,8 +255,8 @@ int main(int argc, const char* argv[]) {
fparams.samples = feature_samples;

// render denoise albedo
fparams.sampler = trace_sampler_type::albedo;
auto albedo = trace_image(scene, camera, fparams, print_progress);
fparams.sampler = trace_sampler_type::albedo;
auto albedo = trace_image(scene, camera, lights, fparams, print_progress);
auto albedo_filename = replace_extension(
imfilename, "-albedo" + feature_ext);

Expand All @@ -263,8 +265,8 @@ int main(int argc, const char* argv[]) {
print_progress("save albedo feature", 1, 1);

// render denoise normals
fparams.sampler = trace_sampler_type::normal;
auto normal = trace_image(scene, camera, fparams, print_progress);
fparams.sampler = trace_sampler_type::normal;
auto normal = trace_image(scene, camera, lights, fparams, print_progress);
auto normal_filename = replace_extension(
imfilename, "-normal" + feature_ext);

Expand Down
57 changes: 50 additions & 7 deletions docs/yocto/yocto_trace.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ or stop-and-resume renders.
## Rendering a scene

To render a scene, first tesselate shapes for subdivs and displacement,
with `tesselate_shapes(scene, params, progress)`, then initialize the scene
bvh and lights, with `init_bvh(scene, params, progress)` and
`init_lights(scene, params, progress)`, and then call
with `tesselate_shapes(scene, params, progress)`, then call
`trace_image(scene, camera, params, progress, image_progress)`.
In these functions, `params` are the rendering options used to
render the scene, `progress` is a callback function used to
Expand All @@ -49,8 +47,6 @@ auto progress = [](const string& message, // progress callback
print_info(message, current, total);
};
tesselate_shapes(scene, params, progress);// tesselate shapes if needed
init_bvh(scene, params, progress); // init bvh
init_lights(scene, params, progress); // init lights
trace_image(scene, params, progress); // render image
auto improgress = [](const image<vec4f>& render, // image progress
int sample, int samples) {
Expand Down Expand Up @@ -108,6 +104,53 @@ db_params.resolution = 720; // medium-res render
db_params.samples = 16; // low-sample count
```

## Low-Level Rendering API

Yocto/Trace supports a low-level rendering API that is more flexible for
applications that need it. In this modality, you have to manage all state
manually.

Yocto/Trace internally uses a `trace_bvh` BVH for ray-scene intersection,
a `trace_lights` objects to store lighting information, and a `trace_state`
object to tracks the rendering process and contains all data needed to perform
progressive computation. Each object need to be initialized separately.

To render a scene, first tesselate shapes for subdivs and displacement,
with `tesselate_shapes(scene, params, progress)`, then initialize the scene
bvh and lights, with `init_bvh(scene, params, progress)` and
`init_lights(lights, scene, params, progress)`, then initialize the state
with `init_state(state, scene, params)` and then call
`trace_image(state, scene, camera, lights, params, progress, image_progress)`.
In these functions, `params` are the rendering options used to
render the scene, `progress` is a callback function used to
report rendering progress and `image_progress` is a callback
function used to report partial images during rendering.
Both callback functions are optional.

```cpp
auto scene = new trace_scene{...}; // initialize scene
auto params = trace_params{}; // default params
auto progress = [](const string& message, // progress callback
int current, int total) {
print_info(message, current, total);
};
tesselate_shapes(scene, params, progress);// tesselate shapes if needed
init_bvh(scene, params, progress); // init bvh
auto lights = new trace_lights{}; // trace lights
init_lights(lights, scene, params, progress); // init lights
auto state = new trace_state{}; // trace state
init_state(state, scene, params, progress); // init lights
trace_image(state, scene, camera, lights, // render image
params, progress);
auto improgress = [](const image<vec4f>& render, // image progress
int sample, int samples) {
if(sample % 16 == 0) // every 16 samples
save_image(filename, render); // save image
};
trace_image(state, scene, camera, lights, // render image
params, progress, improgress);
```
## Experimental async rendering
The render can run in asynchronous mode where the rendering process is
Expand All @@ -119,14 +162,14 @@ by rendering a low resolution preview and then proceeds progressively.
The async renderer takes a `trace_state` struct that tracks the rendering
process and contains all data needed by the async renderer. Rendering progress
ifs given by three callbacks. The first two are the rendering callbacks
is given by three callbacks. The first two are the rendering callbacks
defined for offline rendeirng, that return progress report and an image buffer
for each sample. In async mode, a further callback is called after each
pixel is rendered.
During rendering, no scenes changes are allowed, and changes to bvh and lights
are not tracked. This is on purpose since it allows for a simple API while
retaining maximum speed. To changes the scene, first stop the render, than
retaining maximum speed. To change the scene, first stop the render, than
apply scene changes, than update lights and bvh if needed, and finally restart
the renderer.
To update the BVH, use `update_bvh(scene, instances, shapes, params)` where
Expand Down
Loading

0 comments on commit 6669856

Please sign in to comment.