Add HDR sky lighting support and improve rendering
Added support for HDR sky lighting, including sampling environment maps with a hierarchical CDF. Added new utility functions for handling HDR sky data, including memory management and sampling functions. Added functions to improve texture handling, including pixel data retrieval and texture coordinate management. Changed the path tracing algorithm to enhance light evaluation from HDR skies and adjust light contribution calculations. Changed BSDF sampling functions to utilize constants from Common.h for better readability. Changed the main application logic to load HDR textures and configure the scene with improved lighting settings. Refactored ray intersection logic to enhance accuracy and performance in triangle intersections. Adjusted the sample count in the rendering configuration to optimize performance. Updated the README.md to document new features and example renders.
This commit is contained in:
@@ -7,8 +7,6 @@
|
||||
#include "Rendering/Texture.h"
|
||||
#include "cglm/struct/vec3.h"
|
||||
|
||||
#define SKY_DATA_CAPACITY 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3s hit_point;
|
||||
@@ -23,21 +21,13 @@ typedef struct
|
||||
const texture_collection_t* textures;
|
||||
} light_shading_context_t;
|
||||
|
||||
#ifdef __STDC_ALIGN__
|
||||
#define SKY_ALIGN _Alignof(max_align_t)
|
||||
#else
|
||||
#define SKY_ALIGN (sizeof(void*))
|
||||
#endif
|
||||
|
||||
typedef path_output (*evaluate_bsdf_sky_f) (const void* data, const light_shading_context_t* context, vec3s throughput, uint32_t sample_index);
|
||||
typedef void (*sky_free_f) (void* data);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
_Alignas(SKY_ALIGN)
|
||||
// Should we heap allocate this? It is a bit of a waste to have it on the stack.
|
||||
char data[SKY_DATA_CAPACITY];
|
||||
uint16_t data_size;
|
||||
void* data;
|
||||
|
||||
evaluate_bsdf_sky_f evaluate_bsdf_sky;
|
||||
sky_free_f free_sky_data;
|
||||
@@ -151,6 +141,7 @@ inline void light_collection_free(light_collection_t* collection)
|
||||
{
|
||||
collection->sky_light.free_sky_data(collection->sky_light.data);
|
||||
}
|
||||
free(collection->sky_light.data);
|
||||
|
||||
collection->max_punctual_lights = 0;
|
||||
collection->max_directional_lights = 0;
|
||||
@@ -158,6 +149,7 @@ inline void light_collection_free(light_collection_t* collection)
|
||||
collection->directional_light_count = 0;
|
||||
collection->punctual_lights = NULL;
|
||||
collection->directional_lights = NULL;
|
||||
collection->sky_light.data = NULL;
|
||||
}
|
||||
|
||||
#endif // LIGHT_H
|
||||
|
||||
@@ -20,125 +20,14 @@ typedef struct
|
||||
texture_entity_t texture;
|
||||
float intensity;
|
||||
float total_weight;
|
||||
float* marginal;
|
||||
float* conditional;
|
||||
vec3s* cdf_cache; // Precomputed cache for sampling, xy for texture coordinates, z for PDF
|
||||
} hdr_sky_data_t;
|
||||
|
||||
sky_light_t sky_create_constant_sky(const constant_sky_data_t* data);
|
||||
path_output evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* context, vec3s throughput, uint32_t sample_index);
|
||||
|
||||
sky_light_t sky_create_hdr_sky(const texture_collection_t* textures, texture_entity_t hdri_entity, float intensity);
|
||||
path_output evaluate_bsdf_hdr_sky(const void* data, const light_shading_context_t* context, vec3s throughput, uint32_t sample_index);
|
||||
void hdr_sky_free(hdr_sky_data_t* data);
|
||||
|
||||
inline sky_light_t sky_create_constant_sky(const constant_sky_data_t* data)
|
||||
{
|
||||
sky_light_t light =
|
||||
{
|
||||
.data_size = sizeof(constant_sky_data_t),
|
||||
.evaluate_bsdf_sky = evaluate_bsdf_const_sky,
|
||||
};
|
||||
|
||||
memcpy_s(light.data, SKY_DATA_CAPACITY, data, sizeof(constant_sky_data_t));
|
||||
return light;
|
||||
}
|
||||
|
||||
inline sky_light_t sky_create_hdr_sky(const texture_collection_t* textures, texture_entity_t hdri_entity, float intensity)
|
||||
{
|
||||
sky_light_t light =
|
||||
{
|
||||
.data_size = sizeof(hdr_sky_data_t),
|
||||
.evaluate_bsdf_sky = evaluate_bsdf_hdr_sky,
|
||||
.free_sky_data = (sky_free_f)hdr_sky_free,
|
||||
};
|
||||
|
||||
const texture_t* hdri = get_texture(textures, hdri_entity);
|
||||
hdr_sky_data_t data =
|
||||
{
|
||||
.width = hdri->width,
|
||||
.height = hdri->height,
|
||||
.texture = hdri_entity,
|
||||
.intensity = intensity,
|
||||
};
|
||||
|
||||
float* marginal = (float*)malloc(sizeof(float) * data.width);
|
||||
float* conditional = (float*)malloc(sizeof(float) * data.width * data.height);
|
||||
float* weights = (float*)malloc(sizeof(float) * data.width * data.height);
|
||||
if (marginal == NULL || conditional == NULL || weights == NULL)
|
||||
{
|
||||
free(marginal);
|
||||
free(conditional);
|
||||
free(weights);
|
||||
return light;
|
||||
}
|
||||
|
||||
float total_weight = 0.0f;
|
||||
float max_lum = 0.0f;
|
||||
|
||||
for (uint32_t i = 0; i < data.height; i++)
|
||||
{
|
||||
// theta at row center
|
||||
float theta = ((i + 0.5f) / data.height) * (float)M_PI;
|
||||
float sin_theta = sinf(theta);
|
||||
|
||||
for (uint32_t j = 0; j < data.width; j++)
|
||||
{
|
||||
vec4s pixel = texture_sample(hdri, (float)i / (float)data.width, (float)j / (float)data.height);
|
||||
float lum = 0.2126f * pixel.x + 0.7152f * pixel.y + 0.0722f * pixel.z;
|
||||
max_lum = fmaxf(max_lum, lum);
|
||||
float weight = lum * sin_theta;
|
||||
weights[i * data.height + j] = weight;
|
||||
total_weight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
data.total_weight = total_weight;
|
||||
|
||||
float accumulate = 0.0f;
|
||||
for (uint32_t i = 0; i < data.height; i++)
|
||||
{
|
||||
float row_weight = 0.0f;
|
||||
for (uint32_t j = 0; j < data.width; j++)
|
||||
{
|
||||
row_weight += weights[i * data.height + j];
|
||||
}
|
||||
accumulate += row_weight;
|
||||
marginal[i] = accumulate / total_weight;
|
||||
}
|
||||
marginal[data.height - 1] = 1.0f;
|
||||
|
||||
for (uint32_t i = 0; i < data.height; ++i)
|
||||
{
|
||||
// total weight of this row
|
||||
float prev = (i == 0 ? 0.0f : marginal[i-1]) * total_weight;
|
||||
float rowSum = (marginal[i] * total_weight) - prev;
|
||||
|
||||
float cum = 0.0f;
|
||||
if (rowSum <= 0.0f)
|
||||
{
|
||||
// uniform fallback if row is black
|
||||
for (uint32_t j = 0; j < data.width; ++j)
|
||||
{
|
||||
cum = (float)(j+1) / data.width;
|
||||
conditional[i * data.width + j] = cum;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t j = 0; j < data.width; ++j)
|
||||
{
|
||||
cum += weights[i * data.width + j] / total_weight;
|
||||
conditional[i * data.width + j] = cum / (rowSum / total_weight);
|
||||
}
|
||||
conditional[i * data.width + (data.width - 1)] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
data.marginal = marginal;
|
||||
data.conditional = conditional;
|
||||
|
||||
free(weights);
|
||||
|
||||
memcpy_s(light.data, SKY_DATA_CAPACITY, &data, sizeof(hdr_sky_data_t));
|
||||
return light;
|
||||
}
|
||||
|
||||
#endif // SKY_LIGHT_H
|
||||
|
||||
Reference in New Issue
Block a user