diff --git a/header/Algorithm/BSDF.h b/header/Algorithm/BSDF.h index 20f8cb8..ef5f803 100644 --- a/header/Algorithm/BSDF.h +++ b/header/Algorithm/BSDF.h @@ -6,6 +6,7 @@ float power_heuristic(float pdf_a, float pdf_b); float roughness_to_blinn_phong_specular_exponent(float roughness); +float blinn_phong_specular_exponent_to_roughness(float specular_exponent); vec3s fresnel_schlick_vec3(vec3s f0, float cos_theta); // BSDF sampling functions diff --git a/header/Lighting/Light.h b/header/Lighting/Light.h index 14173b0..c2dbbdb 100644 --- a/header/Lighting/Light.h +++ b/header/Lighting/Light.h @@ -24,6 +24,7 @@ typedef struct const bvh_tree_t* bvh_tree; const material_t* material; + const texture_collection_t* textures; } light_shading_context_t; #ifdef __STDC_ALIGN__ diff --git a/header/Material/Material.h b/header/Material/Material.h index 2710b8b..ef6140d 100644 --- a/header/Material/Material.h +++ b/header/Material/Material.h @@ -3,6 +3,7 @@ #include "Algorithm/Sobol.h" #include "Common.h" +#include "Rendering/Texture.h" #define PROPERTY_SIZE 64 #define INVALID_MATERIAL_ID 255 @@ -14,6 +15,8 @@ typedef struct vec3s wi; vec3s wo; vec2s uv; + + const texture_collection_t* textures; } shading_context_t; typedef void (*compute_surface_data_f)(const shading_context_t* context, const void* properties, void* surface_data_out); @@ -53,8 +56,8 @@ void material_collection_free(material_collection_t* materials); material_entity_t material_create(const void* properties, size_t properties_size, compute_surface_data_f surface_data, sample_bsdf_f sample, sample_bsdf_pdf_f sample_pdf, evaluate_bsdf_f evaluate, material_collection_t* collection); -vec3s sample_material_bsdf(const material_t* material, vec3s normal, vec3s wo, vec2s uv, uint32_t sample_index, uint32_t bounce, float* pdf_out); -float sample_material_bsdf_pdf(const material_t* material, vec3s normal, vec3s wo, vec3s wi, vec2s uv); +vec3s sample_material_bsdf(const material_t* material, const shading_context_t* context, uint32_t sample_index, uint32_t bounce, float* pdf_out); +float sample_material_bsdf_pdf(const material_t* material, const shading_context_t* context); vec3s evaluate_material_bsdf(const material_t* material, const shading_context_t* context); #endif // MATERIAL_H diff --git a/header/Material/SimpleLit.h b/header/Material/SimpleLit.h index 7f6cd5b..73aa798 100644 --- a/header/Material/SimpleLit.h +++ b/header/Material/SimpleLit.h @@ -18,9 +18,9 @@ typedef struct float roughness; float metallic; - const texture_t* albedo_texture; - const texture_t* roughness_texture; - const texture_t* metallic_texture; + texture_entity_t albedo_texture; + texture_entity_t roughness_texture; + texture_entity_t metallic_texture; } simple_lit_properties_t; void simple_lit_data_default(const shading_context_t* context, const void* properties, void* data_out); diff --git a/header/Rendering/Texture.h b/header/Rendering/Texture.h index 8e482d8..d2600e8 100644 --- a/header/Rendering/Texture.h +++ b/header/Rendering/Texture.h @@ -50,4 +50,24 @@ texture_entity_t texture_load(const char* filename, bool srgb, texture_collectio vec4s texture_sample(const texture_t* texture, float u, float v); void texture_free(texture_t* texture); +inline texture_entity_t invalid_texture_entity() +{ + return (texture_entity_t){.id = INVALID_TEXTURE_ID}; +} + +inline bool is_texture_entity_valid(texture_entity_t entity) +{ + return entity.id != INVALID_TEXTURE_ID; +} + +inline texture_t* get_texture(const texture_collection_t* textures, texture_entity_t entity) +{ + if (entity.id >= textures->count || !is_texture_entity_valid(entity)) + { + return NULL; + } + + return &textures->buffer[entity.id]; +} + #endif // TEXTURE_H diff --git a/source/Algorithm/BSDF.c b/source/Algorithm/BSDF.c index e0291c6..ed9a540 100644 --- a/source/Algorithm/BSDF.c +++ b/source/Algorithm/BSDF.c @@ -12,6 +12,11 @@ float roughness_to_blinn_phong_specular_exponent(float roughness) return glm_clamp(2.0f * 1.0f / (fmaxf(roughness * roughness, FLT_EPSILON)) - 2.0f, FLT_EPSILON, 1.0f / FLT_EPSILON); } +float blinn_phong_specular_exponent_to_roughness(float specular_exponent) +{ + return sqrtf(2.0f / (specular_exponent + 2.0f)); +} + vec3s fresnel_schlick_vec3(vec3s f0, float cos_theta) { float x = 1.0f - cos_theta; diff --git a/source/Algorithm/PathTracing.c b/source/Algorithm/PathTracing.c index 4344c4d..565ff1e 100644 --- a/source/Algorithm/PathTracing.c +++ b/source/Algorithm/PathTracing.c @@ -7,11 +7,6 @@ // TODO: Split the diffuse and specular into different Monte Carlo, so we can decide the sample count for each one vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_t max_depth) { - const triangle_collection_t* triangles = &scene->triangles; - const bvh_tree_t* bvh_tree = &scene->bvh_tree; - const material_collection_t* materials = &scene->materials; - const light_collection_t* lights = &scene->lights; - vec4s accumulated_color = (vec4s){0.0f, 0.0f, 0.0f, 1.0f}; vec3s throughput = glms_vec3_one(); @@ -39,7 +34,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_ } // Add the emission of the hit material to the accumulated color - material_t* hit_material = &materials->buffer[triangles->buffer[closest_hit.triangle_id].material_id]; + const material_t* hit_material = &scene->materials.buffer[scene->triangles.buffer[closest_hit.triangle_id].material_id]; vec3s emission = hit_material->emission; accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(glms_vec3_mul(throughput, emission), 0.0f)); @@ -51,15 +46,16 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_ .bounce_depth = depth, - .bvh_tree = bvh_tree, - .material = hit_material + .bvh_tree = &scene->bvh_tree, + .material = hit_material, + .textures = &scene->textures, }; // Running the light loop. // TODO: Implementing other light types. - for (uint32_t i = 0; i < lights->directional_light_count; i++) + for (uint32_t i = 0; i < scene->lights.directional_light_count; i++) { - vec3s l = evaluate_bsdf_directional(lights->directional_lights[i], &light_context, throughput, sample_index); + vec3s l = evaluate_bsdf_directional(scene->lights.directional_lights[i], &light_context, throughput, sample_index); accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(l, 0.0f)); } @@ -67,26 +63,28 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_ accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(sky_light, 0.0f)); // Bounce and prepare for the next iteration - vec3s wo = glms_vec3_negate(active_ray.direction); // We need to negate the direction of the incoming ray - vec3s wi = sample_material_bsdf(hit_material, closest_hit.normal, wo, closest_hit.uv, sample_index, depth, &pdf_bsdf); + shading_context_t shading_context = { + .normal = closest_hit.normal, + .position = closest_hit.point, + .wo = glms_vec3_negate(active_ray.direction), + .uv = closest_hit.uv, + + .textures = &scene->textures, + }; + + vec3s wi = sample_material_bsdf(hit_material, &shading_context, sample_index, depth, &pdf_bsdf); + shading_context.wi = wi; if (pdf_bsdf <= 0.0f) { break; } - shading_context_t shading_context = { - .normal = closest_hit.normal, - .position = closest_hit.point, - .wi = wi, - .wo = wo, - .uv = closest_hit.uv, - }; vec3s bsdf = evaluate_material_bsdf(hit_material, &shading_context); float cos_theta = fmaxf(0.0f, glms_vec3_dot(wi, closest_hit.normal)); throughput = glms_vec3_mul(throughput, glms_vec3_scale(bsdf, cos_theta / pdf_bsdf)); - // We do Russian roulette to decide whether to continue tracing or terminate the path + // We do Russian roulette to decide whether to continue tracing or terminate the path if (depth > 1) { float q = fminf(glms_vec3_max(throughput), 0.95f); diff --git a/source/Geometry/Mesh.c b/source/Geometry/Mesh.c index cd085c7..337c99e 100644 --- a/source/Geometry/Mesh.c +++ b/source/Geometry/Mesh.c @@ -1,4 +1,5 @@ #include "Geometry/Mesh.h" +#include "ALgorithm/BSDF.h" #include "Common/String.h" #include "Material/SimpleLit.h" #include "assimp/cimport.h" @@ -26,10 +27,11 @@ mesh_entity_t mesh_load(const char* filename, scene_t* scene) struct aiColor4D base_color; aiGetMaterialColor(src, AI_MATKEY_COLOR_DIFFUSE, &base_color); - float smoothness = 0.5f; - aiGetMaterialFloat(src, AI_MATKEY_SHININESS, &smoothness); + float roughness = 0.5f; + aiGetMaterialFloat(src, AI_MATKEY_SHININESS, &roughness); + roughness = blinn_phong_specular_exponent_to_roughness(roughness); - texture_t* albedo_texture = NULL; + texture_entity_t albedo_entity = invalid_texture_entity(); if (aiGetMaterialTextureCount(src, aiTextureType_DIFFUSE) > 0) { struct aiString path; @@ -47,7 +49,7 @@ mesh_entity_t mesh_load(const char* filename, scene_t* scene) texture_entity_t entity = texture_load(path.data, true, &scene->textures); if (entity.id != INVALID_TEXTURE_ID) { - albedo_texture = &scene->textures.buffer[entity.id]; + albedo_entity = entity; } } } @@ -55,13 +57,14 @@ mesh_entity_t mesh_load(const char* filename, scene_t* scene) simple_lit_properties_t prop = { .albedo = {base_color.r, base_color.g, base_color.b}, - .roughness = 1.0f - smoothness, + .roughness = roughness, .metallic = 0.0f, - .albedo_texture = albedo_texture, + .albedo_texture = albedo_entity, }; material_create_simple_lit_default(&prop, &scene->materials); + entity.material_count++; } for (uint32_t i = 0; i < mesh_scene->mNumMeshes; i++) diff --git a/source/Lighting/LightEvaluation.c b/source/Lighting/LightEvaluation.c index 6a850c9..eb8c73b 100644 --- a/source/Lighting/LightEvaluation.c +++ b/source/Lighting/LightEvaluation.c @@ -33,6 +33,8 @@ vec3s evaluate_bsdf_directional(directional_light_t light, const light_shading_c .wi = wi, .wo = glms_vec3_negate(context->wo), .uv = context->uv, + + .textures = context->textures, }; vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context); diff --git a/source/Lighting/SkyLight.c b/source/Lighting/SkyLight.c index 513fe96..6cd46ae 100644 --- a/source/Lighting/SkyLight.c +++ b/source/Lighting/SkyLight.c @@ -34,13 +34,15 @@ vec3s evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* c .wi = wi, .wo = glms_vec3_negate(context->wo), .uv = context->uv, + + .textures = context->textures, }; vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context); bsdf = glms_vec3_mul(bsdf, sky_color); float cos_theta = fmaxf(glms_vec3_dot(wi, context->normal), 0.0f); - float pdf_bsdf = sample_material_bsdf_pdf(context->material, shading_context.normal, shading_context.wo, shading_context.wi, context->uv); + float pdf_bsdf = sample_material_bsdf_pdf(context->material, &shading_context); float weight = power_heuristic(pdf, pdf_bsdf); vec3s env_contrib = glms_vec3_scale(glms_vec3_mul(throughput, bsdf), cos_theta / pdf); diff --git a/source/Material/Material.c b/source/Material/Material.c index f9f8857..6aa18aa 100644 --- a/source/Material/Material.c +++ b/source/Material/Material.c @@ -71,36 +71,23 @@ material_entity_t material_create(const void* properties, size_t properties_size return entity; } -vec3s sample_material_bsdf(const material_t* material, vec3s normal, vec3s wo, vec2s uv, uint32_t sample_index, uint32_t bounce, float* pdf_out) +vec3s sample_material_bsdf(const material_t* material, const shading_context_t* context, uint32_t sample_index, uint32_t bounce, float* pdf_out) { vec3s wi = glms_vec3_zero(); if (material->compute_surface_data != NULL && material->sample_bsdf != NULL) { - shading_context_t context = - { - .normal = normal, - .wo = wo, - .uv = uv, - }; - wi = material->sample_bsdf(&context, material->properties, material->compute_surface_data, sample_index, bounce, pdf_out); + wi = material->sample_bsdf(context, material->properties, material->compute_surface_data, sample_index, bounce, pdf_out); } return wi; } -float sample_material_bsdf_pdf(const material_t* material, vec3s normal, vec3s wo, vec3s wi, vec2s uv) +float sample_material_bsdf_pdf(const material_t* material, const shading_context_t* context) { float pdf = 0.0f; if (material->compute_surface_data != NULL && material->sample_bsdf_pdf != NULL) { - shading_context_t context = - { - .normal = normal, - .wo = wo, - .wi = wi, - .uv = uv, - }; - pdf = material->sample_bsdf_pdf(&context, material->properties, material->compute_surface_data); + pdf = material->sample_bsdf_pdf(context, material->properties, material->compute_surface_data); } return pdf; diff --git a/source/Material/SimpleLit.c b/source/Material/SimpleLit.c index ba1f815..7cac0be 100644 --- a/source/Material/SimpleLit.c +++ b/source/Material/SimpleLit.c @@ -12,21 +12,27 @@ void simple_lit_data_default(const shading_context_t* context, const void* prope simple_lit_data_t* data = (simple_lit_data_t*)data_out; data->albedo = prop->albedo; - if (prop->albedo_texture != NULL && prop->albedo_texture->data != NULL) + + const texture_t* albedo_texture = get_texture(context->textures, prop->albedo_texture); + if (albedo_texture != NULL && albedo_texture->data != NULL) { - data->albedo = glms_vec3_mul(data->albedo, glms_vec3(texture_sample(prop->albedo_texture, context->uv.x, context->uv.y))); + data->albedo = glms_vec3_mul(data->albedo, glms_vec3(texture_sample(albedo_texture, context->uv.x, context->uv.y))); } data->roughness = prop->roughness; - if (prop->roughness_texture != NULL && prop->roughness_texture->data != NULL) + + const texture_t* roughness_texture = get_texture(context->textures, prop->roughness_texture); + if (roughness_texture != NULL && roughness_texture->data != NULL) { - data->roughness = data->roughness * texture_sample(prop->roughness_texture, context->uv.x, context->uv.y).x; + data->roughness = data->roughness * texture_sample(roughness_texture, context->uv.x, context->uv.y).x; } data->metallic = prop->metallic; - if (prop->metallic_texture != NULL && prop->metallic_texture->data != NULL) + + const texture_t* metallic_texture = get_texture(context->textures, prop->metallic_texture); + if (metallic_texture != NULL && metallic_texture->data != NULL) { - data->metallic = data->metallic * texture_sample(prop->metallic_texture, context->uv.x, context->uv.y).x; + data->metallic = data->metallic * texture_sample(metallic_texture, context->uv.x, context->uv.y).x; } } diff --git a/source/Rendering/Texture.c b/source/Rendering/Texture.c index cd5f1f7..7d1ca86 100644 --- a/source/Rendering/Texture.c +++ b/source/Rendering/Texture.c @@ -5,11 +5,6 @@ #define GET_CHANNEL_DATA(pixel, channel, channel_count, default) (channel < channel_count ? pixel[channel] : default) / 255.0f -static inline texture_entity_t invalid_texture_entity() -{ - return (texture_entity_t){.id = INVALID_TEXTURE_ID}; -} - bool texture_collection_init(uint16_t size, texture_collection_t* textures) { texture_collection_t temp = {0};