Set C standard to C11 and add new assets

Changed CMakeLists.txt to set the C standard to C11.
Added multiple binary image files for new visual assets.
Added several new image files to enhance rendering capabilities.
Changed stb_image.h to improve support for various image formats.
Changed ray tracing engine to enhance ray creation and intersection.
Changed triangle structure to use a vertex array for better attribute handling.
Changed scene initialization to accommodate new texture management.
This commit is contained in:
2025-04-29 01:43:52 +09:00
parent 4db14ffdb0
commit 3de6b83d32
53 changed files with 8939 additions and 162671 deletions

View File

@@ -62,9 +62,9 @@ static inline aabb_t compute_primitives_aabb(const triangle_collection_t* triang
for (uint64_t i = start + 1; i < start + count; ++i)
{
triangle_index = primitive_indices[i];
aabb_growth(&bounds, triangles->buffer[triangle_index].point_1);
aabb_growth(&bounds, triangles->buffer[triangle_index].point_2);
aabb_growth(&bounds, triangles->buffer[triangle_index].point_3);
aabb_growth(&bounds, triangles->buffer[triangle_index].vertices[0].position);
aabb_growth(&bounds, triangles->buffer[triangle_index].vertices[1].position);
aabb_growth(&bounds, triangles->buffer[triangle_index].vertices[2].position);
}
return bounds;

View File

@@ -22,7 +22,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(&active_ray, scene);
if (!closest_hit.hit)
{
@@ -34,7 +34,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
float weight = power_heuristic(pdf_bsdf, pdf_nee);
sky_light = glms_vec3_scale(sky_light, weight);
}
accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(sky_light, 0.0f)); // TODO: Physical Skybox
accumulated_color = glms_vec4_add(accumulated_color, glms_vec4(sky_light, 0.0f));
break;
}
@@ -47,6 +47,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
.normal = closest_hit.normal,
.hit_point = closest_hit.point,
.wo = active_ray.direction,
.uv = closest_hit.uv,
.bounce_depth = depth,
@@ -67,7 +68,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
// 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, sample_index, depth, &pdf_bsdf);
vec3s wi = sample_material_bsdf(hit_material, closest_hit.normal, wo, closest_hit.uv, sample_index, depth, &pdf_bsdf);
if (pdf_bsdf <= 0.0f)
{
break;
@@ -75,8 +76,10 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
shading_context_t shading_context = {
.normal = closest_hit.normal,
.position = closest_hit.point,
.wi = wi,
.wo = wo
.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));
@@ -97,8 +100,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
throughput = glms_vec3_scale(throughput, 1.0f / q);
}
active_ray.origin = BIAS_RAY_ORIGION(closest_hit.point, closest_hit.normal);
active_ray.direction = wi;
active_ray = ray_create(BIAS_RAY_ORIGION(closest_hit.point, closest_hit.normal), wi);
prev_normal = closest_hit.normal;
depth++;

View File

@@ -1,21 +1,87 @@
#include "algorithm/RayIntersection.h"
#include "Algorithm/RayIntersection.h"
#include "Common.h"
#include "Geometry/Triangle.h"
#include "cglm/struct/vec3.h"
ray_t ray_create(vec3s origin, vec3s direction)
{
return (ray_t)
{
.origin = origin,
.direction = direction,
.inverse_direction = glms_vec3_div(glms_vec3_one(), direction),
.sign =
((direction.x < 0.0f) ? 1 : 0) |
((direction.y < 0.0f) ? 2 : 0) |
((direction.z < 0.0f) ? 4 : 0)
,
};
}
static inline float next_float_up(float value)
{
if (isnan(value) || (isfinite(value) && value > 0))
{
return value;
}
return nextafterf(value, INFINITY);
}
static inline float next_float_down(float value)
{
if (isnan(value) || (isfinite(value) && value < 0))
{
return value;
}
return nextafterf(value, -INFINITY);
}
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 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)
{
offset = glms_vec3_negate(offset);
}
vec3s position = glms_vec3_add(point, offset);
for (int i = 0; i < 3; i++)
{
if (offset.raw[i] > 0.0f)
{
position.raw[i] = next_float_up(position.raw[i]);
}
else if (offset.raw[i] < 0.0f)
{
position.raw[i] = next_float_down(position.raw[i]);
}
}
return position;
//return point;
}
#if 0
// TODO: We still have small amount of block dots in current implementation. It's because of floating point precision. May need to fall back to double or handle it in a different way.
hit_result_t ray_intersect_triangle(ray_t ray, triangle_t triangle)
hit_result_t ray_intersect_triangle(const ray_t* ray, const triangle_t* triangle)
{
hit_result_t result = {0};
vec3s edge1 = glms_vec3_sub(triangle.point_2, triangle.point_1);
vec3s edge2 = glms_vec3_sub(triangle.point_3, triangle.point_2);
vec3s edge3 = glms_vec3_sub(triangle.point_1, triangle.point_3);
vec3s edge1 = glms_vec3_sub(triangle->vertices[1].position, triangle->vertices[0].position);
vec3s edge2 = glms_vec3_sub(triangle->vertices[2].position, triangle->vertices[1].position);
vec3s edge3 = glms_vec3_sub(triangle->vertices[0].position, triangle->vertices[2].position);
vec3s normal_face = triangle.normal_face;
float n_dot_r = glms_vec3_dot(normal_face, ray.direction);
vec3s normal = triangle->face_normal;
float n_dot_r = glms_vec3_dot(normal, ray->direction);
if (n_dot_r > 0.0f)
{
normal_face = glms_vec3_negate(normal_face);
normal = glms_vec3_negate(normal);
}
// triangle is parallel to the ray
@@ -25,85 +91,178 @@ hit_result_t ray_intersect_triangle(ray_t ray, triangle_t triangle)
}
// Get distance from ray origin to triangle plane
float distance = (glms_vec3_dot(normal_face, triangle.point_1) - glms_vec3_dot(normal_face, ray.origin)) / glms_vec3_dot(normal_face, ray.direction);
float distance = (glms_vec3_dot(normal, triangle->vertices[0].position) - glms_vec3_dot(normal, ray->origin)) / glms_vec3_dot(normal, ray->direction);
if (distance < RAY_EPSILON)
float eps = gamma(3) * glms_vec3_max(glms_vec3_abs(ray->origin));
if (distance <= eps)
{
return result;
}
vec3s intersection_point = glms_vec3_add(ray.origin, glms_vec3_scale(ray.direction, distance));
vec3s intersection_point = glms_vec3_add(ray->origin, glms_vec3_scale(ray->direction, distance));
// Check if the intersection point is inside the triangle using barycentric coordinates
vec3s vp = glms_vec3_sub(intersection_point, triangle.point_1);
vec3s vp2 = glms_vec3_sub(intersection_point, triangle.point_2);
vec3s vp3 = glms_vec3_sub(intersection_point, triangle.point_3);
vec3s vp = glms_vec3_sub(intersection_point, triangle->vertices[0].position);
vec3s vp2 = glms_vec3_sub(intersection_point, triangle->vertices[1].position);
vec3s vp3 = glms_vec3_sub(intersection_point, triangle->vertices[2].position);
vec3s c1 = glms_vec3_cross(edge1, vp);
vec3s c2 = glms_vec3_cross(edge2, vp2);
vec3s c3 = glms_vec3_cross(edge3, vp3);
if (glms_vec3_dot(triangle.normal_face, c1) < 0.0f
|| glms_vec3_dot(triangle.normal_face, c2) < 0.0f
|| glms_vec3_dot(triangle.normal_face, c3) < 0.0f)
float n_dot_c1 = glms_vec3_dot(normal, c1);
float n_dot_c2 = glms_vec3_dot(normal, c2);
float n_dot_c3 = glms_vec3_dot(normal, c3);
bool r1 = n_dot_c1 > 0.0f && n_dot_c2 > 0.0f && n_dot_c3 > 0.0f;
bool r2 = n_dot_c1 < 0.0f && n_dot_c2 < 0.0f && n_dot_c3 < 0.0f;
if (!r1 && !r2)
{
return result;
}
// TODO: Normal interpolation
vec3s v0v1 = glms_vec3_sub(triangle->vertices[1].position, triangle->vertices[0].position);
vec3s v0v2 = glms_vec3_sub(triangle->vertices[2].position, triangle->vertices[0].position);
vec3s v0p = glms_vec3_sub(intersection_point, triangle->vertices[0].position);
float d00 = glms_vec3_dot(v0v1, v0v1); // dot(v0v1, v0v1)
float d01 = glms_vec3_dot(v0v1, v0v2); // dot(v0v1, v0v2)
float d11 = glms_vec3_dot(v0v2, v0v2); // dot(v0v2, v0v2)
float d20 = glms_vec3_dot(v0p, v0v1); // dot(v0p, v0v1)
float d21 = glms_vec3_dot(v0p, v0v2); // dot(v0p, v0v2)
float denom = d00 * d11 - d01 * d01;
//if (denom < FLT_EPSILON)
//{
// return result;
//}
float invDenom = 1.0f / denom;
float u = (d11 * d20 - d01 * d21) * invDenom; // This is b1 (weight for V1)
float v = (d00 * d21 - d01 * d20) * invDenom; // This is b2 (weight for V2)
float w = 1.0f - u - v;
//vec3s smooth_normal = glms_vec3_add(glms_vec3_scale(triangle->vertices[0].normal, u), glms_vec3_add(glms_vec3_scale(triangle->vertices[1].normal, v), glms_vec3_scale(triangle->vertices[2].normal, w)));
result.hit = true;
result.point = intersection_point;
result.normal = normal_face;
result.normal = normal;
result.uv = (vec2s)
{
.x = w * triangle->vertices[0].uv.x + u * triangle->vertices[1].uv.x + v * triangle->vertices[2].uv.x,
.y = w * triangle->vertices[0].uv.y + u * triangle->vertices[1].uv.y + v * triangle->vertices[2].uv.y,
};
result.distance = distance;
return result;
}
bool ray_intersect_aabb(ray_t ray, aabb_t aabb, float* enter_out, float* exit_out)
#else
hit_result_t ray_intersect_triangle(const ray_t* ray, const triangle_t* triangle)
{
vec3s inv_dir = glms_vec3_div(glms_vec3_one(), ray.direction);
float t_near = -FLT_MIN;
float t_far = FLT_MAX;
hit_result_t result = {0};
// X axis
vec3s origin = ray->origin;
vec3s direction = ray->direction;
vec3s v0 = triangle->vertices[0].position;
vec3s v1 = triangle->vertices[1].position;
vec3s v2 = triangle->vertices[2].position;
vec3s E1 = glms_vec3_sub(v1, v0);
vec3s E2 = glms_vec3_sub(v2, v0);
// Begin MöllerTrumbore
vec3s P = glms_vec3_cross(direction, E2);
float det = glms_vec3_dot(E1, P);
if (fabsf(det) < FLT_EPSILON)
{
float t1 = (aabb.min.x - ray.origin.x) * inv_dir.x;
float t2 = (aabb.max.x - ray.origin.x) * inv_dir.x;
float tmin = fminf(t1, t2);
float tmax = fmaxf(t1, t2);
t_near = fmaxf(t_near, tmin);
t_far = fminf(t_far, tmax);
}
// Y axis
{
float t1 = (aabb.min.y - ray.origin.y) * inv_dir.y;
float t2 = (aabb.max.y - ray.origin.y) * inv_dir.y;
float tmin = fminf(t1, t2);
float tmax = fmaxf(t1, t2);
t_near = fmaxf(t_near, tmin);
t_far = fminf(t_far, tmax);
}
// Z axis
{
float t1 = (aabb.min.z - ray.origin.z) * inv_dir.z;
float t2 = (aabb.max.z - ray.origin.z) * inv_dir.z;
float tmin = fminf(t1, t2);
float tmax = fmaxf(t1, t2);
t_near = fmaxf(t_near, tmin);
t_far = fminf(t_far, tmax);
return result;
}
if (t_near > t_far || t_far < 0.0f)
float invDet = 1.0f / det;
// Calculate barycentric u
vec3s T = glms_vec3_sub(origin, v0);
float u = glms_vec3_dot(T, P) * invDet;
if (u < 0.0f || u > 1.0f)
{
return result;
}
// Calculate barycentric v
vec3s Q = glms_vec3_cross(T, E1);
float v = glms_vec3_dot(direction, Q) * invDet;
if (v < 0.0f || u + v > 1.0f)
{
return result;
}
// Distance along the ray
float t = glms_vec3_dot(E2, Q) * invDet;
if (t < RAY_EPSILON)
{
return result;
}
result.hit = true;
result.distance = t;
result.point = glms_vec3_add(origin, glms_vec3_scale(direction, t));
// Face normal (unchanged by windings)
vec3s n = triangle->face_normal;
result.normal = glms_vec3_dot(n, direction) < 0.0f ? n : glms_vec3_negate(n);
// Interpolate UVs
float w = 1.0f - u - v;
result.uv.x = w * triangle->vertices[0].uv.x
+ u * triangle->vertices[1].uv.x
+ v * triangle->vertices[2].uv.x;
result.uv.y = w * triangle->vertices[0].uv.y
+ u * triangle->vertices[1].uv.y
+ v * triangle->vertices[2].uv.y;
return result;
}
#endif
bool ray_intersect_aabb(const ray_t* ray, aabb_t aabb, float* enter_out, float* exit_out)
{
// select slab min/max per axis based on sign:
float tx_min = ((SIGN_BIT(ray->sign, 0) ? aabb.max.x : aabb.min.x) - ray->origin.x ) * ray->inverse_direction.x;
float tx_max = ((SIGN_BIT(ray->sign, 0) ? aabb.min.x : aabb.max.x) - ray->origin.x ) * ray->inverse_direction.x;
float ty_min = ((SIGN_BIT(ray->sign, 1) ? aabb.max.y : aabb.min.y) - ray->origin.y ) * ray->inverse_direction.y;
float ty_max = ((SIGN_BIT(ray->sign, 1) ? aabb.min.y : aabb.max.y) - ray->origin.y ) * ray->inverse_direction.y;
// early exit if slabs miss
if ((tx_min > ty_max) || (ty_min > tx_max))
{
return false;
}
if (enter_out)
*enter_out = t_near;
if (exit_out)
*exit_out = t_far;
// merge X and Y
float t0 = tx_min > ty_min ? tx_min : ty_min;
float t1 = tx_max < ty_max ? tx_max : ty_max;
float tz_min = ( (SIGN_BIT(ray->sign, 2) ? aabb.max.z : aabb.min.z) - ray->origin.z ) * ray->inverse_direction.z;
float tz_max = ( (SIGN_BIT(ray->sign, 2) ? aabb.min.z : aabb.max.z) - ray->origin.z ) * ray->inverse_direction.z;
// final overlap test
if ((t0 > tz_max) || (tz_min > t1))
{
return false;
}
// update entry/exit
if (enter_out != NULL)
{
*enter_out = t0 > tz_min ? t0 : tz_min;
}
if (exit_out != NULL)
{
*exit_out = t1 < tz_max ? t1 : tz_max;
}
return true;
}
@@ -117,7 +276,7 @@ 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,
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)
{
const bvh_node_t* node = &bvh_nodes[node_index];
@@ -139,7 +298,7 @@ void ray_intersect_bvh(const ray_t ray, const bvh_node_t* bvh_nodes, const uint6
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]);
hit_result_t hit_result = ray_intersect_triangle(ray, &all_triangles->buffer[triangle_index]);
if (hit_result.hit && hit_result.distance < *closest_out)
{
hit_result.triangle_id = triangle_index;
@@ -191,7 +350,7 @@ void ray_intersect_bvh(const ray_t ray, const bvh_node_t* bvh_nodes, const uint6
}
}
hit_result_t ray_intersect_scene(ray_t ray, const scene_t* scene)
hit_result_t ray_intersect_scene(const ray_t* ray, const scene_t* scene)
{
hit_result_t result = {0};
float closest = FLT_MAX;