Add AOV rendering support and related enhancements
Added support for rendering Arbitrary Output Variables (AOVs) for detailed outputs like beauty, albedo, normal, depth, and position. Added new functions `render_aov` and `accumulate_aov` for AOV data management during rendering. Added AOV rendering capabilities to the `SimpleLit` material with specific functions. Changed the material system to include new function pointers for AOV rendering. Changed the renderer to initialize and update AOV targets during the rendering process. Changed the main rendering loop to handle AOVs and update render targets accordingly. Fixed various minor issues, including function signature updates, variable name changes, and improved error handling for memory allocations.
This commit is contained in:
@@ -3,6 +3,40 @@
|
||||
|
||||
#define FLIP_Y
|
||||
|
||||
static inline void create_target_if_required(aov_flags_t aov_flags, aov_flags_t target_flag, render_target_t** render_target, uint32_t width, uint32_t height)
|
||||
{
|
||||
render_target_t* temp = NULL;
|
||||
if (has_flag(aov_flags, target_flag))
|
||||
{
|
||||
temp = (render_target_t*)malloc(sizeof(render_target_t));
|
||||
if (temp == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
render_target_init(width, height, temp);
|
||||
}
|
||||
|
||||
*render_target = temp;
|
||||
}
|
||||
|
||||
bool renderer_aov_target_init(render_job_t* job, aov_flags_t aov_flags)
|
||||
{
|
||||
job->aov_target = (render_target_t**)malloc(sizeof(render_target_t*) * MAX_AOV_TARGET);
|
||||
if (job->aov_target == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
create_target_if_required(aov_flags, AOV_BEAUTY, &job->aov_target[AOV_BEAUTY_INDEX], job->config->width, job->config->height);
|
||||
create_target_if_required(aov_flags, AOV_AlBEDO, &job->aov_target[AOV_AlBEDO_INDEX], job->config->width, job->config->height);
|
||||
create_target_if_required(aov_flags, AOV_NORMAL, &job->aov_target[AOV_NORMAL_INDEX], job->config->width, job->config->height);
|
||||
create_target_if_required(aov_flags, AOV_DEPTH, &job->aov_target[AOV_DEPTH_INDEX], job->config->width, job->config->height);
|
||||
create_target_if_required(aov_flags, AOV_POSITION, &job->aov_target[AOV_POSITION_INDEX], job->config->width, job->config->height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void ensure_camera_aspect_ratio(camera_t* camera, const rendering_config_t* config)
|
||||
{
|
||||
float aspect_ratio = (float)config->width / config->height;
|
||||
@@ -25,27 +59,23 @@ static inline vec2s compute_ndc(float x, float y, uint32_t width, uint32_t heigh
|
||||
};
|
||||
}
|
||||
|
||||
static inline uint16_t get_sample_count(uint16_t sample_count, int flag)
|
||||
static inline uint16_t get_sample_count(uint16_t sample_count, aov_index_t index)
|
||||
{
|
||||
switch (flag)
|
||||
switch (index)
|
||||
{
|
||||
case DEBUG_BVH:
|
||||
case DEBUG_SOBOL:
|
||||
case DEBUG_UV:
|
||||
return 1;
|
||||
default:
|
||||
case AOV_BEAUTY_INDEX:
|
||||
return sample_count;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s coord, uint32_t x, uint32_t y, debug_flag_t flag, vec4s* pixel_color)
|
||||
static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s coord, uint32_t x, uint32_t y, bool request_aov, aov_output_t* pixel_output)
|
||||
{
|
||||
vec4s accumulated_color = glms_vec4_zero();
|
||||
aov_output_t accumulated_color = {0};
|
||||
|
||||
uint32_t pixel_id = y * config->width + x;
|
||||
uint16_t sample_count = get_sample_count(config->sample_count, flag);
|
||||
uint16_t sample_count = config->sample_count;
|
||||
float inv_sample = 1.0f / (float)sample_count;
|
||||
|
||||
vec3s camera_right = quat_get_right(scene->camera.rotation);
|
||||
@@ -72,11 +102,36 @@ static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s
|
||||
|
||||
ray_t ray = ray_create(scene->camera.position, glms_vec3_normalize(glms_vec3_sub(image_plane_point, scene->camera.position)));
|
||||
|
||||
vec4s out_color = flag == 0 ? path_trace(scene, ray, sobol_idx, config->max_depth) : render_debug(scene, ray, sobol_idx, flag);
|
||||
accumulated_color = glms_vec4_add(accumulated_color, out_color);
|
||||
aov_output_t aov_output = {0};
|
||||
aov_output.beauty = path_trace(scene, ray, sobol_idx, config->max_depth);
|
||||
if (request_aov)
|
||||
{
|
||||
render_aov(scene, ray, sobol_idx, config->max_depth, &aov_output);
|
||||
}
|
||||
|
||||
accumulate_aov(&accumulated_color, &aov_output, inv_sample);
|
||||
}
|
||||
|
||||
*pixel_color = glms_vec4_scale(accumulated_color, inv_sample);
|
||||
*pixel_output = accumulated_color;
|
||||
}
|
||||
|
||||
static inline void update_aov_pixel_if_exist(render_target_t** target, vec4s color, uint32_t x, uint32_t y)
|
||||
{
|
||||
if (*target == NULL || (*target)->buffer == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
render_target_set_pixel(*target, x, y, color);
|
||||
}
|
||||
|
||||
static inline void update_aov(render_target_t** target, const aov_output_t* aov, uint32_t x, uint32_t y)
|
||||
{
|
||||
update_aov_pixel_if_exist(&target[AOV_BEAUTY_INDEX], aov->beauty, x, y);
|
||||
update_aov_pixel_if_exist(&target[AOV_AlBEDO_INDEX], aov->albedo, x, y);
|
||||
update_aov_pixel_if_exist(&target[AOV_NORMAL_INDEX], aov->normal, x, y);
|
||||
update_aov_pixel_if_exist(&target[AOV_DEPTH_INDEX], (vec4s){aov->depth, aov->depth, aov->depth, 1.0f}, x, y);
|
||||
update_aov_pixel_if_exist(&target[AOV_POSITION_INDEX], aov->position, x, y);
|
||||
}
|
||||
|
||||
// TODO: Progressive rendering
|
||||
@@ -88,13 +143,12 @@ void renderer_start(render_job_t* job)
|
||||
uint32_t tile_count_y = (job->config->height + job->config->bucket_size - 1) / job->config->bucket_size;
|
||||
uint32_t tile_count = tile_count_x * tile_count_y;
|
||||
|
||||
float inv_sample = 1.0f / job->config->sample_count;
|
||||
vec3s coord = glms_vec3_add(job->scene->camera.position, glms_vec3_scale(quat_get_forward(job->scene->camera.rotation), job->scene->camera.focal_length));
|
||||
|
||||
int64_t x, y, tile_index; // OpenMP requires these to be declared outside the parallel region. Also, they need to be signed integers. To avoid overflow, we need to use int64_t
|
||||
|
||||
#pragma omp parallel for schedule(dynamic, 1) default(none) \
|
||||
shared(tile_count_x, tile_count_y, tile_count, coord, inv_sample, job) \
|
||||
shared(tile_count_x, tile_count_y, tile_count, coord, job) \
|
||||
private(x, y, tile_index)
|
||||
for (tile_index = 0; tile_index < tile_count; tile_index++)
|
||||
{
|
||||
@@ -112,13 +166,32 @@ void renderer_start(render_job_t* job)
|
||||
goto tile_done;
|
||||
}
|
||||
|
||||
vec4s pixel_color;
|
||||
render_pixel(job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, job->debug_flag, &pixel_color);
|
||||
render_target_set_pixel(job->render_target, (uint32_t)x, (uint32_t)y, pixel_color);
|
||||
aov_output_t pixel_output = {0};
|
||||
render_pixel(job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, job->aov_flags != AOV_BEAUTY, &pixel_output);
|
||||
update_aov(job->aov_target, &pixel_output, (uint32_t)x, (uint32_t)y);
|
||||
}
|
||||
}
|
||||
tile_done:;
|
||||
tile_done:;
|
||||
}
|
||||
|
||||
// TODO: A-Trous denoising
|
||||
|
||||
job->is_done = true;
|
||||
}
|
||||
|
||||
void render_job_free(render_job_t* job)
|
||||
{
|
||||
if (job == NULL || job->aov_target == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < MAX_AOV_TARGET; i++)
|
||||
{
|
||||
if (job->aov_target[i] != NULL)
|
||||
{
|
||||
render_target_free(job->aov_target[i]);
|
||||
free(job->aov_target[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user