Refactor the codebase and add aov support.

This commit is contained in:
2025-12-30 01:20:41 +09:00
parent 400137ee99
commit bfd06bdd11
9 changed files with 265 additions and 122 deletions

View File

@@ -7,7 +7,9 @@
#include "Rendering/AOV.h" #include "Rendering/AOV.h"
#include "Rendering/Scene.h" #include "Rendering/Scene.h"
vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_t max_depth); // Unified AOV integrator:
void render_aov(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_t max_depth, aov_output_t* aov_output); // - If only surface AOVs are requested, executes a single-hit fast path.
// - If beauty/direct/indirect are requested, runs the full path tracer and buckets contributions.
void path_trace_aov(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_t max_depth, aov_flags_t aov_flags, aov_output_t* out);
#endif // PATH_TRACING_H #endif // PATH_TRACING_H

View File

@@ -15,6 +15,7 @@
#define PI 3.141592653589793f #define PI 3.141592653589793f
#define TWO_PI 6.283185307179586f // 2 * PI #define TWO_PI 6.283185307179586f // 2 * PI
#define HALF_PI 1.570796326794896f // PI / 2 #define HALF_PI 1.570796326794896f // PI / 2
#define QUARTER_PI 0.785398163397448f // PI / 4
#define PI_TWO 9.869604401089358f // PI^2 #define PI_TWO 9.869604401089358f // PI^2
#define INV_PI 0.318309886183790f // 1 / PI #define INV_PI 0.318309886183790f // 1 / PI
@@ -34,8 +35,8 @@ typedef struct
vec3s direct_lighting; vec3s direct_lighting;
vec3s bsdf; vec3s bsdf;
float pdf; float pdf;
path_state state;
float spread_angle; float spread_angle;
path_state state;
} path_output; } path_output;
inline float random_float() inline float random_float()

View File

@@ -31,13 +31,12 @@ typedef struct
path_output standard_lit_render_loop(const standard_lit_properties_t* properties, const shading_context_t* context); path_output standard_lit_render_loop(const standard_lit_properties_t* properties, const shading_context_t* context);
float sample_bsdf_pdf(const standard_lit_surface_data_t* surface_data, vec3s V, vec3s L); void standard_lit_render_aov(const standard_lit_properties_t* properties, const shading_context_t* context, aov_output_t* aov_output);
void standard_lit_render_aov(const shading_context_t* properties, const shading_context_t* context, aov_output_t* aov_output);
inline material_handle_t material_create_standard_lit_default(const standard_lit_properties_t* properties, material_collection_t* collection) inline material_handle_t material_create_standard_lit_default(const standard_lit_properties_t* properties, material_collection_t* collection)
{ {
return material_create(properties, sizeof(standard_lit_properties_t), (material_render_loop_f)standard_lit_render_loop, NULL, collection); return material_create(properties, sizeof(standard_lit_properties_t), (material_render_loop_f)standard_lit_render_loop, (material_render_aov_f)standard_lit_render_aov, collection);
} }
#endif // STANDARd_LIT_H #endif // STANDARd_LIT_H

View File

@@ -2,8 +2,9 @@
#define AOV_H #define AOV_H
#include "cglm/struct/vec4.h" #include "cglm/struct/vec4.h"
#include <math.h>
#define MAX_AOV_TARGET 5 #define MAX_AOV_TARGET 7
typedef enum typedef enum
@@ -13,6 +14,9 @@ typedef enum
AOV_NORMAL = 1 << 2, AOV_NORMAL = 1 << 2,
AOV_DEPTH = 1 << 3, AOV_DEPTH = 1 << 3,
AOV_POSITION = 1 << 4, AOV_POSITION = 1 << 4,
// Lighting AOVs (require integration / multiple samples)
AOV_DIRECT = 1 << 5,
AOV_INDIRECT = 1 << 6,
} aov_flags_t; } aov_flags_t;
typedef enum typedef enum
@@ -22,6 +26,8 @@ typedef enum
AOV_NORMAL_INDEX = 2, AOV_NORMAL_INDEX = 2,
AOV_DEPTH_INDEX = 3, AOV_DEPTH_INDEX = 3,
AOV_POSITION_INDEX = 4, AOV_POSITION_INDEX = 4,
AOV_DIRECT_INDEX = 5,
AOV_INDIRECT_INDEX = 6,
} aov_index_t; } aov_index_t;
typedef struct typedef struct
@@ -31,6 +37,9 @@ typedef struct
vec4s normal; vec4s normal;
vec4s position; vec4s position;
vec4s direct;
vec4s indirect;
float depth; float depth;
} aov_output_t; } aov_output_t;
@@ -40,7 +49,22 @@ inline void accumulate_aov(aov_output_t* aov, const aov_output_t* new_aov, float
aov->albedo = glms_vec4_add(aov->albedo, glms_vec4_scale(new_aov->albedo, inv_sample_count)); aov->albedo = glms_vec4_add(aov->albedo, glms_vec4_scale(new_aov->albedo, inv_sample_count));
aov->normal = glms_vec4_add(aov->normal, glms_vec4_scale(new_aov->normal, inv_sample_count)); aov->normal = glms_vec4_add(aov->normal, glms_vec4_scale(new_aov->normal, inv_sample_count));
aov->position = glms_vec4_add(aov->position, glms_vec4_scale(new_aov->position, inv_sample_count)); aov->position = glms_vec4_add(aov->position, glms_vec4_scale(new_aov->position, inv_sample_count));
aov->direct = glms_vec4_add(aov->direct, glms_vec4_scale(new_aov->direct, inv_sample_count));
aov->indirect = glms_vec4_add(aov->indirect, glms_vec4_scale(new_aov->indirect, inv_sample_count));
// Depth: keep nearest valid depth across samples; treat 0 as "unset".
if (new_aov->depth > 0.0f)
{
if (aov->depth <= 0.0f)
{
aov->depth = new_aov->depth;
}
else
{
aov->depth = fminf(aov->depth, new_aov->depth); aov->depth = fminf(aov->depth, new_aov->depth);
}
}
} }
#endif // AOV_H #endif // AOV_H

View File

@@ -3,15 +3,157 @@
#include "Lighting/LightEvaluation.h" #include "Lighting/LightEvaluation.h"
#include "Algorithm/BSDF.h" #include "Algorithm/BSDF.h"
// TODO: Split the diffuse and specular into different Monte Carlo, so we can decide the sample count for each one static inline bool aov_wants_lighting(aov_flags_t flags)
vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_t max_depth) {
return (flags & (AOV_BEAUTY | AOV_DIRECT | AOV_INDIRECT)) != 0;
}
static inline bool aov_wants_surface(aov_flags_t flags)
{
return (flags & (AOV_AlBEDO | AOV_NORMAL | AOV_DEPTH | AOV_POSITION)) != 0;
}
static inline vec4s vec4_add_rgb(vec4s base, vec3s rgb)
{
return glms_vec4_add(base, glms_vec4(rgb, 0.0f));
}
static inline void aov_init_output(aov_output_t* out)
{
*out = (aov_output_t){0};
out->beauty = (vec4s){0.0f, 0.0f, 0.0f, 1.0f};
out->direct = (vec4s){0.0f, 0.0f, 0.0f, 1.0f};
out->indirect = (vec4s){0.0f, 0.0f, 0.0f, 1.0f};
}
static inline shading_context_t make_shading_context(const scene_t* scene,
vec3s wo,
vec3s throughput,
uint32_t sample_index,
uint32_t bounce_depth,
const hit_result_t* hit,
float cone_width,
float spread_angle)
{
return (shading_context_t){
.camera_position = scene->camera.position,
.camera_direction = glms_vec3_normalize(glms_vec3_sub(hit->point, scene->camera.position)),
.position = hit->point,
.normal = hit->normal,
.tangent = hit->tangent,
.uv = hit->uv,
.wo = wo,
.throughput = throughput,
.sample_index = sample_index,
.bounce_depth = bounce_depth,
.bvh_tree = &scene->bvh_tree,
.triangles = &scene->triangles,
.lights = &scene->lights,
.textures = &scene->textures,
.triangle_id = hit->triangle_id,
.cone_width = cone_width,
.spread_angle = spread_angle,
};
}
static void trace_surface_aovs_only(const scene_t* scene,
ray_t ray,
uint32_t sample_index,
aov_flags_t aov_flags,
aov_output_t* out)
{
hit_result_t closest_hit = ray_intersect_scene_closest(&ray, scene);
if (!closest_hit.hit)
{
return;
}
const material_t* hit_material = &scene->materials.buffer[scene->triangles.buffer[closest_hit.triangle_id].material_id];
float cone_width = ray.width + closest_hit.distance * ray.spread_angle;
shading_context_t shading_context = make_shading_context(scene,
ray.direction,
glms_vec3_one(),
sample_index,
0,
&closest_hit,
cone_width,
ray.spread_angle);
render_material_aov(hit_material, &shading_context, out);
if (aov_flags & AOV_POSITION)
{
out->position = glms_vec4(closest_hit.point, 1.0f);
}
if (aov_flags & AOV_DEPTH)
{
out->depth = closest_hit.distance;
}
}
static inline void aov_accumulate_env(aov_output_t* out, aov_flags_t flags, vec3s env_contrib, uint16_t depth)
{
if (flags & AOV_BEAUTY)
{
out->beauty = vec4_add_rgb(out->beauty, env_contrib);
}
// Environment visible from camera => direct; reached after bounces => indirect.
if (depth == 0)
{
if (flags & AOV_DIRECT)
{
out->direct = vec4_add_rgb(out->direct, env_contrib);
}
}
else
{
if (flags & AOV_INDIRECT)
{
out->indirect = vec4_add_rgb(out->indirect, env_contrib);
}
}
}
static inline void aov_accumulate_nee(aov_output_t* out, aov_flags_t flags, vec3s L, uint16_t depth)
{
// Next-event estimation at camera-visible vertex => direct.
// NEE at later vertices is reached via bounces => indirect.
if (depth == 0)
{
if (flags & AOV_DIRECT)
{
out->direct = vec4_add_rgb(out->direct, L);
}
}
else
{
if (flags & AOV_INDIRECT)
{
out->indirect = vec4_add_rgb(out->indirect, L);
}
}
if (flags & AOV_BEAUTY)
{
out->beauty = vec4_add_rgb(out->beauty, L);
}
}
static void trace_lighting_aovs(const scene_t* scene,
ray_t ray,
uint32_t sample_index,
uint16_t max_depth,
aov_flags_t aov_flags,
aov_output_t* out)
{ {
vec4s accumulated_color = (vec4s){0.0f, 0.0f, 0.0f, 1.0f};
vec3s throughput = glms_vec3_one(); vec3s throughput = glms_vec3_one();
ray_t active_ray = ray; ray_t active_ray = ray;
// PDF of the direction that generated the current ray segment (used for MIS on env hits).
float last_bsdf_pdf = 0.0f; float last_bsdf_pdf = 0.0f;
uint16_t depth = 0; uint16_t depth = 0;
@@ -21,7 +163,6 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
if (!closest_hit.hit) if (!closest_hit.hit)
{ {
// Set bvh to null indicate that the ray is not hit anything
light_shading_context_t light_context = light_shading_context_t light_context =
{ {
.wo = active_ray.direction, .wo = active_ray.direction,
@@ -30,7 +171,6 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
}; };
path_output sky_output = evaluate_bsdf_sky(&scene->lights, &light_context, throughput, sample_index); path_output sky_output = evaluate_bsdf_sky(&scene->lights, &light_context, throughput, sample_index);
// MIS for BSDF-sampled environment hit (for depth==0 camera ray, use weight 1).
float w = 1.0f; float w = 1.0f;
if (depth > 0) if (depth > 0)
{ {
@@ -43,52 +183,48 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
} }
vec3s env_contrib = glms_vec3_scale(sky_output.direct_lighting, w); vec3s env_contrib = glms_vec3_scale(sky_output.direct_lighting, w);
accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(env_contrib, 0.0f)); aov_accumulate_env(out, aov_flags, env_contrib, depth);
break; break;
} }
uint8_t material_id = scene->triangles.buffer[closest_hit.triangle_id].material_id; uint8_t material_id = scene->triangles.buffer[closest_hit.triangle_id].material_id;
const material_t* hit_material = &scene->materials.buffer[material_id]; const material_t* hit_material = &scene->materials.buffer[material_id];
// Calculate ray cone width at the hit point
float current_cone_width = active_ray.width + closest_hit.distance * active_ray.spread_angle; float current_cone_width = active_ray.width + closest_hit.distance * active_ray.spread_angle;
shading_context_t shading_context = make_shading_context(scene,
active_ray.direction,
throughput,
sample_index,
depth,
&closest_hit,
current_cone_width,
active_ray.spread_angle);
shading_context_t shading_context = // First-hit surface AOVs are still cheap; record them if requested.
if (depth == 0 && aov_wants_surface(aov_flags))
{ {
.camera_position = scene->camera.position, render_material_aov(hit_material, &shading_context, out);
.camera_direction = glms_vec3_normalize(glms_vec3_sub(closest_hit.point, scene->camera.position)), if (aov_flags & AOV_POSITION)
{
.position = closest_hit.point, out->position = glms_vec4(closest_hit.point, 1.0f);
.normal = closest_hit.normal, }
.tangent = closest_hit.tangent, if (aov_flags & AOV_DEPTH)
.uv = closest_hit.uv, {
.wo = active_ray.direction, out->depth = closest_hit.distance;
.throughput = throughput, }
}
.sample_index = sample_index,
.bounce_depth = depth,
.bvh_tree = &scene->bvh_tree,
.triangles = &scene->triangles,
.lights = &scene->lights,
.textures = &scene->textures,
.triangle_id = closest_hit.triangle_id,
.cone_width = current_cone_width,
.spread_angle = active_ray.spread_angle,
};
path_output material_output = render_material(hit_material, &shading_context); path_output material_output = render_material(hit_material, &shading_context);
if (glms_vec3_isinf(material_output.direct_lighting) || glms_vec3_isnan(material_output.direct_lighting)) if (glms_vec3_isinf(material_output.direct_lighting) || glms_vec3_isnan(material_output.direct_lighting))
{ {
goto end_path_trace; break;
} }
accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(material_output.direct_lighting, 0.0f)); aov_accumulate_nee(out, aov_flags, material_output.direct_lighting, depth);
if (material_output.pdf < FLT_EPSILON) if (material_output.pdf < FLT_EPSILON)
{ {
goto end_path_trace; break;
} }
last_bsdf_pdf = material_output.pdf; last_bsdf_pdf = material_output.pdf;
@@ -96,78 +232,52 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
throughput = glms_vec3_mul(throughput, material_output.bsdf); throughput = glms_vec3_mul(throughput, material_output.bsdf);
if (glms_vec3_isinf(throughput) || glms_vec3_isnan(throughput)) if (glms_vec3_isinf(throughput) || glms_vec3_isnan(throughput))
{ {
goto end_path_trace; break;
} }
// We do Russian roulette to decide whether to continue tracing or terminate the path
if (depth > 1) if (depth > 1)
{ {
float q = fminf(glms_vec3_max(throughput), 0.95f); float q = fminf(glms_vec3_max(throughput), 0.95f);
float rr = sobol_sample(sample_index, sobol_get_dimension(depth, PRNG_TERMINATE)); float rr = sobol_sample(sample_index, sobol_get_dimension(depth, PRNG_TERMINATE));
if (rr > q) if (rr > q)
{ {
goto end_path_trace; break;
} }
// Keep the energy of the path by scaling the throughput
throughput = glms_vec3_scale(throughput, 1.0f / q); throughput = glms_vec3_scale(throughput, 1.0f / q);
} }
switch (material_output.state) if (material_output.state != PS_SUCCESS)
{ {
//case PATH_THROUGH: break;
// active_ray = ray_create(BIAS_RAY_ORIGION(closest_hit.point, glms_vec3_negate(closest_hit.normal)), active_ray.direction); }
// continue;
case PS_SUCCESS:
vec3s origin = offset_ray_origin(closest_hit.point, closest_hit.normal, shading_context.wo); vec3s origin = offset_ray_origin(closest_hit.point, closest_hit.normal, shading_context.wo);
active_ray = ray_create(origin, material_output.wi, current_cone_width, material_output.spread_angle); active_ray = ray_create(origin, material_output.wi, current_cone_width, material_output.spread_angle);
depth++; depth++;
break;
default:
goto end_path_trace;
} }
}
end_path_trace:
return accumulated_color;
} }
// How to handle multi-bounced aov like indirect lighting? void path_trace_aov(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_t max_depth, aov_flags_t aov_flags, aov_output_t* out)
// 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_closest(&ray, scene); if (out == NULL)
if (!closest_hit.hit)
{ {
return; return;
} }
const material_t* hit_material = &scene->materials.buffer[scene->triangles.buffer[closest_hit.triangle_id].material_id]; aov_init_output(out);
shading_context_t shading_context =
// Fast path: surface-only AOVs (single intersection + material aov evaluation).
if (!aov_wants_lighting(aov_flags))
{ {
.camera_position = scene->camera.position, if (!aov_wants_surface(aov_flags))
.camera_direction = glms_vec3_normalize(glms_vec3_sub(closest_hit.point, scene->camera.position)), {
return;
}
.position = closest_hit.point, trace_surface_aovs_only(scene, ray, sample_index, aov_flags, out);
.normal = closest_hit.normal, return;
.tangent = closest_hit.tangent, }
.uv = closest_hit.uv,
.wo = ray.direction,
.throughput = 1.0f,
.sample_index = sample_index, trace_lighting_aovs(scene, ray, sample_index, max_depth, aov_flags, out);
.bounce_depth = 0,
.bvh_tree = &scene->bvh_tree,
.triangles = &scene->triangles,
.lights = &scene->lights,
.textures = &scene->textures,
.triangle_id = closest_hit.triangle_id,
.cone_width = ray.width + closest_hit.distance * ray.spread_angle,
.spread_angle = ray.spread_angle,
};
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

@@ -129,7 +129,6 @@ static float oren_nayar_eval(vec3s l, vec3s v, vec3s n, float roughness, float n
static void get_surface_data(const shading_context_t* context, const standard_lit_properties_t* properties, standard_lit_surface_data_t* data_out) static void get_surface_data(const shading_context_t* context, const standard_lit_properties_t* properties, standard_lit_surface_data_t* data_out)
{ {
// Use the ray cone width (footprint) instead of simple distance for mip selection // Use the ray cone width (footprint) instead of simple distance for mip selection
float footprint = context->cone_width;
float distance = glms_vec3_distance(context->camera_position, context->position); float distance = glms_vec3_distance(context->camera_position, context->position);
vec3s view = context->camera_direction; vec3s view = context->camera_direction;
@@ -143,7 +142,7 @@ static void get_surface_data(const shading_context_t* context, const standard_li
.edge2 = glms_vec3_sub(triangle->vertices[2].position, triangle->vertices[0].position), .edge2 = glms_vec3_sub(triangle->vertices[2].position, triangle->vertices[0].position),
.uv1 = glms_vec2_sub(triangle->vertices[1].uv, triangle->vertices[0].uv), .uv1 = glms_vec2_sub(triangle->vertices[1].uv, triangle->vertices[0].uv),
.uv2 = glms_vec2_sub(triangle->vertices[2].uv, triangle->vertices[0].uv), .uv2 = glms_vec2_sub(triangle->vertices[2].uv, triangle->vertices[0].uv),
.ray_width = footprint, .ray_width = context->cone_width,
.distance = distance .distance = distance
}; };
@@ -410,7 +409,7 @@ path_output standard_lit_render_loop(const standard_lit_properties_t* properties
// Propagate spread angle for ray cones // Propagate spread angle for ray cones
// Heuristic: spread increases with roughness // Heuristic: spread increases with roughness
output.spread_angle = context->spread_angle + surface_data.roughness * 0.2f; output.spread_angle = context->spread_angle + surface_data.roughness * QUARTER_PI;
} }
else else
{ {
@@ -453,3 +452,19 @@ path_output standard_lit_render_loop(const standard_lit_properties_t* properties
output.state = PS_SUCCESS; output.state = PS_SUCCESS;
return output; return output;
} }
void standard_lit_render_aov(const standard_lit_properties_t* properties, const shading_context_t* context, aov_output_t* aov_output)
{
standard_lit_surface_data_t surface_data; // Assuming you reuse your struct
get_surface_data(context, properties, &surface_data);
// Keep shading normal in the same hemisphere as the geometric normal to avoid invalid transport.
if (glms_vec3_dot(surface_data.normal, context->normal) < 0.0f)
{
surface_data.normal = glms_vec3_negate(surface_data.normal);
}
aov_output->albedo = glms_vec4(surface_data.albedo, 1.0f);
vec3s n_ws = glms_vec3_normalize(surface_data.normal);
aov_output->normal = (vec4s){n_ws.x * 0.5f + 0.5f, n_ws.y * 0.5f + 0.5f, n_ws.z * 0.5f + 0.5f, 1.0f};
}

View File

@@ -32,6 +32,9 @@ bool renderer_aov_target_init(render_job_t* job, aov_flags_t aov_flags)
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_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); create_target_if_required(aov_flags, AOV_POSITION, &job->aov_target[AOV_POSITION_INDEX], job->config->width, job->config->height);
create_target_if_required(aov_flags, AOV_DIRECT, &job->aov_target[AOV_DIRECT_INDEX], job->config->width, job->config->height);
create_target_if_required(aov_flags, AOV_INDIRECT, &job->aov_target[AOV_INDIRECT_INDEX], job->config->width, job->config->height);
return true; return true;
} }
@@ -57,15 +60,9 @@ 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, aov_index_t index) static inline bool aov_needs_lighting_samples(aov_flags_t flags)
{ {
switch (index) return has_flag(flags, AOV_BEAUTY) || has_flag(flags, AOV_DIRECT) || has_flag(flags, AOV_INDIRECT);
{
case AOV_BEAUTY_INDEX:
return sample_count;
default:
return 1;
}
} }
static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s coord, uint32_t x, uint32_t y, aov_flags_t aov_flags, aov_output_t* pixel_output) static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s coord, uint32_t x, uint32_t y, aov_flags_t aov_flags, aov_output_t* pixel_output)
@@ -73,7 +70,7 @@ static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s
aov_output_t accumulated_color = {0}; aov_output_t accumulated_color = {0};
uint32_t pixel_id = y * config->width + x; uint32_t pixel_id = y * config->width + x;
uint16_t sample_count = config->sample_count; uint16_t sample_count = aov_needs_lighting_samples(aov_flags) ? (uint16_t)config->sample_count : 1;
float inv_sample = 1.0f / (float)sample_count; float inv_sample = 1.0f / (float)sample_count;
vec3s camera_right = quat_get_right(scene->camera.rotation); vec3s camera_right = quat_get_right(scene->camera.rotation);
@@ -82,7 +79,7 @@ static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s
for (uint16_t k = 0; k < sample_count; k++) for (uint16_t k = 0; k < sample_count; k++)
{ {
// TODO: Hash it // TODO: Hash it
uint32_t sobol_idx = pixel_id * config->sample_count + (k + 1); uint32_t sobol_idx = pixel_id * (uint32_t)sample_count + (k + 1);
// Apply AA // Apply AA
float du = sobol_sample(sobol_idx, PRNG_FILTER_U); float du = sobol_sample(sobol_idx, PRNG_FILTER_U);
@@ -105,15 +102,7 @@ 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)), 0.0f, spread_angle); ray_t ray = ray_create(scene->camera.position, glms_vec3_normalize(glms_vec3_sub(image_plane_point, scene->camera.position)), 0.0f, spread_angle);
aov_output_t aov_output = {0}; aov_output_t aov_output = {0};
if (has_flag(aov_flags, AOV_BEAUTY)) path_trace_aov(scene, ray, sobol_idx, config->max_depth, aov_flags, &aov_output);
{
aov_output.beauty = path_trace(scene, ray, sobol_idx, config->max_depth);
}
if (aov_flags != AOV_BEAUTY)
{
render_aov(scene, ray, sobol_idx, config->max_depth, &aov_output);
}
accumulate_aov(&accumulated_color, &aov_output, inv_sample); accumulate_aov(&accumulated_color, &aov_output, inv_sample);
} }
@@ -138,6 +127,9 @@ static inline void update_aov(render_target_t** target, const aov_output_t* aov,
update_aov_pixel_if_exist(&target[AOV_NORMAL_INDEX], aov->normal, 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_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); update_aov_pixel_if_exist(&target[AOV_POSITION_INDEX], aov->position, x, y);
update_aov_pixel_if_exist(&target[AOV_DIRECT_INDEX], aov->direct, x, y);
update_aov_pixel_if_exist(&target[AOV_INDIRECT_INDEX], aov->indirect, x, y);
} }
// TODO: Progressive rendering // TODO: Progressive rendering

View File

@@ -419,7 +419,7 @@ float texture_get_sample_lod(const texture_t* texture, const texture_sample_cont
// 4. Convert to LOD // 4. Convert to LOD
// LOD 0 = 1 texel. LOD 1 = 2 texels. LOD 2 = 4 texels. // LOD 0 = 1 texel. LOD 1 = 2 texels. LOD 2 = 4 texels.
// log2(texels_covered) gives the mip level. // log2(texels_covered) gives the mip level.
return log2f(texels_covered); return log2f(texels_covered) * 0.5f;
} }
static vec4s nearest_filter(const texture_t* texture, vec2s uv, uint8_t lod) static vec4s nearest_filter(const texture_t* texture, vec2s uv, uint8_t lod)

View File

@@ -85,7 +85,7 @@ static bool load_assets(scene_t* scene)
return scene_build_bvh(scene); return scene_build_bvh(scene);
} }
static bool initialize_renderer(const rendering_config_t* config, render_job_t** outJob, scene_t* outScene) static bool initialize_renderer(const rendering_config_t* config, aov_flags_t aov_flags, render_job_t** outJob, scene_t* outScene)
{ {
if (!scene_setup(outScene) if (!scene_setup(outScene)
|| !load_assets(outScene)) || !load_assets(outScene))
@@ -104,7 +104,7 @@ static bool initialize_renderer(const rendering_config_t* config, render_job_t**
.config = config, .config = config,
.rendering_mode = RENDER_TILE_BASED, .rendering_mode = RENDER_TILE_BASED,
.aov_flags = AOV_BEAUTY, .aov_flags = aov_flags,
.is_done = false, .is_done = false,
}; };
@@ -141,7 +141,7 @@ static void update_pixel_buffer(render_target_t* render_target)
{ {
vec4s pixel = render_target_get_pixel(render_target, x, y); vec4s pixel = render_target_get_pixel(render_target, x, y);
pixel = gamma_correct(pixel, 2.2f); pixel = gamma_correct(pixel, 2.2f);
pixel = aces_tone_map(pixel); //pixel = aces_tone_map(pixel);
window_update_pixel(pixel, x, y); window_update_pixel(pixel, x, y);
} }
} }
@@ -198,14 +198,14 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
.bucket_size = 64, .bucket_size = 64,
}; };
if (!initialize_renderer(&config, &job, &scene) if (!initialize_renderer(&config, AOV_INDIRECT, &job, &scene)
|| !window_create(TITLE, hInstance, config.width, config.height, job)) || !window_create(TITLE, hInstance, config.width, config.height, job))
{ {
shutdown_renderer(job, &scene); shutdown_renderer(job, &scene);
return -1; return -1;
} }
int result = run_main_loop(job, AOV_BEAUTY_INDEX); int result = run_main_loop(job, AOV_INDIRECT_INDEX);
window_close(); window_close();
shutdown_renderer(job, &scene); shutdown_renderer(job, &scene);