Update AOV support, ray intersection logic, and README

Added:
- AOV support for normals, albedo, and depth marked as completed.
- New function `normal_unpack` in `BSDF.h`.
- New field `esp` in `ray_t` structure in `RayIntersection.h`.

Changed:
- Updated `normal_ts_to_ws` to accept an additional parameter.
- Refactored `weight_nee_light` for clarity.
- Modified `RAY_EPSILON` for improved precision.
- Updated `path_output` structure to include a `normal` field.
- Normalized unpacked normal vector in `normal_unpack` function.
- Updated `path_trace` to use closest hit ray intersection.
- Updated `render_aov` to utilize closest hit logic.
- Modified `ray_create` to initialize `esp` based on ray origin.
- Improved accuracy in `offset_ray_origin` calculations.
- Updated ray intersection logic in `ray_intersect_triangle` and `ray_intersect_aabb` to include epsilon checks.
- Updated `evaluate_bsdf_directional` and `evaluate_bsdf_const_sky` for shadow rays.
- Adjusted `sample_bsdf_simple_lit` for incoming light direction calculations.
- Enhanced `render_pixel` to manage AOV flags effectively.
- Changed camera rotation and light intensity in `scene_setup`.
- Simplified texture loading by removing unnecessary sRGB conversion.

Modified:
- Several binary image files have been updated.
This commit is contained in:
2025-05-05 01:59:13 +09:00
parent 4b29de15cd
commit f940569ca3
21 changed files with 190 additions and 85 deletions

View File

@@ -34,20 +34,26 @@ vec3s normal_unpack(vec3s normal)
float dot_xy = glm_clamp_zo(unpacked_normal.x * unpacked_normal.x + unpacked_normal.y * unpacked_normal.y);
unpacked_normal.z = fmaxf(FLT_MIN, sqrtf(1.0f - dot_xy));
return unpacked_normal;
return glms_vec3_normalize(unpacked_normal);
}
vec3s normal_ts_to_ws(vec3s normal, vec3s tangent)
vec3s normal_ts_to_ws(vec3s normal, vec3s geo_normal, vec3s tangent)
{
vec3s t = glms_vec3_normalize(tangent);
vec3s b = glms_vec3_cross(normal, t);
tangent = glms_vec3_normalize(tangent);
vec3s bitangent = glms_vec3_cross(geo_normal, tangent);
float w = (glms_vec3_dot(glms_vec3_cross(geo_normal, tangent), bitangent) < 0.0f) ? -1.0f : +1.0f;
float proj = glms_vec3_dot(geo_normal, tangent);
vec3s t_prime = glms_vec3_normalize(glms_vec3_sub(tangent, glms_vec3_scale(geo_normal, proj)));
vec3s b_prime = glms_vec3_scale(glms_vec3_cross(geo_normal, t_prime), w);
// Matrix in cglm is column-major, not row-major
mat3s tbn =
{
t.x, b.x, normal.x,
t.y, b.y, normal.y,
t.z, b.z, normal.z
t_prime.x, t_prime.y, t_prime.z,
b_prime.x, b_prime.y, b_prime.z,
geo_normal.x, geo_normal.y, geo_normal.z
};
return glms_vec3_normalize(glms_mat3_mulv(tbn, normal));
@@ -242,3 +248,12 @@ vec3s random_uniform_cdf_direction_angular(vec3s direction, uint32_t index, floa
vec3s world_dir = glms_vec3_add(glms_vec3_add(term_u, term_v), term_w);
return world_dir;
}
// Must use this function to weight any nee light contribution before accumulate.
vec3s weight_nee_light(vec3s bsdf, vec3s light, float pdf_bsdf, float pdf_sky)
{
light = glms_vec3_mul(bsdf, light);
float weight = power_heuristic(pdf_sky, pdf_bsdf);
return glms_vec3_scale(light, weight);
}

View File

@@ -14,7 +14,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
uint16_t depth = 0;
while (depth < max_depth)
{
hit_result_t closest_hit = ray_intersect_scene(&active_ray, scene);
hit_result_t closest_hit = ray_intersect_scene_closest(&active_ray, scene);
if (!closest_hit.hit)
{
@@ -76,7 +76,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
// active_ray = ray_create(BIAS_RAY_ORIGION(closest_hit.point, glms_vec3_negate(closest_hit.normal)), active_ray.direction);
// continue;
default:
active_ray = ray_create(BIAS_RAY_ORIGION(closest_hit.point, closest_hit.normal), material_output.wi);
active_ray = ray_create(offset_ray_origin(closest_hit.point, material_output.normal, shading_context.wo), material_output.wi);
depth++;
break;
}
@@ -90,7 +90,7 @@ end_path_trace:
// 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);
hit_result_t closest_hit = ray_intersect_scene_closest(&ray, scene);
if (!closest_hit.hit)
{
return;

View File

@@ -5,7 +5,7 @@
ray_t ray_create(vec3s origin, vec3s direction)
{
return (ray_t)
ray_t ray =
{
.origin = origin,
.direction = direction,
@@ -15,6 +15,9 @@ ray_t ray_create(vec3s origin, vec3s direction)
((direction.y < 0.0f) ? 2 : 0) |
((direction.z < 0.0f) ? 4 : 0)
};
ray.esp = glms_vec3_max(glms_vec3_abs(ray.origin)) * gamma(10);
return ray;
}
static inline float next_float_up(float value)
@@ -40,11 +43,11 @@ static inline float next_float_down(float value)
vec3s offset_ray_origin(vec3s point, vec3s normal, vec3s wo)
{
vec3s abs_normal = glms_vec3_abs(normal);
float c = glms_vec3_max(point) * gamma(3);
float c = glms_vec3_max(glms_vec3_abs(point)) * gamma(10);
float d = glms_vec3_dot(abs_normal, (vec3s){c, c, c});
vec3s offset = glms_vec3_scale(abs_normal, d);
if (glms_vec3_dot(wo, normal) < 0.0f)
vec3s offset = glms_vec3_scale(normal, d);
if (glms_vec3_dot(glms_vec3_negate(wo), normal) < 0.0f)
{
offset = glms_vec3_negate(offset);
}
@@ -107,7 +110,7 @@ hit_result_t ray_intersect_triangle(const ray_t* ray, const triangle_t* triangle
// Distance along the ray
float t = glms_vec3_dot(e2, Q) * invDet;
if (t < RAY_EPSILON)
if (t <= ray->esp)
{
return result;
}
@@ -169,13 +172,15 @@ bool ray_intersect_aabb(const ray_t* ray, aabb_t aabb, float* enter_out, float*
}
// update entry/exit
if (enter_out != NULL)
if (enter_out != NULL && exit_out != NULL)
{
*enter_out = t0 > tz_min ? t0 : tz_min;
}
if (exit_out != NULL)
{
*exit_out = t1 < tz_max ? t1 : tz_max;
if (fmaxf(*enter_out, ray->esp) > *exit_out)
{
return false;
}
}
return true;
@@ -190,8 +195,8 @@ static inline float distance_to_aabb(vec3s point, aabb_t aabb)
}
// TODO: Use a stack to avoid recursion.
void ray_intersect_bvh(const ray_t* ray, const bvh_node_t* bvh_nodes, const uint64_t* primitive_indices, const triangle_collection_t* all_triangles, uint64_t node_index, float* closest_out,
hit_result_t* best_hit_out)
void ray_intersect_bvh_closest(const ray_t* ray, const bvh_node_t* bvh_nodes, const uint64_t* primitive_indices, const triangle_collection_t* all_triangles, uint64_t node_index,
float* closest_out, hit_result_t* best_hit_out)
{
const bvh_node_t* node = &bvh_nodes[node_index];
@@ -238,33 +243,102 @@ void ray_intersect_bvh(const ray_t* ray, const bvh_node_t* bvh_nodes, const uint
{
if (left_enter < right_enter)
{
ray_intersect_bvh(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, closest_out, best_hit_out);
ray_intersect_bvh_closest(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, closest_out, best_hit_out);
if (right_enter < *closest_out)
{
ray_intersect_bvh(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, closest_out, best_hit_out);
ray_intersect_bvh_closest(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, closest_out, best_hit_out);
}
}
else
{
ray_intersect_bvh(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, closest_out, best_hit_out);
ray_intersect_bvh_closest(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, closest_out, best_hit_out);
if (left_enter < *closest_out)
{
ray_intersect_bvh(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, closest_out, best_hit_out);
ray_intersect_bvh_closest(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, closest_out, best_hit_out);
}
}
}
else if (hit_left_aabb)
{
ray_intersect_bvh(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, closest_out, best_hit_out);
ray_intersect_bvh_closest(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, closest_out, best_hit_out);
}
else if (hit_right_aabb)
{
ray_intersect_bvh(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, closest_out, best_hit_out);
ray_intersect_bvh_closest(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, closest_out, best_hit_out);
}
}
}
hit_result_t ray_intersect_scene(const ray_t* ray, const scene_t* scene)
void ray_intersect_bvh_any(const ray_t* ray, const bvh_node_t* bvh_nodes, const uint64_t* primitive_indices, const triangle_collection_t* all_triangles, uint64_t node_index, hit_result_t* any_hit_out)
{
const bvh_node_t* node = &bvh_nodes[node_index];
float enter, exit;
if (!ray_intersect_aabb(ray, node->bounds, &enter, &exit))
{
return;
}
// If primitive_count > 0 implies leaf:
if (node->primitive_count > 0)
{
for (uint32_t i = 0; i < node->primitive_count; i++)
{
uint64_t triangle_index = primitive_indices[node->start_index + i];
hit_result_t hit_result = ray_intersect_triangle(ray, &all_triangles->buffer[triangle_index]);
if (hit_result.hit)
{
*any_hit_out = hit_result;
any_hit_out->triangle_id = triangle_index;
return;
}
}
}
else
{
// Internal node: traverse children in nearfirst order
uint64_t left_child_index = node->left_child_offset;
uint64_t right_child_index = node->right_child_offset;
const bvh_node_t* left_child = &bvh_nodes[left_child_index];
const bvh_node_t* right_child = &bvh_nodes[right_child_index];
float left_enter, left_exit, right_enter, right_exit;
bool hit_left_aabb = ray_intersect_aabb(ray, left_child->bounds, &left_enter, &left_exit);
bool hit_right_aabb = ray_intersect_aabb(ray, right_child->bounds, &right_enter, &right_exit);
if (hit_left_aabb && hit_right_aabb)
{
if (left_enter < right_enter)
{
ray_intersect_bvh_any(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, any_hit_out);
if (!any_hit_out->hit)
{
ray_intersect_bvh_any(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, any_hit_out);
}
}
else
{
ray_intersect_bvh_any(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, any_hit_out);
if (!any_hit_out->hit)
{
ray_intersect_bvh_any(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, any_hit_out);
}
}
}
else if (hit_left_aabb)
{
ray_intersect_bvh_any(ray, bvh_nodes, primitive_indices, all_triangles, node->left_child_offset, any_hit_out);
}
else if (hit_right_aabb)
{
ray_intersect_bvh_any(ray, bvh_nodes, primitive_indices, all_triangles, node->right_child_offset, any_hit_out);
}
}
}
hit_result_t ray_intersect_scene_closest(const ray_t* ray, const scene_t* scene)
{
hit_result_t result = {0};
float closest = FLT_MAX;
@@ -273,7 +347,20 @@ hit_result_t ray_intersect_scene(const ray_t* ray, const scene_t* scene)
{
return result;
}
ray_intersect_bvh(ray, scene->bvh_tree.nodes, scene->bvh_tree.primitive_indices, &scene->triangles, 0, &closest, &result);
ray_intersect_bvh_closest(ray, scene->bvh_tree.nodes, scene->bvh_tree.primitive_indices, &scene->triangles, 0, &closest, &result);
return result;
}
hit_result_t ray_intersect_scene_any(const ray_t* ray, const scene_t* scene)
{
hit_result_t result = {0};
result.distance = FLT_MAX;
if (scene == NULL || scene->bvh_tree.nodes == NULL || scene->triangles.count == 0 || scene->bvh_tree.node_count == 0 || scene->bvh_tree.primitive_count == 0)
{
return result;
}
ray_intersect_bvh_any(ray, scene->bvh_tree.nodes, scene->bvh_tree.primitive_indices, &scene->triangles, 0, &result);
return result;
}

View File

@@ -26,12 +26,11 @@ path_output evaluate_bsdf_directional(directional_light_t light, const light_sha
return output;
}
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->position, context->normal), wi);
ray_t shadow_ray = ray_create(offset_ray_origin(context->position, context->normal, context->wo), wi);
float closest = FLT_MAX;
hit_result_t shadow_hit = {1};
ray_intersect_bvh(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0,
&closest, &shadow_hit);
hit_result_t shadow_hit = {0};
ray_intersect_bvh_any(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0, &shadow_hit);
if (shadow_hit.hit)
{
return output;

View File

@@ -47,11 +47,10 @@ 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->position, context->normal), wi);
ray_t shadow_ray = ray_create(offset_ray_origin(context->position, context->normal, context->wo), wi);
float closest = FLT_MAX;
hit_result_t shadow_hit = {1};
ray_intersect_bvh(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0, &closest, &shadow_hit);
hit_result_t shadow_hit = {0};
ray_intersect_bvh_any(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0, &shadow_hit);
if (shadow_hit.hit)
{
return output;
@@ -305,8 +304,15 @@ path_output evaluate_bsdf_hdr_sky(const void* data, const light_shading_context_
}
uint32_t i,j;
// 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);
// Should we also use sobol numbers for the sky sampling?
//uint16_t d1 = sobol_get_dimension(context->bounce_depth, PRNG_LIGHT_U);
//uint16_t d2 = sobol_get_dimension(context->bounce_depth, PRNG_LIGHT_V);
//float r1 = sobol_sample(sample_index, d1);
//float r2 = sobol_sample(sample_index, d2);
float r1 = random_float();
float r2 = random_float();
uv_to_index((vec2s){r1, r2}, sky_data->width, sky_data->height, &j, &i);
vec3s cdf = sky_data->cdf_cache[i * sky_data->width + j];
vec3s wi = equirectangular_to_direction(cdf.x,-cdf.y);
@@ -316,11 +322,10 @@ 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->position, context->normal), wi);
ray_t shadow_ray = ray_create(offset_ray_origin(context->position, context->normal, context->wo), wi);
float closest = FLT_MAX;
hit_result_t shadow_hit = {1};
ray_intersect_bvh(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0, &closest, &shadow_hit);
hit_result_t shadow_hit = {0};
ray_intersect_bvh_any(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0, &shadow_hit);
if (shadow_hit.hit)
{
return output;

View File

@@ -19,13 +19,15 @@ static void get_surface_data(const shading_context_t* context, const void* prope
data_out->albedo = glms_vec3_mul(data_out->albedo, glms_vec3(texture_sample(albedo_texture, context->uv.x, context->uv.y)));
}
// NOTE: Currently normal map will produce lots of fireflies, need to be fixed.
// Not sure is it because of the quality of the normal map or the algorithm itself.
data_out->normal = context->normal;
const texture_t* normal_texture = get_texture(context->textures, prop->normal_texture);
if (normal_texture != NULL && normal_texture->data != NULL)
{
vec3s normal_sample = glms_vec3(texture_sample(normal_texture, context->uv.x, context->uv.y));
normal_sample = normal_unpack(normal_sample);
data_out->normal = glms_vec3_add(data_out->normal, normal_ts_to_ws(normal_sample, context->tangent));
data_out->normal = normal_ts_to_ws(normal_sample, context->normal, context->tangent);
}
data_out->roughness = prop->roughness;
@@ -54,6 +56,7 @@ static vec3s sample_bsdf_simple_lit(const shading_context_t* context, const surf
vec3s f = fresnel_schlick_vec3(f0, cos_theta_0);
float lum_f = (f.x + f.y + f.z) / 3.0f;
//float prob_specular = 0.0f;
float prob_specular = glm_lerp(lum_f, 1.0f, surface_data->metallic);
float prob_diffuse = (1.0f - surface_data->metallic) * (1.0f - lum_f); // Diffuse only for non-metals, reduced by reflection
float total_prob = prob_diffuse + prob_specular;
@@ -110,8 +113,8 @@ static vec3s sample_bsdf_simple_lit(const shading_context_t* context, const surf
h_ws = glms_vec3_add(h_ws, scaled_n);
h_ws = glms_vec3_normalize(h_ws);
// wi is simple now, just reflect wo around normal
wi = glms_vec3_reflect(glms_vec3_negate(L), h_ws);
// wi is simple now, just reflect L around normal
wi = glms_vec3_reflect(L, h_ws);
}
// Final check to ensure wi is in the correct hemisphere
@@ -139,7 +142,7 @@ static float sample_bsdf_pdf_simple_lit(const shading_context_t* context, const
vec3s L = glms_vec3_negate(context->wo);
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, surface_data->albedo, surface_data->metallic);
float cos_theta_o = fmaxf(glms_vec3_dot(context->normal, L), 0.0f); // Use 'o' for outgoing (wo)
float cos_theta_o = fmaxf(glms_vec3_dot(surface_data->normal, L), 0.0f); // Use 'o' for outgoing (wo)
float F = glms_vec3_max(fresnel_schlick_vec3(f0, cos_theta_o));
float prob_specular = glm_lerp(F, 1.0f, surface_data->metallic);
@@ -153,11 +156,10 @@ static float sample_bsdf_pdf_simple_lit(const shading_context_t* context, const
prob_diffuse /= total_prob;
prob_specular /= total_prob;
float pdf_diff = pdf_cosine_weighted_hemisphere(context->normal, wi);
float pdf_diff = pdf_cosine_weighted_hemisphere(surface_data->normal, wi);
float diffuse_pdf_component = prob_diffuse * pdf_diff;
// When computing specular PDF, L is the wi and wi is the view direction
float pdf_spec = pdf_blinn_phong_lobe(context->normal, L, wi, surface_data->roughness);
float pdf_spec = pdf_blinn_phong_lobe(surface_data->normal, wi, L, surface_data->roughness);
float specular_pdf_component = prob_specular * pdf_spec;
return diffuse_pdf_component + specular_pdf_component;
@@ -231,7 +233,8 @@ path_output simple_lit_render_loop(const shading_context_t* properties, const sh
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);
float pdf_bsdf = sample_bsdf_pdf_simple_lit(context, &surface_data, light_output.wi);
vec3s light_contribute = weight_nee_light(bsdf_dir_light, light_output.direct_lighting, pdf_bsdf, light_output.pdf);
output.direct_lighting = glms_vec3_add(output.direct_lighting, light_contribute);
}
}
@@ -254,8 +257,9 @@ path_output simple_lit_render_loop(const shading_context_t* properties, const sh
}
vec3s bsdf = evaluate_bsdf_simple_lit(context, &surface_data, output.wi);
float cos_theta = fmaxf(0.0f, glms_vec3_dot(output.wi, context->normal));
float cos_theta = fmaxf(0.0f, glms_vec3_dot(output.wi, surface_data.normal));
output.normal = surface_data.normal;
output.bsdf = glms_vec3_scale(bsdf, cos_theta / output.pdf);
output.state = PS_NORMAL;
return output;

View File

@@ -56,7 +56,7 @@ vec4s render_debug(scene_t* scene, ray_t ray, uint16_t sample_index, int flag)
return (vec4s){sobol_sample_value, sobol_sample_value, sobol_sample_value, 1.0f};
case DEBUG_UV:
hit_result_t hit_result = ray_intersect_scene(&ray, scene);
hit_result_t hit_result = ray_intersect_scene_closest(&ray, scene);
return (vec4s){fmodf(fabsf(hit_result.uv.x), 1.0f), fmodf(fabsf(hit_result.uv.y), 1.0f), 0.0f, 1.0f};
default:

View File

@@ -70,7 +70,7 @@ static inline uint16_t get_sample_count(uint16_t sample_count, aov_index_t index
}
}
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)
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)
{
aov_output_t accumulated_color = {0};
@@ -103,8 +103,12 @@ 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)));
aov_output_t aov_output = {0};
aov_output.beauty = path_trace(scene, ray, sobol_idx, config->max_depth);
if (request_aov)
if (has_flag(aov_flags, AOV_BEAUTY))
{
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);
}
@@ -167,7 +171,7 @@ void renderer_start(render_job_t* job)
}
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);
render_pixel(job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, job->aov_flags, &pixel_output);
update_aov(job->aov_target, &pixel_output, (uint32_t)x, (uint32_t)y);
}
}

View File

@@ -82,16 +82,7 @@ texture_entity_t texture_load(const char* filename, bool srgb, stride_t stride,
switch (stride)
{
case UINT_8:
uint8_t* img_data = stbi_load(filename, &width, &height, &channels, 0);
if (srgb)
{
// Convert to linear space if the texture is in sRGB format
for (int i = 0; i < width * height * channels; i++)
{
img_data[i] = (uint8_t)(powf(img_data[i] / 255.0f, 2.2f) * 255.0f);
}
}
data = (char*)img_data;
data = stbi_load(filename, &width, &height, &channels, 0);
break;
case UINT_16:

View File

@@ -25,14 +25,14 @@ 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);
directional_light_t* sun_light = &scene->lights.directional_lights[sun.id];
sun_light->direction = glms_vec3_normalize((vec3s){0.6f, 1.0f, 0.25f});
sun_light->color = (vec3s){1.0f, 0.93f, 0.87f};
sun_light->intensity = 0.0f;
sun_light->intensity = 1.0f;
sun_light->angular_diameter = 0.53f;
//scene->lights.sky_light = sky_create_constant_sky(&(constant_sky_data_t)