Add HDR files and improve light handling
Added three binary files: `golden_gate_hills_1k.hdr`, `rogland_sunset_1k.hdr`, and `studio_small_03_1k.hdr`. Added a new inline function `weight_nee_light` in `BSDF.h` to compute the weighted contribution of light based on the next event estimation (NEE). Added a new function pointer type `sky_free_f` in `Light.h` for freeing sky light data. Added a new structure `hdr_sky_data_t` in `SkyLight.h` to hold HDR sky data, including texture and intensity. Changed the `RAY_EPSILON` definition in `Common.h` to a new value. Changed the `light_collection_free` function in `Light.h` to include freeing sky light data if it exists. Changed the `sky_create_hdr_sky` function in `SkyLight.h` to initialize HDR sky data and compute marginal and conditional distributions. Changed the `texture_load` function in `Texture.h` to accept a `stride` parameter for different texture formats. Changed the `evaluate_bsdf_directional` function in `LightEvaluation.c` to handle light intensity checks. Changed the `evaluate_bsdf_const_sky` function in `SkyLight.c` to use a pointer for sky data and added checks for intensity. Removed TODO comments related to handling triangle and material removal in `Triangle.h` and `Light.h`. Removed the old `weight_sky_light` function in `SkyLight.h` and replaced it with the new `weight_nee_light` function. Updated the `scene_setup` function in `main.c` to change camera position and light direction, and to load HDR textures. Increased the sample count in the rendering configuration in `main.c` for better quality rendering.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#define SKY_LIGHT_H
|
||||
|
||||
#include "Algorithm/BSDF.h"
|
||||
#include "Algorithm/RayIntersection.h"
|
||||
#include "Light.h"
|
||||
|
||||
#include <string.h>
|
||||
@@ -12,24 +13,131 @@ typedef struct
|
||||
float intensity;
|
||||
} constant_sky_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
texture_entity_t texture;
|
||||
float intensity;
|
||||
float total_weight;
|
||||
float* marginal;
|
||||
float* conditional;
|
||||
} hdr_sky_data_t;
|
||||
|
||||
path_output evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* context, vec3s throughput, uint32_t sample_index);
|
||||
|
||||
// Must use this function to weight the sky light contribution because of nee.
|
||||
inline vec3s weight_sky_light(vec3s bsdf, vec3s sky_light, float pdf_bsdf, float pdf_sky)
|
||||
{
|
||||
bsdf = glms_vec3_mul(bsdf, sky_light);
|
||||
float weight = power_heuristic(pdf_sky, pdf_bsdf);
|
||||
return glms_vec3_scale(bsdf, weight);
|
||||
}
|
||||
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 = {
|
||||
.evaluate_bsdf_sky = evaluate_bsdf_const_sky,
|
||||
sky_light_t light =
|
||||
{
|
||||
.data_size = sizeof(constant_sky_data_t),
|
||||
.evaluate_bsdf_sky = evaluate_bsdf_const_sky,
|
||||
};
|
||||
|
||||
memcpy(light.data, data, sizeof(constant_sky_data_t));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user