Add texture handling and refactor material functions

Added a new function `blinn_phong_specular_exponent_to_roughness` in `BSDF.h` to convert a specular exponent to roughness.
Added a `textures` member to the `shading_context_t` structure in `Material.h` for passing texture information during shading.
Added a new member `textures` in the `light_shading_context_t` structure in `Light.h` to hold texture information.
Added inline functions in `Texture.h` for handling texture entities, including `invalid_texture_entity`, `is_texture_entity_valid`, and `get_texture`.
Changed the texture-related members in `simple_lit_properties_t` in `SimpleLit.h` from pointers to `texture_entity_t` to better manage texture entities.
Changed the `sample_material_bsdf` and `sample_material_bsdf_pdf` functions in `Material.h` to accept a `shading_context_t` instead of individual parameters.
Changed the `mesh_load` function in `Mesh.c` to use the new roughness calculation and texture entity handling.
Changed the `path_trace` function in `PathTracing.c` to use the new structure and functions for handling materials and textures.
Refactored the `sample_material_bsdf` and `sample_material_bsdf_pdf` functions in `Material.c` to utilize the new `shading_context_t` structure.
Updated the `material_collection_init` function in `Material.h` to reflect changes in the material sampling functions.
Updated the `evaluate_bsdf_directional` and `evaluate_bsdf_const_sky` functions to use the new shading context structure.
Adjusted the `simple_lit_data_default` function in `SimpleLit.c` to work with the new texture handling approach.
Added texture entity handling in `Texture.c` for managing invalid texture entities.
This commit is contained in:
2025-04-29 13:29:29 +09:00
parent 3de6b83d32
commit 3c3168af7a
13 changed files with 83 additions and 60 deletions

View File

@@ -6,6 +6,7 @@
float power_heuristic(float pdf_a, float pdf_b); float power_heuristic(float pdf_a, float pdf_b);
float roughness_to_blinn_phong_specular_exponent(float roughness); 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); vec3s fresnel_schlick_vec3(vec3s f0, float cos_theta);
// BSDF sampling functions // BSDF sampling functions

View File

@@ -24,6 +24,7 @@ typedef struct
const bvh_tree_t* bvh_tree; const bvh_tree_t* bvh_tree;
const material_t* material; const material_t* material;
const texture_collection_t* textures;
} light_shading_context_t; } light_shading_context_t;
#ifdef __STDC_ALIGN__ #ifdef __STDC_ALIGN__

View File

@@ -3,6 +3,7 @@
#include "Algorithm/Sobol.h" #include "Algorithm/Sobol.h"
#include "Common.h" #include "Common.h"
#include "Rendering/Texture.h"
#define PROPERTY_SIZE 64 #define PROPERTY_SIZE 64
#define INVALID_MATERIAL_ID 255 #define INVALID_MATERIAL_ID 255
@@ -14,6 +15,8 @@ typedef struct
vec3s wi; vec3s wi;
vec3s wo; vec3s wo;
vec2s uv; vec2s uv;
const texture_collection_t* textures;
} shading_context_t; } shading_context_t;
typedef void (*compute_surface_data_f)(const shading_context_t* context, const void* properties, void* surface_data_out); 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); 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); 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, vec3s normal, vec3s wo, vec3s wi, vec2s uv); 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); vec3s evaluate_material_bsdf(const material_t* material, const shading_context_t* context);
#endif // MATERIAL_H #endif // MATERIAL_H

View File

@@ -18,9 +18,9 @@ typedef struct
float roughness; float roughness;
float metallic; float metallic;
const texture_t* albedo_texture; texture_entity_t albedo_texture;
const texture_t* roughness_texture; texture_entity_t roughness_texture;
const texture_t* metallic_texture; texture_entity_t metallic_texture;
} simple_lit_properties_t; } simple_lit_properties_t;
void simple_lit_data_default(const shading_context_t* context, const void* properties, void* data_out); void simple_lit_data_default(const shading_context_t* context, const void* properties, void* data_out);

View File

@@ -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); vec4s texture_sample(const texture_t* texture, float u, float v);
void texture_free(texture_t* texture); 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 #endif // TEXTURE_H

View File

@@ -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); 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) vec3s fresnel_schlick_vec3(vec3s f0, float cos_theta)
{ {
float x = 1.0f - cos_theta; float x = 1.0f - cos_theta;

View File

@@ -7,11 +7,6 @@
// TODO: Split the diffuse and specular into different Monte Carlo, so we can decide the sample count for each one // 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) 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}; vec4s accumulated_color = (vec4s){0.0f, 0.0f, 0.0f, 1.0f};
vec3s throughput = glms_vec3_one(); 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 // 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; vec3s emission = hit_material->emission;
accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(glms_vec3_mul(throughput, emission), 0.0f)); 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, .bounce_depth = depth,
.bvh_tree = bvh_tree, .bvh_tree = &scene->bvh_tree,
.material = hit_material .material = hit_material,
.textures = &scene->textures,
}; };
// Running the light loop. // Running the light loop.
// TODO: Implementing other light types. // 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)); 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)); accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(sky_light, 0.0f));
// Bounce and prepare for the next iteration // 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 shading_context_t shading_context = {
vec3s wi = sample_material_bsdf(hit_material, closest_hit.normal, wo, closest_hit.uv, sample_index, depth, &pdf_bsdf); .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) if (pdf_bsdf <= 0.0f)
{ {
break; 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); vec3s bsdf = evaluate_material_bsdf(hit_material, &shading_context);
float cos_theta = fmaxf(0.0f, glms_vec3_dot(wi, closest_hit.normal)); 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)); 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) if (depth > 1)
{ {
float q = fminf(glms_vec3_max(throughput), 0.95f); float q = fminf(glms_vec3_max(throughput), 0.95f);

View File

@@ -1,4 +1,5 @@
#include "Geometry/Mesh.h" #include "Geometry/Mesh.h"
#include "ALgorithm/BSDF.h"
#include "Common/String.h" #include "Common/String.h"
#include "Material/SimpleLit.h" #include "Material/SimpleLit.h"
#include "assimp/cimport.h" #include "assimp/cimport.h"
@@ -26,10 +27,11 @@ mesh_entity_t mesh_load(const char* filename, scene_t* scene)
struct aiColor4D base_color; struct aiColor4D base_color;
aiGetMaterialColor(src, AI_MATKEY_COLOR_DIFFUSE, &base_color); aiGetMaterialColor(src, AI_MATKEY_COLOR_DIFFUSE, &base_color);
float smoothness = 0.5f; float roughness = 0.5f;
aiGetMaterialFloat(src, AI_MATKEY_SHININESS, &smoothness); 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) if (aiGetMaterialTextureCount(src, aiTextureType_DIFFUSE) > 0)
{ {
struct aiString path; 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); texture_entity_t entity = texture_load(path.data, true, &scene->textures);
if (entity.id != INVALID_TEXTURE_ID) 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 = simple_lit_properties_t prop =
{ {
.albedo = {base_color.r, base_color.g, base_color.b}, .albedo = {base_color.r, base_color.g, base_color.b},
.roughness = 1.0f - smoothness, .roughness = roughness,
.metallic = 0.0f, .metallic = 0.0f,
.albedo_texture = albedo_texture, .albedo_texture = albedo_entity,
}; };
material_create_simple_lit_default(&prop, &scene->materials); material_create_simple_lit_default(&prop, &scene->materials);
entity.material_count++;
} }
for (uint32_t i = 0; i < mesh_scene->mNumMeshes; i++) for (uint32_t i = 0; i < mesh_scene->mNumMeshes; i++)

View File

@@ -33,6 +33,8 @@ vec3s evaluate_bsdf_directional(directional_light_t light, const light_shading_c
.wi = wi, .wi = wi,
.wo = glms_vec3_negate(context->wo), .wo = glms_vec3_negate(context->wo),
.uv = context->uv, .uv = context->uv,
.textures = context->textures,
}; };
vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context); vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context);

View File

@@ -34,13 +34,15 @@ vec3s evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* c
.wi = wi, .wi = wi,
.wo = glms_vec3_negate(context->wo), .wo = glms_vec3_negate(context->wo),
.uv = context->uv, .uv = context->uv,
.textures = context->textures,
}; };
vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context); vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context);
bsdf = glms_vec3_mul(bsdf, sky_color); bsdf = glms_vec3_mul(bsdf, sky_color);
float cos_theta = fmaxf(glms_vec3_dot(wi, context->normal), 0.0f); 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); float weight = power_heuristic(pdf, pdf_bsdf);
vec3s env_contrib = glms_vec3_scale(glms_vec3_mul(throughput, bsdf), cos_theta / pdf); vec3s env_contrib = glms_vec3_scale(glms_vec3_mul(throughput, bsdf), cos_theta / pdf);

View File

@@ -71,36 +71,23 @@ material_entity_t material_create(const void* properties, size_t properties_size
return entity; 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(); vec3s wi = glms_vec3_zero();
if (material->compute_surface_data != NULL && material->sample_bsdf != NULL) if (material->compute_surface_data != NULL && material->sample_bsdf != NULL)
{ {
shading_context_t context = wi = material->sample_bsdf(context, material->properties, material->compute_surface_data, sample_index, bounce, pdf_out);
{
.normal = normal,
.wo = wo,
.uv = uv,
};
wi = material->sample_bsdf(&context, material->properties, material->compute_surface_data, sample_index, bounce, pdf_out);
} }
return wi; 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; float pdf = 0.0f;
if (material->compute_surface_data != NULL && material->sample_bsdf_pdf != NULL) if (material->compute_surface_data != NULL && material->sample_bsdf_pdf != NULL)
{ {
shading_context_t context = pdf = material->sample_bsdf_pdf(context, material->properties, material->compute_surface_data);
{
.normal = normal,
.wo = wo,
.wi = wi,
.uv = uv,
};
pdf = material->sample_bsdf_pdf(&context, material->properties, material->compute_surface_data);
} }
return pdf; return pdf;

View File

@@ -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; simple_lit_data_t* data = (simple_lit_data_t*)data_out;
data->albedo = prop->albedo; 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; 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; 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;
} }
} }

View File

@@ -5,11 +5,6 @@
#define GET_CHANNEL_DATA(pixel, channel, channel_count, default) (channel < channel_count ? pixel[channel] : default) / 255.0f #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) bool texture_collection_init(uint16_t size, texture_collection_t* textures)
{ {
texture_collection_t temp = {0}; texture_collection_t temp = {0};