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

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