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:
2025-05-04 17:32:48 +09:00
parent 4c62b3ecde
commit 4b29de15cd
16 changed files with 357 additions and 135 deletions

View File

@@ -54,7 +54,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
float cos_theta = fmaxf(0.0f, glms_vec3_dot(material_output.wi, closest_hit.normal));
throughput = glms_vec3_mul(throughput, material_output.bsdf);
// We do Russian roulette to decide whether to continue tracing or terminate the path
if (depth > 1)
{
@@ -70,7 +70,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
switch (material_output.state)
{
case TERMINATE:
case PS_TERMINATE:
goto end_path_trace;
//case PATH_THROUGH:
// active_ray = ray_create(BIAS_RAY_ORIGION(closest_hit.point, glms_vec3_negate(closest_hit.normal)), active_ray.direction);
@@ -85,3 +85,37 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
end_path_trace:
return accumulated_color;
}
// How to handle multi-bounced aov like indirect lighting?
// Maybe we should move aov to path_trace and split accumulated_color into direct/indirect diffuse/specular before returning.
void render_aov(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_t max_depth, aov_output_t* aov_output)
{
hit_result_t closest_hit = ray_intersect_scene(&ray, scene);
if (!closest_hit.hit)
{
return;
}
const material_t* hit_material = &scene->materials.buffer[scene->triangles.buffer[closest_hit.triangle_id].material_id];
shading_context_t shading_context =
{
.position = closest_hit.point,
.normal = closest_hit.normal,
.tangent = closest_hit.tangent,
.uv = closest_hit.uv,
.wo = ray.direction,
.throughput = 1.0f,
.sample_index = sample_index,
.bounce_depth = 0,
.bvh_tree = &scene->bvh_tree,
.triangles = &scene->triangles,
.lights = &scene->lights,
.textures = &scene->textures,
};
render_material_aov(hit_material, &shading_context, aov_output);
aov_output->position = glms_vec4(closest_hit.point, 1.0f);
aov_output->depth = closest_hit.distance;
}

View File

@@ -5,7 +5,7 @@
path_output evaluate_bsdf_directional(directional_light_t light, const light_shading_context_t* context, vec3s throughput, uint32_t sample_index)
{
path_output output = {0.0f};
output.state = TERMINATE;
output.state = PS_TERMINATE;
output.pdf = 1.0f;
if (light.intensity <= 0.0f)
@@ -26,7 +26,7 @@ path_output evaluate_bsdf_directional(directional_light_t light, const light_sha
return output;
}
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->hit_point, context->normal), wi);
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->position, context->normal), wi);
float closest = FLT_MAX;
hit_result_t shadow_hit = {1};
@@ -42,6 +42,6 @@ path_output evaluate_bsdf_directional(directional_light_t light, const light_sha
output.direct_lighting = glms_vec3_mul(light_radiance, light_contribute);
output.wi = wi;
output.state = NORMAL;
output.state = PS_NORMAL;
return output;
}

View File

@@ -1,6 +1,8 @@
#include "Lighting/SkyLight.h"
#include "Common.h"
// Constant Sky
sky_light_t sky_create_constant_sky(const constant_sky_data_t* data)
{
sky_light_t light = {
@@ -23,7 +25,7 @@ path_output evaluate_bsdf_const_sky(const void* data, const light_shading_contex
const constant_sky_data_t* sky_data = (const constant_sky_data_t*)data;
path_output output = {0.0f};
output.state = TERMINATE;
output.state = PS_TERMINATE;
if (sky_data->intensity <= 0.0f)
{
@@ -45,7 +47,7 @@ path_output evaluate_bsdf_const_sky(const void* data, const light_shading_contex
vec3s wi = random_uniform_cdf_direction(context->normal, sample_index, d1, d2);
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->hit_point, context->normal), wi);
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->position, context->normal), wi);
float closest = FLT_MAX;
hit_result_t shadow_hit = {1};
@@ -59,7 +61,7 @@ path_output evaluate_bsdf_const_sky(const void* data, const light_shading_contex
output.direct_lighting = glms_vec3_scale(glms_vec3_mul(sky_light, throughput), cos_theta / pdf);
output.wi = wi;
output.state = NORMAL;
output.state = PS_NORMAL;
return output;
}
@@ -84,6 +86,8 @@ static uint32_t lower_bound_float(const float* arr, uint32_t n, float target)
return low; // This is the index where target would be inserted to maintain order
}
// HDR Sky
sky_light_t sky_create_hdr_sky(const texture_collection_t* textures, texture_entity_t hdri_entity, float intensity)
{
sky_light_t light = {
@@ -98,12 +102,6 @@ sky_light_t sky_create_hdr_sky(const texture_collection_t* textures, texture_ent
return light;
}
light.data = malloc(sizeof(hdr_sky_data_t));
if (light.data == NULL)
{
return light;
}
hdr_sky_data_t data = {
.width = hdri->width,
.height = hdri->height,
@@ -256,6 +254,13 @@ sky_light_t sky_create_hdr_sky(const texture_collection_t* textures, texture_ent
free(intermediate_buffer);
light.data = malloc(sizeof(hdr_sky_data_t));
if (light.data == NULL)
{
free(cache);
return light;
}
data.total_weight = lumSum;
data.cdf_cache = cache;
@@ -283,7 +288,7 @@ path_output evaluate_bsdf_hdr_sky(const void* data, const light_shading_context_
const hdr_sky_data_t* sky_data = (const hdr_sky_data_t*)data;
path_output output = {0.0f};
output.state = TERMINATE;
output.state = PS_TERMINATE;
if (sky_data->intensity <= 0.0f)
{
@@ -303,21 +308,7 @@ path_output evaluate_bsdf_hdr_sky(const void* data, const light_shading_context_
// TODO: Should we also use sobol numbers for the sky sampling?
uv_to_index((vec2s){random_float(), random_float()}, sky_data->width, sky_data->height, &j, &i);
vec3s cdf = sky_data->cdf_cache[i * sky_data->width + j];
float theta = -cdf.y * PI;
float phi = cdf.x * TWO_PI;
float sin_theta = sinf(theta);
float cos_theta = cosf(theta);
float sin_phi = sinf(phi);
float cos_phi = cosf(phi);
vec3s wi = glms_vec3_normalize((vec3s)
{
sin_theta * cos_phi,
cos_theta,
sin_theta * sin_phi,
});
vec3s wi = equirectangular_to_direction(cdf.x,-cdf.y);
float n_dot_l = glms_vec3_dot(wi, context->normal);
if (n_dot_l <= 0.0f)
@@ -325,7 +316,7 @@ path_output evaluate_bsdf_hdr_sky(const void* data, const light_shading_context_
return output;
}
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->hit_point, context->normal), wi);
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->position, context->normal), wi);
float closest = FLT_MAX;
hit_result_t shadow_hit = {1};
@@ -346,7 +337,7 @@ path_output evaluate_bsdf_hdr_sky(const void* data, const light_shading_context_
output.wi = wi;
output.pdf = pdf;
output.state = NORMAL;
output.state = PS_NORMAL;
return output;
}

View File

@@ -46,12 +46,18 @@ void material_collection_free(material_collection_t* materials)
{
if (materials->buffer != NULL)
{
for (uint8_t i = 0; i < materials->count; i++)
{
free(materials->buffer[i].properties);
materials->buffer[i].properties = NULL;
}
free(materials->buffer);
materials->buffer = NULL;
}
}
material_entity_t material_create(const void* properties, size_t properties_size, material_render_loop_f render_loop, material_collection_t* collection)
material_entity_t material_create(const void* properties, size_t properties_size, material_render_loop_f render_loop, material_render_aov_f render_aov, material_collection_t* collection)
{
material_t material = {0};
@@ -60,8 +66,18 @@ material_entity_t material_create(const void* properties, size_t properties_size
material_collection_resize(collection, collection->size * 2);
}
memcpy(material.properties, properties, properties_size);
void* temp = malloc(properties_size);
if (temp == NULL)
{
return invalid_material_entity();
}
memcpy(temp, properties, properties_size);
material.properties = temp;
material.properties_size = properties_size;
material.render_loop = render_loop;
material.render_aov = render_aov;
material_entity_t entity = {.id = collection->count};
@@ -70,3 +86,21 @@ material_entity_t material_create(const void* properties, size_t properties_size
return entity;
}
// void material_free(material_entity_t entity, material_collection_t* collection)
// {
// if (entity.id >= collection->count || !is_material_entity_valid(entity))
// {
// return;
// }
//
// free(collection->buffer[entity.id].properties);
// collection->buffer[entity.id].properties = NULL;
//
// for (uint8_t i = entity.id; i < collection->count - 1; i++)
// {
// collection->buffer[i] = collection->buffer[i + 1];
// }
//
// collection->count--;
// }

View File

@@ -50,7 +50,7 @@ static vec3s sample_bsdf_simple_lit(const shading_context_t* context, const surf
//TODO: having a bsdf data struct to avoid recomputing the same thing in both sample and evaluate
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, surface_data->albedo, surface_data->metallic);
float cos_theta_0 = fmaxf(glms_vec3_dot(context->normal, L), 0.0f);
float cos_theta_0 = fmaxf(glms_vec3_dot(surface_data->normal, L), 0.0f);
vec3s f = fresnel_schlick_vec3(f0, cos_theta_0);
float lum_f = (f.x + f.y + f.z) / 3.0f;
@@ -75,7 +75,7 @@ static vec3s sample_bsdf_simple_lit(const shading_context_t* context, const surf
if (lob_sample < prob_diffuse) // Diffuse Lobe
{
wi = random_cosine_direction(context->normal, sample_index, d1, d2);
wi = random_cosine_direction(surface_data->normal, sample_index, d1, d2);
}
else // Specular Lobe
{
@@ -98,11 +98,11 @@ static vec3s sample_bsdf_simple_lit(const shading_context_t* context, const surf
vec3s tangent_u; // World-space tangent (U)
vec3s bitangent_v; // World-space bitangent (V)
create_orthonormal_basis(context->normal, &tangent_u, &bitangent_v);
create_orthonormal_basis(surface_data->normal, &tangent_u, &bitangent_v);
vec3s scaled_u = glms_vec3_scale(tangent_u, h_ts.x);
vec3s scaled_v = glms_vec3_scale(bitangent_v, h_ts.y);
vec3s scaled_n = glms_vec3_scale(context->normal, h_ts.z);
vec3s scaled_n = glms_vec3_scale(surface_data->normal, h_ts.z);
// Transform h from tangent space to world space
vec3s h_ws;
@@ -115,14 +115,14 @@ static vec3s sample_bsdf_simple_lit(const shading_context_t* context, const surf
}
// Final check to ensure wi is in the correct hemisphere
if (glms_vec3_dot(wi, context->normal) < 0.0f)
if (glms_vec3_dot(wi, surface_data->normal) < 0.0f)
{
*pdf_out = 0.0f;
return glms_vec3_zero();
}
float pdf_diffuse = pdf_cosine_weighted_hemisphere(context->normal, wi);
float pdf_specular = pdf_blinn_phong_lobe(context->normal, wi, L, surface_data->roughness);
float pdf_diffuse = pdf_cosine_weighted_hemisphere(surface_data->normal, wi);
float pdf_specular = pdf_blinn_phong_lobe(surface_data->normal, wi, L, surface_data->roughness);
*pdf_out = prob_diffuse * pdf_diffuse + prob_specular * pdf_specular;
return wi;
@@ -131,7 +131,7 @@ static vec3s sample_bsdf_simple_lit(const shading_context_t* context, const surf
static float sample_bsdf_pdf_simple_lit(const shading_context_t* context, const surface_data_t* surface_data, vec3s wi)
{
// If wi is below the horizon relative to the normal, PDF must be 0
if (glms_vec3_dot(context->normal, wi) <= 0.0f) // Use <= to be safe
if (glms_vec3_dot(surface_data->normal, wi) <= 0.0f) // Use <= to be safe
{
return 0.0f;
}
@@ -168,9 +168,9 @@ static vec3s evaluate_bsdf_simple_lit(const shading_context_t* context, const su
vec3s L = glms_vec3_negate(context->wo);
vec3s h = glms_vec3_normalize(glms_vec3_add(wi, L));
float n_dot_l = fmaxf(FLT_EPSILON, glms_vec3_dot(context->normal, wi));
float n_dot_v = fmaxf(FLT_EPSILON, glms_vec3_dot(context->normal, L));
float n_dot_h = glms_vec3_dot(context->normal, h);
float n_dot_l = fmaxf(FLT_EPSILON, glms_vec3_dot(surface_data->normal, wi));
float n_dot_v = fmaxf(FLT_EPSILON, glms_vec3_dot(surface_data->normal, L));
float n_dot_h = glms_vec3_dot(surface_data->normal, h);
float v_dot_h = glms_vec3_dot(L, h);
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, surface_data->albedo, surface_data->metallic);
@@ -196,7 +196,7 @@ static vec3s evaluate_bsdf_simple_lit(const shading_context_t* context, const su
}
// NOTE: Need to double check is this physically correct, especially the nee and mis.
path_output simple_lit_render_loop(const void* properties, const shading_context_t* context)
path_output simple_lit_render_loop(const shading_context_t* properties, const shading_context_t* context)
{
surface_data_t surface_data = {0};
get_surface_data(context, properties, &surface_data);
@@ -211,8 +211,8 @@ path_output simple_lit_render_loop(const void* properties, const shading_context
light_shading_context_t light_context =
{
.hit_point = context->position,
.normal = context->normal,
.position = context->position,
.normal = surface_data.normal,
.tangent = context->tangent,
.uv = context->uv,
.wo = context->wo,
@@ -228,7 +228,7 @@ path_output simple_lit_render_loop(const void* properties, const shading_context
for (uint32_t i = 0; i < context->lights->directional_light_count; i++)
{
path_output light_output = evaluate_bsdf_directional(context->lights->directional_lights[i], &light_context, context->throughput, context->sample_index);
if (light_output.state == NORMAL)
if (light_output.state == PS_NORMAL)
{
vec3s bsdf_dir_light = evaluate_bsdf_simple_lit(context, &surface_data, light_output.wi);
vec3s light_contribute = glms_vec3_mul(light_output.direct_lighting, bsdf_dir_light);
@@ -238,7 +238,7 @@ path_output simple_lit_render_loop(const void* properties, const shading_context
// Sky
path_output sky_output = evaluate_bsdf_sky(context->lights, &light_context, context->throughput, context->sample_index);
if (sky_output.state == NORMAL)
if (sky_output.state == PS_NORMAL)
{
vec3s bsdf_sky_light = evaluate_bsdf_simple_lit(context, &surface_data, sky_output.wi);
float pdf_bsdf = sample_bsdf_pdf_simple_lit(context, &surface_data, sky_output.wi);
@@ -249,7 +249,7 @@ path_output simple_lit_render_loop(const void* properties, const shading_context
output.wi = sample_bsdf_simple_lit(context, &surface_data, context->sample_index, context->bounce_depth, &output.pdf);
if (output.pdf <= 0.0f)
{
output.state = TERMINATE;
output.state = PS_TERMINATE;
return output;
}
@@ -257,6 +257,15 @@ path_output simple_lit_render_loop(const void* properties, const shading_context
float cos_theta = fmaxf(0.0f, glms_vec3_dot(output.wi, context->normal));
output.bsdf = glms_vec3_scale(bsdf, cos_theta / output.pdf);
output.state = NORMAL;
output.state = PS_NORMAL;
return output;
}
void simple_lit_render_aov(const shading_context_t* properties, const shading_context_t* context, aov_output_t* aov_output)
{
surface_data_t surface_data = {0};
get_surface_data(context, properties, &surface_data);
aov_output->albedo = glms_vec4(surface_data.albedo, 1.0f);
aov_output->normal = glms_vec4(surface_data.normal, 1.0f);
}

View File

@@ -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]);
}
}
}

View File

@@ -1,3 +1,4 @@
#include <time.h>
#include <omp.h>
#include <stdint.h>
#include <svpng.inc>
@@ -7,6 +8,7 @@
#include "Geometry/Mesh.h"
#include "Lighting/SkyLight.h"
#include "Material/SimpleLit.h"
#include "Rendering/AOV.h"
#include "Rendering/PostProcessing.h"
#include "Rendering/Scene.h"
#include "Window.h"
@@ -23,7 +25,7 @@ static bool scene_setup(scene_t* scene)
}
scene->camera.position = (vec3s){7.5f, 2.0f, 0.0f};
scene->camera.rotation = euler_to_quat(10.0f, 90.0f, 0.0f);
scene->camera.rotation = euler_to_quat(-10.0f, 90.0f, 0.0f);
// TODO: Standardize light unit
light_entity_t sun = light_create_directional_light(&scene->lights);
@@ -41,32 +43,32 @@ static bool scene_setup(scene_t* scene)
texture_entity_t hdri = texture_load(HDRI_PATH, false, FLOAT_32, &scene->textures);
scene->lights.sky_light = sky_create_hdr_sky(&scene->textures, hdri, 1.0f);
return true;
return scene->lights.sky_light.data != NULL;
}
static bool load_assets(scene_t* scene)
{
mesh_load(SCENE_PATH, scene);
// material_entity_t floor_material = material_create_simple_lit_default(&(simple_lit_properties_t)
// {
// .albedo = (vec3s){0.8f, 0.8f, 0.8f},
// .roughness = 0.95f,
// .metallic = 0.0f,
// .albedo_texture = invalid_texture_entity(),
// .metallic_texture = invalid_texture_entity(),
// .roughness_texture = invalid_texture_entity(),
// }, &scene->materials);
// quad_create((vec3s){0.0f, 0.0f, 0.0f}, (vec3s){0.0f, 1.0f, 0.0f}, (vec3s){1.0f, 0.0f, 0.0f}, 10.0f, floor_material.id, &scene->triangles);
// quad_create((vec3s){0.0f, 0.5f, 0.0f}, (vec3s){1.0f, 0.0f, 0.0f}, (vec3s){0.0f, 1.0f, 0.0f}, 1.0f, floor_material.id, &scene->triangles);
//material_entity_t floor_material = material_create_simple_lit_default(&(simple_lit_properties_t)
//{
// .albedo = (vec3s){0.8f, 0.8f, 0.8f},
// .roughness = 0.95f,
// .metallic = 0.0f,
// .albedo_texture = invalid_texture_entity(),
// .metallic_texture = invalid_texture_entity(),
// .roughness_texture = invalid_texture_entity(),
// .normal_texture = invalid_texture_entity(),
//}, &scene->materials);
//quad_create((vec3s){0.0f, 0.0f, 0.0f}, (vec3s){0.0f, 1.0f, 0.0f}, (vec3s){1.0f, 0.0f, 0.0f}, 10.0f, floor_material.id, &scene->triangles);
//quad_create((vec3s){0.0f, 0.5f, 0.0f}, (vec3s){1.0f, 0.0f, 0.0f}, (vec3s){0.0f, 1.0f, 0.0f}, 1.0f, floor_material.id, &scene->triangles);
return scene_build_bvh(scene);
}
static bool initialize_renderer(const rendering_config_t* config, render_job_t** outJob, render_target_t* outImg, scene_t* outScene)
static bool initialize_renderer(const rendering_config_t* config, render_job_t** outJob, scene_t* outScene)
{
if (!scene_setup(outScene)
|| !load_assets(outScene)
|| !render_target_init(config->width, config->height, outImg))
|| !load_assets(outScene))
{
return false;
}
@@ -79,29 +81,31 @@ static bool initialize_renderer(const rendering_config_t* config, render_job_t**
*job = (render_job_t){
.scene = outScene,
.render_target = outImg,
.config = config,
.rendering_type = TILE_BASED,
.debug_flag = DEBUG_NONE,
.rendering_mode = RENDER_TILE_BASED,
.aov_flags = AOV_BEAUTY,
.is_done = false,
};
if (!renderer_aov_target_init(job, job->aov_flags))
{
return false;
}
sobol_init();
srand((unsigned int)time(NULL));
*outJob = job;
return true;
}
static void shutdown_renderer(render_job_t* job, render_target_t* img, scene_t* scene)
static void shutdown_renderer(render_job_t* job, scene_t* scene)
{
if (job != NULL)
{
free(job);
}
render_target_free(img);
render_job_free(job);
scene_free(scene);
free(job);
}
static void update_pixel_buffer(render_target_t* render_target)
@@ -125,10 +129,11 @@ static void update_pixel_buffer(render_target_t* render_target)
window_refresh_region(0, 0, render_target->width, render_target->height);
}
static int run_main_loop(render_job_t* job, render_target_t* img)
static int run_main_loop(render_job_t* job, uint8_t aov_index)
{
MSG msg;
bool running = true;
render_target_t* render_target = job->aov_target[aov_index];
while (running)
{
@@ -150,7 +155,7 @@ static int run_main_loop(render_job_t* job, render_target_t* img)
if (!job->is_done && running)
{
update_pixel_buffer(img);
update_pixel_buffer(render_target);
}
}
@@ -163,28 +168,27 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
omp_set_num_threads(16);
scene_t scene = {0};
render_target_t img = {0};
render_job_t* job = NULL;
rendering_config_t config = {
.width = 1920 / 1,
.height = 1080 / 1,
.sample_count = 16 * 4,
.width = 1920 / 2,
.height = 1080 / 2,
.sample_count = 16 * 1,
.max_depth = 4,
.bucket_size = 64,
};
if (!initialize_renderer(&config, &job, &img, &scene)
if (!initialize_renderer(&config, &job, &scene)
|| !window_create(TITLE, hInstance, config.width, config.height, job))
{
shutdown_renderer(job, &img, &scene);
shutdown_renderer(job, &scene);
return -1;
}
int result = run_main_loop(job, &img);
int result = run_main_loop(job, AOV_BEAUTY_INDEX);
window_close();
shutdown_renderer(job, &img, &scene);
shutdown_renderer(job, &scene);
return result;
}