Added mip selection using ray differentials

This commit is contained in:
2025-12-29 23:36:21 +09:00
parent adee5acd10
commit 400137ee99
12 changed files with 125 additions and 28 deletions

View File

@@ -393,13 +393,33 @@ vec4s texture_get_pixel(const texture_t* texture, vec2s uv, uint8_t lod)
return get_pixel_data_from_buffer(mipmap->data, x, y, mipmap->width, texture->channel_count, texture->stride);
}
float texture_get_sample_lod(vec3s view_direction, vec3s normal, float distance)
// Calculate LOD based on Ray Cones
float texture_get_sample_lod(const texture_t* texture, const texture_sample_context_t* sample_context)
{
// TODO: Implement a more accurate LOD calculation.
const float factor = 1.0f;
// 1. Calculate the ray footprint on the surface
// If we hit the surface at an angle, the footprint elongates.
float cos_theta = fabsf(glms_vec3_dot(sample_context->normal, sample_context->view_direction));
float surface_width = sample_context->ray_width / fmaxf(cos_theta, 0.001f); // Project width onto surface
float n_dot_v = glms_vec3_dot(normal, view_direction);
return fmaxf(log2f(distance * factor) - fabsf(n_dot_v), 0.0f);
// 2. Estimate UV density (How much UV changes per meter of surface)
// This is an approximation. A more accurate way uses Triangle derivatives (Ray Differentials).
// For a triangle, we can approximate the scale:
float edge1_len = glms_vec3_norm(sample_context->edge1);
float edge2_len = glms_vec3_norm(sample_context->edge2);
float uv_area = fabsf((sample_context->uv1.x * sample_context->uv2.y) - (sample_context->uv1.y * sample_context->uv2.x)); // Approximation of UV area
float geo_area = glms_vec3_norm(glms_vec3_cross(sample_context->edge1, sample_context->edge2));
// Ratio of Texture Area to Geometric Area
float uv_density = sqrtf(uv_area / geo_area);
// 3. Calculate texture footprint
// How many texels does our ray cover?
float texels_covered = surface_width * uv_density * fmaxf(texture->width, texture->height);
// 4. Convert to LOD
// LOD 0 = 1 texel. LOD 1 = 2 texels. LOD 2 = 4 texels.
// log2(texels_covered) gives the mip level.
return log2f(texels_covered);
}
static vec4s nearest_filter(const texture_t* texture, vec2s uv, uint8_t lod)
@@ -460,10 +480,11 @@ static inline vec4s filter_texture(const texture_t* texture, vec2s uv, float lod
}
}
vec4s texture_sample(const texture_t* texture, vec2s uv, vec3s view_direction, vec3s normal, float distance)
vec4s texture_sample(const texture_t* texture, const texture_sample_context_t* sample_context, vec2s uv)
{
warp_uv(texture->wrap_mode, &uv);
return filter_texture(texture, uv, texture_get_sample_lod(view_direction, normal, distance));
float lod = texture_get_sample_lod(texture, sample_context);
return filter_texture(texture, uv, lod);
}
vec4s texture_sample_lod(const texture_t* texture, vec2s uv, float lod)