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.
@@ -1,6 +1,7 @@
|
|||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(PROJECT_NAME SimpleRayTracer)
|
set(PROJECT_NAME SimpleRayTracer)
|
||||||
|
|
||||||
project(${PROJECT_NAME} LANGUAGES C)
|
project(${PROJECT_NAME} LANGUAGES C)
|
||||||
|
|||||||
BIN
assets/00_skap.JPG
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/01_STUB-bump.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
assets/01_STUB.jpg
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
assets/01_S_ba.JPG
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/01_S_kap-bump.jpg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
assets/01_S_kap.JPG
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/01_St_kp-bump.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/01_St_kp.JPG
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
assets/KAMEN-bump.jpg
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
assets/KAMEN-stup.JPG
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
assets/KAMEN.JPG
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
assets/prozor1.JPG
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/reljef-bump.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
assets/reljef.JPG
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
assets/sp_luk-bump.JPG
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/sp_luk.JPG
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
assets/sponza.fbx
Normal file
162358
assets/sponza.obj
BIN
assets/vrata_ko.JPG
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/vrata_kr.JPG
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
assets/x01_st-bump.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/x01_st.JPG
Normal file
|
After Width: | Height: | Size: 25 KiB |
7988
external/stb_image.h
vendored
Normal file
@@ -5,26 +5,34 @@
|
|||||||
#include "Geometry/Triangle.h"
|
#include "Geometry/Triangle.h"
|
||||||
#include "Rendering/Scene.h"
|
#include "Rendering/Scene.h"
|
||||||
|
|
||||||
|
#define SIGN_BIT(sign, axis) (((sign) >> (axis)) & 1)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3s origin;
|
vec3s origin;
|
||||||
vec3s direction;
|
vec3s direction;
|
||||||
|
vec3s inverse_direction;
|
||||||
|
uint8_t sign;
|
||||||
} ray_t;
|
} ray_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3s point;
|
vec3s point;
|
||||||
vec3s normal;
|
vec3s normal;
|
||||||
|
vec2s uv;
|
||||||
uint64_t triangle_id;
|
uint64_t triangle_id;
|
||||||
float distance;
|
float distance;
|
||||||
bool hit;
|
bool hit;
|
||||||
} hit_result_t;
|
} hit_result_t;
|
||||||
|
|
||||||
hit_result_t ray_intersect_triangle(ray_t ray, triangle_t triangle);
|
ray_t ray_create(vec3s origin, vec3s direction);
|
||||||
bool ray_intersect_aabb(ray_t ray, aabb_t aabb, float* enter_out, float* exit_out);
|
vec3s offset_ray_origin(vec3s point, vec3s normal, vec3s wo);
|
||||||
void ray_intersect_bvh(const ray_t ray, const bvh_node_t* bvh_nodes,
|
|
||||||
|
hit_result_t ray_intersect_triangle(const ray_t* ray, const triangle_t* triangle);
|
||||||
|
bool ray_intersect_aabb(const ray_t* ray, aabb_t aabb, float* enter_out, float* exit_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,
|
const uint64_t* primitive_indices, const triangle_collection_t* all_triangles, uint64_t node_index,
|
||||||
float* closest_out, hit_result_t* best_hit_out);
|
float* closest_out, hit_result_t* best_hit_out);
|
||||||
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);
|
||||||
|
|
||||||
#endif // RAY_INTERSECTION_H
|
#endif // RAY_INTERSECTION_H
|
||||||
|
|||||||
@@ -6,9 +6,10 @@
|
|||||||
#include "cglm/struct/vec3.h"
|
#include "cglm/struct/vec3.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define RAY_EPSILON 5.192092896e-05F
|
#define RAY_EPSILON 6.192092896e-05F
|
||||||
|
|
||||||
#define COLOR_CLAMP(color) (unsigned char)fminf(fmaxf(color, 0.0f), 255.0f)
|
#define COLOR_CLAMP(color) (unsigned char)fminf(fmaxf(color, 0.0f), 255.0f)
|
||||||
|
// Any better way to do this?
|
||||||
#define BIAS_RAY_ORIGION(positon, normal) glms_vec3_add(positon, glms_vec3_scale(normal, RAY_EPSILON))
|
#define BIAS_RAY_ORIGION(positon, normal) glms_vec3_add(positon, glms_vec3_scale(normal, RAY_EPSILON))
|
||||||
|
|
||||||
inline float random_float()
|
inline float random_float()
|
||||||
@@ -16,7 +17,13 @@ inline float random_float()
|
|||||||
return (float)rand() / (float)RAND_MAX;
|
return (float)rand() / (float)RAND_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t hash_uint32(uint32_t x) {
|
inline float gamma(int n)
|
||||||
|
{
|
||||||
|
return (n * FLT_EPSILON) / (1.0f - n * FLT_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t hash_uint32(uint32_t x)
|
||||||
|
{
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
x = (x >> 16) ^ x;
|
x = (x >> 16) ^ x;
|
||||||
@@ -28,7 +35,6 @@ inline bool has_flag(int flags, int flag)
|
|||||||
return (flags & flag) != 0;
|
return (flags & flag) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline versors euler_to_quat(float x, float y, float z)
|
inline versors euler_to_quat(float x, float y, float z)
|
||||||
{
|
{
|
||||||
versors qx = glms_quatv(glm_rad(x), (vec3s){1.0f, 0.0f, 0.0f});
|
versors qx = glms_quatv(glm_rad(x), (vec3s){1.0f, 0.0f, 0.0f});
|
||||||
|
|||||||
77
header/Common/String.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#ifndef STRING_H
|
||||||
|
#define STRING_H
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static inline bool is_absolute_path(const char* path)
|
||||||
|
{
|
||||||
|
if (!path || !*path) return false;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// 1) Drive-letter paths: "C:\…", "D:/…"
|
||||||
|
if (isalpha((unsigned char)path[0]) &&
|
||||||
|
path[1] == ':' &&
|
||||||
|
(path[2] == '\\' || path[2] == '/'))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) UNC paths: "\\server\share\…"
|
||||||
|
if (path[0] == '\\' && path[1] == '\\')
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
// POSIX: anything starting with '/'
|
||||||
|
return path[0] == '/';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void get_path_directory(const char* path, char* out, size_t out_size)
|
||||||
|
{
|
||||||
|
if (path == NULL || out == NULL || out_size == 0)
|
||||||
|
{
|
||||||
|
if (out && out_size > 0)
|
||||||
|
{
|
||||||
|
out[0] = '\0'; // ensure output is empty on invalid input
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* last_slash = strrchr(path, '/');
|
||||||
|
|
||||||
|
if (!last_slash)
|
||||||
|
{
|
||||||
|
if (out_size > 0)
|
||||||
|
out[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dir_len = (size_t)(last_slash - path);
|
||||||
|
|
||||||
|
if (dir_len >= out_size)
|
||||||
|
{
|
||||||
|
dir_len = out_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out, path, dir_len);
|
||||||
|
out[dir_len] = '/';
|
||||||
|
out[dir_len + 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void string_join(const char* a, const char* b, char* out, size_t out_size)
|
||||||
|
{
|
||||||
|
if (a == NULL || b == NULL || out == NULL || out_size == 0) return;
|
||||||
|
|
||||||
|
size_t a_len = strlen(a);
|
||||||
|
size_t b_len = strlen(b);
|
||||||
|
|
||||||
|
if (a_len + b_len + 1 >= out_size) return; // +1 for null terminator
|
||||||
|
|
||||||
|
strcpy(out, a);
|
||||||
|
strcat(out, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // STRING_H
|
||||||
@@ -19,57 +19,62 @@ inline void quad_create(vec3s center, vec3s forward, vec3s up, float size, uint8
|
|||||||
vec3s bottom_right = glms_vec3_sub(temp_add, scaled_up);
|
vec3s bottom_right = glms_vec3_sub(temp_add, scaled_up);
|
||||||
vec3s bottom_left = glms_vec3_sub(temp_sub, scaled_up);
|
vec3s bottom_left = glms_vec3_sub(temp_sub, scaled_up);
|
||||||
|
|
||||||
triangle_create(top_left, top_right, bottom_left, material_id, collection);
|
vertex_t vertex_1 = {.position = top_left, .normal = forward, .uv = {0.0f, 0.0f}};
|
||||||
triangle_create(top_right, bottom_right, bottom_left, material_id, collection);
|
vertex_t vertex_2 = {.position = top_right, .normal = forward, .uv = {1.0f, 0.0f}};
|
||||||
|
vertex_t vertex_3 = {.position = bottom_right, .normal = forward, .uv = {1.0f, 1.0f}};
|
||||||
|
vertex_t vertex_4 = {.position = bottom_left, .normal = forward, .uv = {0.0f, 1.0f}};
|
||||||
|
|
||||||
|
triangle_create(vertex_1, vertex_2, vertex_4, material_id, collection);
|
||||||
|
triangle_create(vertex_2, vertex_3, vertex_4, material_id, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void sphere_create(vec3s center, float radius, uint8_t material_id, triangle_collection_t* collection)
|
// inline void sphere_create(vec3s center, float radius, uint8_t material_id, triangle_collection_t* collection)
|
||||||
{
|
// {
|
||||||
int segments = 16;
|
// int segments = 16;
|
||||||
int rings = 16;
|
// int rings = 16;
|
||||||
|
//
|
||||||
for (int i = 0; i < rings; i++)
|
// for (int i = 0; i < rings; i++)
|
||||||
{
|
// {
|
||||||
float theta1 = (float)i / (float)rings * (float)M_PI;
|
// float theta1 = (float)i / (float)rings * (float)M_PI;
|
||||||
float theta2 = (float)(i + 1) / (float)rings * (float)M_PI;
|
// float theta2 = (float)(i + 1) / (float)rings * (float)M_PI;
|
||||||
|
//
|
||||||
for (int j = 0; j < segments; j++)
|
// for (int j = 0; j < segments; j++)
|
||||||
{
|
// {
|
||||||
float phi1 = (float)j / (float)segments * 2.0f * (float)M_PI;
|
// float phi1 = (float)j / (float)segments * 2.0f * (float)M_PI;
|
||||||
float phi2 = (float)(j + 1) / (float)segments * 2.0f * (float)M_PI;
|
// float phi2 = (float)(j + 1) / (float)segments * 2.0f * (float)M_PI;
|
||||||
|
//
|
||||||
vec3s p1 = {
|
// vec3s p1 = {
|
||||||
center.x + radius * sinf(theta1) * cosf(phi1),
|
// center.x + radius * sinf(theta1) * cosf(phi1),
|
||||||
center.y + radius * cosf(theta1),
|
// center.y + radius * cosf(theta1),
|
||||||
center.z + radius * sinf(theta1) * sinf(phi1)
|
// center.z + radius * sinf(theta1) * sinf(phi1)
|
||||||
};
|
// };
|
||||||
vec3s p2 = {
|
// vec3s p2 = {
|
||||||
center.x + radius * sinf(theta2) * cosf(phi1),
|
// center.x + radius * sinf(theta2) * cosf(phi1),
|
||||||
center.y + radius * cosf(theta2),
|
// center.y + radius * cosf(theta2),
|
||||||
center.z + radius * sinf(theta2) * sinf(phi1)
|
// center.z + radius * sinf(theta2) * sinf(phi1)
|
||||||
};
|
// };
|
||||||
vec3s p3 = {
|
// vec3s p3 = {
|
||||||
center.x + radius * sinf(theta2) * cosf(phi2),
|
// center.x + radius * sinf(theta2) * cosf(phi2),
|
||||||
center.y + radius * cosf(theta2),
|
// center.y + radius * cosf(theta2),
|
||||||
center.z + radius * sinf(theta2) * sinf(phi2)
|
// center.z + radius * sinf(theta2) * sinf(phi2)
|
||||||
};
|
// };
|
||||||
vec3s p4 = {
|
// vec3s p4 = {
|
||||||
center.x + radius * sinf(theta1) * cosf(phi2),
|
// center.x + radius * sinf(theta1) * cosf(phi2),
|
||||||
center.y + radius * cosf(theta1),
|
// center.y + radius * cosf(theta1),
|
||||||
center.z + radius * sinf(theta1) * sinf(phi2)
|
// center.z + radius * sinf(theta1) * sinf(phi2)
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
// vec3s n1 = glms_vec3_normalize(glms_vec3_sub(p1, center));
|
// // vec3s n1 = glms_vec3_normalize(glms_vec3_sub(p1, center));
|
||||||
// vec3s n2 = glms_vec3_normalize(glms_vec3_sub(p2, center));
|
// // vec3s n2 = glms_vec3_normalize(glms_vec3_sub(p2, center));
|
||||||
// vec3s n3 = glms_vec3_normalize(glms_vec3_sub(p3, center));
|
// // vec3s n3 = glms_vec3_normalize(glms_vec3_sub(p3, center));
|
||||||
// vec3s n4 = glms_vec3_normalize(glms_vec3_sub(p4, center));
|
// // vec3s n4 = glms_vec3_normalize(glms_vec3_sub(p4, center));
|
||||||
|
//
|
||||||
// triangle_create_with_normals(p3, p2, p1, n3, n2, n1, material_id, collection);
|
// // triangle_create_with_normals(p3, p2, p1, n3, n2, n1, material_id, collection);
|
||||||
// triangle_create_with_normals(p3, p1, p4, n3, n1, n4, material_id, collection);
|
// // triangle_create_with_normals(p3, p1, p4, n3, n1, n4, material_id, collection);
|
||||||
triangle_create(p3, p2, p1, material_id, collection);
|
// triangle_create(p3, p2, p1, material_id, collection);
|
||||||
triangle_create(p3, p1, p4, material_id, collection);
|
// triangle_create(p3, p1, p4, material_id, collection);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
#endif // GEOMETRY_UTILITIES_H
|
#endif // GEOMETRY_UTILITIES_H
|
||||||
|
|||||||
@@ -3,22 +3,25 @@
|
|||||||
|
|
||||||
#include "Material/Material.h"
|
#include "Material/Material.h"
|
||||||
#include "Geometry/Triangle.h"
|
#include "Geometry/Triangle.h"
|
||||||
|
#include "Rendering/Scene.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// TODO: Currently transformation does not work because we store every triangle in to the same buffer and when bulding the bvh, we only consider that triangle buffer.
|
// TODO: Currently transformation does not work because we store every triangle in to the same buffer and when bulding the bvh, we only consider that triangle buffer.
|
||||||
// One solution for this is we can have two levels of bvh, one for scene and one for each mesh. The mesh level bvh will apply the transformation to the triangles.
|
// One solution for this is we can have two levels of bvh, one for scene and one for each mesh. The mesh level bvh will apply the transformation to the triangles.
|
||||||
// The scene level bvh onlt tells the ray which mesh to check and the mesh level bvh will tell the ray which triangle to check.
|
// The scene level bvh only tells the ray which mesh to check and the mesh level bvh will tell the ray which triangle to check.
|
||||||
// For instancing, we may need another mesh_model_t struct to store the actual bvh and triangle data(like id and size), and each mesh_entity_t will have a transformation matrix and the id to that mesh_model_t.
|
// For instancing, we may need another mesh_model_t struct to store the actual bvh and triangle data(like id and size), and each mesh_entity_t will have a transformation matrix and the id to that mesh_model_t.
|
||||||
// This way we can share the same triangle and bvh for multiple instances of the same mesh, and we can also apply different transformations to each instance.
|
// This way we can share the same triangle and bvh for multiple instances of the same mesh, and we can also apply different transformations to each instance.
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
mat4s local_to_world;
|
mat4s local_to_world;
|
||||||
uint64_t id;
|
uint64_t triangle_id;
|
||||||
uint64_t size;
|
uint64_t triangle_count;
|
||||||
|
uint16_t material_id;
|
||||||
|
uint16_t material_count;
|
||||||
} mesh_entity_t;
|
} mesh_entity_t;
|
||||||
|
|
||||||
//HACK: We should handle the material from mesh, not user input.
|
//HACK: We should handle the material from mesh, not user input.
|
||||||
mesh_entity_t mesh_load(const char* filename, uint8_t material_id, triangle_collection_t* triangles, material_collection_t* materials);
|
mesh_entity_t mesh_load(const char* filename, scene_t* scene);
|
||||||
|
|
||||||
#endif // MESH_H
|
#endif // MESH_H
|
||||||
|
|||||||
@@ -7,16 +7,19 @@
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3s point_1;
|
vec3s position;
|
||||||
vec3s point_2;
|
vec3s normal;
|
||||||
vec3s point_3;
|
vec3s color;
|
||||||
vec3s normal_1;
|
vec2s uv;
|
||||||
vec3s normal_2;
|
} vertex_t;
|
||||||
vec3s normal_3;
|
|
||||||
vec3s normal_face;
|
typedef struct
|
||||||
|
{
|
||||||
|
vertex_t vertices[3];
|
||||||
|
vec3s face_normal;
|
||||||
|
|
||||||
uint8_t material_id;
|
uint8_t material_id;
|
||||||
}triangle_t;
|
} triangle_t;
|
||||||
|
|
||||||
//TODO: Handle triangle remove, we can use something like sparse set.
|
//TODO: Handle triangle remove, we can use something like sparse set.
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -25,27 +28,24 @@ typedef struct
|
|||||||
uint64_t size;
|
uint64_t size;
|
||||||
|
|
||||||
triangle_t* buffer;
|
triangle_t* buffer;
|
||||||
}triangle_collection_t;
|
} triangle_collection_t;
|
||||||
|
|
||||||
bool triangle_collection_init(triangle_collection_t* triangles, size_t size);
|
bool triangle_collection_init(size_t size, triangle_collection_t* triangles);
|
||||||
void triangle_collection_resize(triangle_collection_t* collection, size_t size);
|
void triangle_collection_resize(triangle_collection_t* collection, size_t size);
|
||||||
void triangle_collection_free(triangle_collection_t* collection);
|
void triangle_collection_free(triangle_collection_t* collection);
|
||||||
|
|
||||||
void triangle_create_with_normals(vec3s point1, vec3s point2, vec3s point3,
|
void triangle_create(vertex_t v1, vertex_t v2, vertex_t v3, uint8_t material_id, triangle_collection_t* collection);
|
||||||
vec3s normal1, vec3s normal2, vec3s normal3,
|
|
||||||
uint8_t material_id, triangle_collection_t* collection);
|
|
||||||
void triangle_create(vec3s point1, vec3s point2, vec3s point3, uint8_t material_id, triangle_collection_t* collection);
|
|
||||||
|
|
||||||
inline vec3s triangle_centroid(const triangle_t triangle)
|
inline vec3s triangle_centroid(const triangle_t triangle)
|
||||||
{
|
{
|
||||||
return glms_vec3_scale(glms_vec3_add(glms_vec3_add(triangle.point_1, triangle.point_2), triangle.point_3), 1.0f / 3.0f);
|
return glms_vec3_scale(glms_vec3_add(glms_vec3_add(triangle.vertices[0].position, triangle.vertices[1].position), triangle.vertices[2].position), 1.0f / 3.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline aabb_t compute_bounds_triangle(triangle_t triangle)
|
inline aabb_t compute_bounds_triangle(triangle_t triangle)
|
||||||
{
|
{
|
||||||
aabb_t bounds;
|
aabb_t bounds;
|
||||||
bounds.min = glms_vec3_minv(triangle.point_1, glms_vec3_minv(triangle.point_2, triangle.point_3));
|
bounds.min = glms_vec3_minv(triangle.vertices[0].position, glms_vec3_minv(triangle.vertices[1].position, triangle.vertices[2].position));
|
||||||
bounds.max = glms_vec3_maxv(triangle.point_1, glms_vec3_maxv(triangle.point_2, triangle.point_3));
|
bounds.max = glms_vec3_maxv(triangle.vertices[0].position, glms_vec3_maxv(triangle.vertices[1].position, triangle.vertices[2].position));
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,18 @@
|
|||||||
#include "Material/Material.h"
|
#include "Material/Material.h"
|
||||||
#include "cglm/struct/vec3.h"
|
#include "cglm/struct/vec3.h"
|
||||||
|
|
||||||
|
#define SKY_DATA_CAPACITY 64
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SKY_TYPE_CONSTANT,
|
||||||
|
} sky_type_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3s normal;
|
vec3s normal;
|
||||||
vec3s hit_point;
|
vec3s hit_point;
|
||||||
vec3s wo;
|
vec3s wo;
|
||||||
|
vec2s uv;
|
||||||
|
|
||||||
uint16_t bounce_depth;
|
uint16_t bounce_depth;
|
||||||
|
|
||||||
@@ -19,12 +26,22 @@ typedef struct
|
|||||||
const material_t* material;
|
const material_t* material;
|
||||||
} light_shading_context_t;
|
} light_shading_context_t;
|
||||||
|
|
||||||
|
#ifdef __STDC_ALIGN__
|
||||||
|
#define SKY_ALIGN _Alignof(max_align_t)
|
||||||
|
#else
|
||||||
|
#define SKY_ALIGN (sizeof(void*))
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef vec3s (*evaluate_bsdf_sky_f) (const void* data, const light_shading_context_t* context, vec3s throughput, uint32_t index);
|
typedef vec3s (*evaluate_bsdf_sky_f) (const void* data, const light_shading_context_t* context, vec3s throughput, uint32_t index);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
evaluate_bsdf_sky_f evaluate_bsdf_sky;
|
evaluate_bsdf_sky_f evaluate_bsdf_sky;
|
||||||
const void* data;
|
sky_type_t type;
|
||||||
|
uint16_t data_size;
|
||||||
|
|
||||||
|
_Alignas(SKY_ALIGN)
|
||||||
|
char data[SKY_DATA_CAPACITY];
|
||||||
} sky_light_t;
|
} sky_light_t;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SKY_LIGHT_H
|
#define SKY_LIGHT_H
|
||||||
|
|
||||||
#include "Light.h"
|
#include "Light.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -13,10 +14,14 @@ vec3s evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* c
|
|||||||
|
|
||||||
inline sky_light_t sky_create_constant_sky(const constant_sky_data_t* data)
|
inline sky_light_t sky_create_constant_sky(const constant_sky_data_t* data)
|
||||||
{
|
{
|
||||||
return (sky_light_t){
|
sky_light_t light = {
|
||||||
.evaluate_bsdf_sky = evaluate_bsdf_const_sky,
|
.evaluate_bsdf_sky = evaluate_bsdf_const_sky,
|
||||||
.data = data,
|
.type = SKY_TYPE_CONSTANT,
|
||||||
|
.data_size = sizeof(constant_sky_data_t),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
memcpy(light.data, data, sizeof(constant_sky_data_t));
|
||||||
|
return light;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SKY_LIGHT_H
|
#endif // SKY_LIGHT_H
|
||||||
|
|||||||
@@ -4,26 +4,33 @@
|
|||||||
#include "Algorithm/Sobol.h"
|
#include "Algorithm/Sobol.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
#define PROPERTY_SIZE 64
|
||||||
|
#define INVALID_MATERIAL_ID 255
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3s normal;
|
vec3s normal;
|
||||||
vec3s position;
|
vec3s position;
|
||||||
vec3s wi;
|
vec3s wi;
|
||||||
vec3s wo;
|
vec3s wo;
|
||||||
|
vec2s uv;
|
||||||
} shading_context_t;
|
} shading_context_t;
|
||||||
|
|
||||||
typedef vec3s (*sample_bsdf_f)(const void* data, vec3s normal, vec3s wo, uint32_t index, uint32_t bounce, float* pdf_out);
|
typedef void (*compute_surface_data_f)(const shading_context_t* context, const void* properties, void* surface_data_out);
|
||||||
typedef float (*sample_bsdf_pdf_f)(const void* data, vec3s normal, vec3s wo, vec3s wi);
|
|
||||||
typedef vec3s (*evaluate_bsdf_f)(const shading_context_t* context, const void* data);
|
typedef vec3s (*sample_bsdf_f)(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data, uint32_t index, uint32_t bounce, float* pdf_out);
|
||||||
|
typedef float (*sample_bsdf_pdf_f)(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data);
|
||||||
|
typedef vec3s (*evaluate_bsdf_f)(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
char properties[PROPERTY_SIZE];
|
||||||
// TODO: alpha, displacement, etc.
|
// TODO: alpha, displacement, etc.
|
||||||
vec3s emission; // We have to have emission outside of data because data is only for bsdf, and emission is not part of bsdf. Maybe another shading properties struct is needed if the number of properties increases.
|
vec3s emission; // We have to have emission outside of data because data is only for bsdf, and emission is not part of bsdf. Maybe another shading properties struct is needed if the number of properties increases.
|
||||||
|
compute_surface_data_f compute_surface_data;
|
||||||
sample_bsdf_f sample_bsdf;
|
sample_bsdf_f sample_bsdf;
|
||||||
sample_bsdf_pdf_f sample_bsdf_pdf;
|
sample_bsdf_pdf_f sample_bsdf_pdf;
|
||||||
evaluate_bsdf_f evaluate_bsdf;
|
evaluate_bsdf_f evaluate_bsdf;
|
||||||
void* data;
|
|
||||||
} material_t;
|
} material_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -40,14 +47,14 @@ typedef struct
|
|||||||
material_t* buffer;
|
material_t* buffer;
|
||||||
} material_collection_t;
|
} material_collection_t;
|
||||||
|
|
||||||
bool material_collection_init(size_t size, material_collection_t* materials);
|
bool material_collection_init(uint8_t size, material_collection_t* materials);
|
||||||
void material_collection_resize(material_collection_t* materials, size_t size);
|
void material_collection_resize(material_collection_t* materials, size_t size);
|
||||||
void material_collection_free(material_collection_t* materials);
|
void material_collection_free(material_collection_t* materials);
|
||||||
|
|
||||||
material_entity_t material_create(sample_bsdf_f sample, sample_bsdf_pdf_f sample_pdf, evaluate_bsdf_f evaluate, void* data, size_t size_of_data, 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, uint32_t sample_index, uint32_t bounce, float* pdf_out);
|
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);
|
float sample_material_bsdf_pdf(const material_t* material, vec3s normal, vec3s wo, vec3s wi, vec2s uv);
|
||||||
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
|
||||||
|
|||||||
@@ -2,22 +2,41 @@
|
|||||||
#define SIMPLE_LIT_H
|
#define SIMPLE_LIT_H
|
||||||
|
|
||||||
#include "Material.h"
|
#include "Material.h"
|
||||||
#include "cglm/types-struct.h"
|
#include "Rendering/Texture.h"
|
||||||
|
#include "cglm/struct/vec3.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3s albedo;
|
vec3s albedo;
|
||||||
float roughness;
|
float roughness;
|
||||||
float metallic;
|
float metallic;
|
||||||
}simple_lit_data_t;
|
} simple_lit_data_t;
|
||||||
|
|
||||||
vec3s sample_bsdf_simple_lit(const void* data, vec3s normal, vec3s wo, uint32_t sample_index, uint32_t bounce, float* pdf_out);
|
typedef struct
|
||||||
vec3s evaluate_bsdf_simple_lit(const shading_context_t* context, const void* data);
|
|
||||||
float sample_bsdf_pdf_simple_lit(const void* data, vec3s normal, vec3s wo, vec3s wi);
|
|
||||||
|
|
||||||
inline material_entity_t material_create_simple_lit(simple_lit_data_t* lit_data, material_collection_t* collection)
|
|
||||||
{
|
{
|
||||||
return material_create(sample_bsdf_simple_lit, sample_bsdf_pdf_simple_lit, evaluate_bsdf_simple_lit, lit_data, sizeof(simple_lit_data_t), collection);
|
vec3s albedo;
|
||||||
|
float roughness;
|
||||||
|
float metallic;
|
||||||
|
|
||||||
|
const texture_t* albedo_texture;
|
||||||
|
const texture_t* roughness_texture;
|
||||||
|
const texture_t* metallic_texture;
|
||||||
|
} simple_lit_properties_t;
|
||||||
|
|
||||||
|
void simple_lit_data_default(const shading_context_t* context, const void* properties, void* data_out);
|
||||||
|
|
||||||
|
vec3s sample_bsdf_simple_lit(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data, uint32_t sample_index, uint32_t bounce, float* pdf_out);
|
||||||
|
vec3s evaluate_bsdf_simple_lit(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data);
|
||||||
|
float sample_bsdf_pdf_simple_lit(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data);
|
||||||
|
|
||||||
|
inline material_entity_t material_create_simple_lit(const simple_lit_properties_t* properties, compute_surface_data_f surface_data, material_collection_t* collection)
|
||||||
|
{
|
||||||
|
return material_create(properties, sizeof(simple_lit_properties_t), surface_data, sample_bsdf_simple_lit, sample_bsdf_pdf_simple_lit, evaluate_bsdf_simple_lit, collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline material_entity_t material_create_simple_lit_default(const simple_lit_properties_t* properties, material_collection_t* collection)
|
||||||
|
{
|
||||||
|
return material_create(properties, sizeof(simple_lit_properties_t), simple_lit_data_default, sample_bsdf_simple_lit, sample_bsdf_pdf_simple_lit, evaluate_bsdf_simple_lit, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SIMPLE_LIT_H
|
#endif // SIMPLE_LIT_H
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ typedef enum
|
|||||||
DEBUG_NONE = 0,
|
DEBUG_NONE = 0,
|
||||||
DEBUG_BVH = 1,
|
DEBUG_BVH = 1,
|
||||||
DEBUG_SOBOL = 2,
|
DEBUG_SOBOL = 2,
|
||||||
|
DEBUG_UV = 3,
|
||||||
} debug_flag_t;
|
} debug_flag_t;
|
||||||
|
|
||||||
static const vec4s DEBUG_COLOR_BVH = {0.0f, 1.0f, 0.0f, 0.005f}; // Green
|
static const vec4s DEBUG_COLOR_BVH = {0.0f, 1.0f, 0.0f, 0.005f}; // Green
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
#include "Lighting/Light.h"
|
#include "Lighting/Light.h"
|
||||||
#include "Material/Material.h"
|
#include "Material/Material.h"
|
||||||
#include "RenderTarget.h"
|
|
||||||
#include "Geometry/Triangle.h"
|
#include "Geometry/Triangle.h"
|
||||||
|
#include "Rendering/RenderTarget.h"
|
||||||
|
#include "Rendering/Texture.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -14,10 +15,11 @@ typedef struct
|
|||||||
bvh_tree_t bvh_tree;
|
bvh_tree_t bvh_tree;
|
||||||
triangle_collection_t triangles;
|
triangle_collection_t triangles;
|
||||||
material_collection_t materials;
|
material_collection_t materials;
|
||||||
|
texture_collection_t textures;
|
||||||
light_collection_t lights;
|
light_collection_t lights;
|
||||||
} scene_t;
|
} scene_t;
|
||||||
|
|
||||||
bool scene_init(scene_t* scene, uint64_t triangle_count, uint8_t material_count, uint32_t punctual_light_count);
|
bool scene_init(scene_t* scene, uint64_t triangle_count, uint16_t texture_count, uint8_t material_count, uint32_t punctual_light_count);
|
||||||
bool scene_build_bvh(scene_t* scene);
|
bool scene_build_bvh(scene_t* scene);
|
||||||
void scene_free(scene_t* scene);
|
void scene_free(scene_t* scene);
|
||||||
|
|
||||||
|
|||||||
53
header/Rendering/Texture.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef TEXTURE_H
|
||||||
|
#define TEXTURE_H
|
||||||
|
|
||||||
|
#include "cglm/struct/vec4.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define INVALID_TEXTURE_ID UINT16_MAX
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
REPEAT,
|
||||||
|
CLAMP,
|
||||||
|
} wrap_mode_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
NEAREST,
|
||||||
|
LINEAR,
|
||||||
|
} filter_mode_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
wrap_mode_t wrap_mode;
|
||||||
|
filter_mode_t filter_mode;
|
||||||
|
uint8_t channel_count;
|
||||||
|
uint8_t* data;
|
||||||
|
} texture_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t count;
|
||||||
|
uint16_t size;
|
||||||
|
texture_t* buffer;
|
||||||
|
} texture_collection_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t id;
|
||||||
|
} texture_entity_t;
|
||||||
|
|
||||||
|
bool texture_collection_init(uint16_t size, texture_collection_t* textures);
|
||||||
|
void texture_collection_resize(texture_collection_t* textures, uint16_t size);
|
||||||
|
void texture_collection_free(texture_collection_t* textures);
|
||||||
|
|
||||||
|
texture_entity_t texture_load(const char* filename, bool srgb, texture_collection_t* textures);
|
||||||
|
vec4s texture_sample(const texture_t* texture, float u, float v);
|
||||||
|
void texture_free(texture_t* texture);
|
||||||
|
|
||||||
|
#endif // TEXTURE_H
|
||||||
@@ -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)
|
for (uint64_t i = start + 1; i < start + count; ++i)
|
||||||
{
|
{
|
||||||
triangle_index = primitive_indices[i];
|
triangle_index = primitive_indices[i];
|
||||||
aabb_growth(&bounds, triangles->buffer[triangle_index].point_1);
|
aabb_growth(&bounds, triangles->buffer[triangle_index].vertices[0].position);
|
||||||
aabb_growth(&bounds, triangles->buffer[triangle_index].point_2);
|
aabb_growth(&bounds, triangles->buffer[triangle_index].vertices[1].position);
|
||||||
aabb_growth(&bounds, triangles->buffer[triangle_index].point_3);
|
aabb_growth(&bounds, triangles->buffer[triangle_index].vertices[2].position);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bounds;
|
return bounds;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
|
|||||||
uint16_t depth = 0;
|
uint16_t depth = 0;
|
||||||
while (depth < max_depth)
|
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)
|
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);
|
float weight = power_heuristic(pdf_bsdf, pdf_nee);
|
||||||
sky_light = glms_vec3_scale(sky_light, weight);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +47,7 @@ vec4s path_trace(const scene_t* scene, ray_t ray, uint32_t sample_index, uint16_
|
|||||||
.normal = closest_hit.normal,
|
.normal = closest_hit.normal,
|
||||||
.hit_point = closest_hit.point,
|
.hit_point = closest_hit.point,
|
||||||
.wo = active_ray.direction,
|
.wo = active_ray.direction,
|
||||||
|
.uv = closest_hit.uv,
|
||||||
|
|
||||||
.bounce_depth = depth,
|
.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
|
// 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 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)
|
if (pdf_bsdf <= 0.0f)
|
||||||
{
|
{
|
||||||
break;
|
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 = {
|
shading_context_t shading_context = {
|
||||||
.normal = closest_hit.normal,
|
.normal = closest_hit.normal,
|
||||||
|
.position = closest_hit.point,
|
||||||
.wi = wi,
|
.wi = wi,
|
||||||
.wo = wo
|
.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));
|
||||||
@@ -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);
|
throughput = glms_vec3_scale(throughput, 1.0f / q);
|
||||||
}
|
}
|
||||||
|
|
||||||
active_ray.origin = BIAS_RAY_ORIGION(closest_hit.point, closest_hit.normal);
|
active_ray = ray_create(BIAS_RAY_ORIGION(closest_hit.point, closest_hit.normal), wi);
|
||||||
active_ray.direction = wi;
|
|
||||||
prev_normal = closest_hit.normal;
|
prev_normal = closest_hit.normal;
|
||||||
|
|
||||||
depth++;
|
depth++;
|
||||||
|
|||||||
@@ -1,21 +1,87 @@
|
|||||||
#include "algorithm/RayIntersection.h"
|
#include "Algorithm/RayIntersection.h"
|
||||||
|
#include "Common.h"
|
||||||
#include "Geometry/Triangle.h"
|
#include "Geometry/Triangle.h"
|
||||||
#include "cglm/struct/vec3.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.
|
// 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};
|
hit_result_t result = {0};
|
||||||
|
|
||||||
vec3s edge1 = glms_vec3_sub(triangle.point_2, triangle.point_1);
|
vec3s edge1 = glms_vec3_sub(triangle->vertices[1].position, triangle->vertices[0].position);
|
||||||
vec3s edge2 = glms_vec3_sub(triangle.point_3, triangle.point_2);
|
vec3s edge2 = glms_vec3_sub(triangle->vertices[2].position, triangle->vertices[1].position);
|
||||||
vec3s edge3 = glms_vec3_sub(triangle.point_1, triangle.point_3);
|
vec3s edge3 = glms_vec3_sub(triangle->vertices[0].position, triangle->vertices[2].position);
|
||||||
|
|
||||||
vec3s normal_face = triangle.normal_face;
|
vec3s normal = triangle->face_normal;
|
||||||
float n_dot_r = glms_vec3_dot(normal_face, ray.direction);
|
float n_dot_r = glms_vec3_dot(normal, ray->direction);
|
||||||
if (n_dot_r > 0.0f)
|
if (n_dot_r > 0.0f)
|
||||||
{
|
{
|
||||||
normal_face = glms_vec3_negate(normal_face);
|
normal = glms_vec3_negate(normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// triangle is parallel to the ray
|
// 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
|
// 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;
|
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
|
// Check if the intersection point is inside the triangle using barycentric coordinates
|
||||||
|
vec3s vp = glms_vec3_sub(intersection_point, triangle->vertices[0].position);
|
||||||
vec3s vp = glms_vec3_sub(intersection_point, triangle.point_1);
|
vec3s vp2 = glms_vec3_sub(intersection_point, triangle->vertices[1].position);
|
||||||
vec3s vp2 = glms_vec3_sub(intersection_point, triangle.point_2);
|
vec3s vp3 = glms_vec3_sub(intersection_point, triangle->vertices[2].position);
|
||||||
vec3s vp3 = glms_vec3_sub(intersection_point, triangle.point_3);
|
|
||||||
|
|
||||||
vec3s c1 = glms_vec3_cross(edge1, vp);
|
vec3s c1 = glms_vec3_cross(edge1, vp);
|
||||||
vec3s c2 = glms_vec3_cross(edge2, vp2);
|
vec3s c2 = glms_vec3_cross(edge2, vp2);
|
||||||
vec3s c3 = glms_vec3_cross(edge3, vp3);
|
vec3s c3 = glms_vec3_cross(edge3, vp3);
|
||||||
|
|
||||||
if (glms_vec3_dot(triangle.normal_face, c1) < 0.0f
|
float n_dot_c1 = glms_vec3_dot(normal, c1);
|
||||||
|| glms_vec3_dot(triangle.normal_face, c2) < 0.0f
|
float n_dot_c2 = glms_vec3_dot(normal, c2);
|
||||||
|| glms_vec3_dot(triangle.normal_face, c3) < 0.0f)
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Normal interpolation
|
// 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.hit = true;
|
||||||
result.point = intersection_point;
|
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;
|
result.distance = distance;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
bool ray_intersect_aabb(ray_t ray, aabb_t aabb, float* enter_out, float* exit_out)
|
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);
|
hit_result_t result = {0};
|
||||||
float t_near = -FLT_MIN;
|
|
||||||
float t_far = FLT_MAX;
|
|
||||||
|
|
||||||
// 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öller–Trumbore
|
||||||
|
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;
|
return result;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enter_out)
|
// merge X and Y
|
||||||
*enter_out = t_near;
|
float t0 = tx_min > ty_min ? tx_min : ty_min;
|
||||||
if (exit_out)
|
float t1 = tx_max < ty_max ? tx_max : ty_max;
|
||||||
*exit_out = t_far;
|
|
||||||
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -117,7 +276,7 @@ static inline float distance_to_aabb(vec3s point, aabb_t aabb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use a stack to avoid recursion.
|
// 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)
|
hit_result_t* best_hit_out)
|
||||||
{
|
{
|
||||||
const bvh_node_t* node = &bvh_nodes[node_index];
|
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++)
|
for (uint32_t i = 0; i < node->primitive_count; i++)
|
||||||
{
|
{
|
||||||
uint64_t triangle_index = primitive_indices[node->start_index + 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)
|
if (hit_result.hit && hit_result.distance < *closest_out)
|
||||||
{
|
{
|
||||||
hit_result.triangle_id = triangle_index;
|
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};
|
hit_result_t result = {0};
|
||||||
float closest = FLT_MAX;
|
float closest = FLT_MAX;
|
||||||
|
|||||||
@@ -1,23 +1,72 @@
|
|||||||
#include "Geometry/Mesh.h"
|
#include "Geometry/Mesh.h"
|
||||||
#include "Geometry/Triangle.h"
|
#include "Common/String.h"
|
||||||
|
#include "Material/SimpleLit.h"
|
||||||
#include "assimp/cimport.h"
|
#include "assimp/cimport.h"
|
||||||
#include "assimp/scene.h"
|
#include "assimp/scene.h"
|
||||||
#include "assimp/postprocess.h"
|
#include "assimp/postprocess.h"
|
||||||
|
|
||||||
mesh_entity_t mesh_load(const char* filename, uint8_t material_id, triangle_collection_t* triangles, material_collection_t* materials)
|
mesh_entity_t mesh_load(const char* filename, scene_t* scene)
|
||||||
{
|
{
|
||||||
mesh_entity_t entity = {0};
|
mesh_entity_t entity = {0};
|
||||||
|
|
||||||
const C_STRUCT aiScene* scene = aiImportFile(filename, aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_GenSmoothNormals);
|
const struct aiScene* mesh_scene = aiImportFile(filename, aiProcessPreset_TargetRealtime_Quality);
|
||||||
if (scene == NULL)
|
if (mesh_scene == NULL)
|
||||||
{
|
{
|
||||||
perror(aiGetErrorString());
|
perror(aiGetErrorString());
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < scene->mNumMeshes; i++)
|
entity.triangle_id = scene->triangles.count;
|
||||||
|
entity.material_id = scene->materials.count;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mesh_scene->mNumMaterials; i++)
|
||||||
{
|
{
|
||||||
struct aiMesh* mesh = scene->mMeshes[i];
|
const struct aiMaterial* src = mesh_scene->mMaterials[i];
|
||||||
|
|
||||||
|
struct aiColor4D base_color;
|
||||||
|
aiGetMaterialColor(src, AI_MATKEY_COLOR_DIFFUSE, &base_color);
|
||||||
|
|
||||||
|
float smoothness = 0.5f;
|
||||||
|
aiGetMaterialFloat(src, AI_MATKEY_SHININESS, &smoothness);
|
||||||
|
|
||||||
|
texture_t* albedo_texture = NULL;
|
||||||
|
if (aiGetMaterialTextureCount(src, aiTextureType_DIFFUSE) > 0)
|
||||||
|
{
|
||||||
|
struct aiString path;
|
||||||
|
if (AI_SUCCESS == aiGetMaterialTexture(src, aiTextureType_DIFFUSE, 0, &path, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||||
|
{
|
||||||
|
if (!is_absolute_path(path.data))
|
||||||
|
{
|
||||||
|
char directory[1024];
|
||||||
|
get_path_directory(filename, directory, 1024);
|
||||||
|
char image_path[1024];
|
||||||
|
memcpy(image_path, path.data, 1024);
|
||||||
|
string_join(directory, image_path, path.data, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_entity_t entity = texture_load(path.data, true, &scene->textures);
|
||||||
|
if (entity.id != INVALID_TEXTURE_ID)
|
||||||
|
{
|
||||||
|
albedo_texture = &scene->textures.buffer[entity.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_lit_properties_t prop =
|
||||||
|
{
|
||||||
|
.albedo = {base_color.r, base_color.g, base_color.b},
|
||||||
|
.roughness = 1.0f - smoothness,
|
||||||
|
.metallic = 0.0f,
|
||||||
|
|
||||||
|
.albedo_texture = albedo_texture,
|
||||||
|
};
|
||||||
|
|
||||||
|
material_create_simple_lit_default(&prop, &scene->materials);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mesh_scene->mNumMeshes; i++)
|
||||||
|
{
|
||||||
|
const struct aiMesh* mesh = mesh_scene->mMeshes[i];
|
||||||
|
|
||||||
//TODO: Handle all primitive types, not just triangles
|
//TODO: Handle all primitive types, not just triangles
|
||||||
if (mesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
|
if (mesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
|
||||||
@@ -25,9 +74,11 @@ mesh_entity_t mesh_load(const char* filename, uint8_t material_id, triangle_coll
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_uv = mesh->mTextureCoords[0] != NULL && mesh->mNumUVComponents[0] >= 2;
|
||||||
|
|
||||||
for (uint32_t j = 0; j < mesh->mNumFaces; j++)
|
for (uint32_t j = 0; j < mesh->mNumFaces; j++)
|
||||||
{
|
{
|
||||||
struct aiFace* face = &mesh->mFaces[j];
|
const struct aiFace* face = &mesh->mFaces[j];
|
||||||
if (face->mNumIndices != 3)
|
if (face->mNumIndices != 3)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -36,7 +87,7 @@ mesh_entity_t mesh_load(const char* filename, uint8_t material_id, triangle_coll
|
|||||||
uint32_t index1 = face->mIndices[0];
|
uint32_t index1 = face->mIndices[0];
|
||||||
uint32_t index2 = face->mIndices[1];
|
uint32_t index2 = face->mIndices[1];
|
||||||
uint32_t index3 = face->mIndices[2];
|
uint32_t index3 = face->mIndices[2];
|
||||||
|
|
||||||
vec3s point1 = {
|
vec3s point1 = {
|
||||||
mesh->mVertices[index1].x,
|
mesh->mVertices[index1].x,
|
||||||
mesh->mVertices[index1].y,
|
mesh->mVertices[index1].y,
|
||||||
@@ -53,6 +104,20 @@ mesh_entity_t mesh_load(const char* filename, uint8_t material_id, triangle_coll
|
|||||||
mesh->mVertices[index3].z
|
mesh->mVertices[index3].z
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vec2s uv1 = {0.0f, 0.0f};
|
||||||
|
vec2s uv2 = {0.0f, 0.0f};
|
||||||
|
vec2s uv3 = {0.0f, 0.0f};
|
||||||
|
if (has_uv)
|
||||||
|
{
|
||||||
|
struct aiVector3D const* tc = mesh->mTextureCoords[0];
|
||||||
|
uv1.x = tc[index1].x;
|
||||||
|
uv1.y = tc[index1].y;
|
||||||
|
uv2.x = tc[index2].x;
|
||||||
|
uv2.y = tc[index2].y;
|
||||||
|
uv3.x = tc[index3].x;
|
||||||
|
uv3.y = tc[index3].y;
|
||||||
|
}
|
||||||
|
|
||||||
vec3s normal1 = {
|
vec3s normal1 = {
|
||||||
mesh->mNormals[index1].x,
|
mesh->mNormals[index1].x,
|
||||||
mesh->mNormals[index1].y,
|
mesh->mNormals[index1].y,
|
||||||
@@ -69,18 +134,15 @@ mesh_entity_t mesh_load(const char* filename, uint8_t material_id, triangle_coll
|
|||||||
mesh->mNormals[index3].z
|
mesh->mNormals[index3].z
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO: Handle materials, we use OpenPBR standard for parameter naming
|
vertex_t vertex1 = {.position = point1, .normal = normal1, .uv = uv1};
|
||||||
|
vertex_t vertex2 = {.position = point2, .normal = normal2, .uv = uv2};
|
||||||
|
vertex_t vertex3 = {.position = point3, .normal = normal3, .uv = uv3};
|
||||||
|
|
||||||
// uint32_t properties_count = scene->mMaterials[mesh->mMaterialIndex]->mNumProperties;
|
triangle_create(vertex1, vertex2, vertex3, entity.material_id + mesh->mMaterialIndex, &scene->triangles);
|
||||||
// C_STRUCT aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
|
entity.triangle_count++;
|
||||||
// for (uint32_t p = 0; p < properties_count; p++)
|
|
||||||
// {
|
|
||||||
// material->mProperties[p]->mKey;
|
|
||||||
// }
|
|
||||||
|
|
||||||
triangle_create_with_normals(point1, point2, point3, normal1, normal2, normal3, material_id, triangles);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aiReleaseImport(mesh_scene);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "Geometry/Triangle.h"
|
#include "Geometry/Triangle.h"
|
||||||
|
|
||||||
bool triangle_collection_init(triangle_collection_t* triangles, size_t size)
|
bool triangle_collection_init(size_t size, triangle_collection_t* triangles)
|
||||||
{
|
{
|
||||||
if (size > UINT64_MAX)
|
if (size > UINT64_MAX)
|
||||||
{
|
{
|
||||||
@@ -45,37 +45,23 @@ void triangle_collection_free(triangle_collection_t* collection)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void triangle_create_with_normals(vec3s point1, vec3s point2, vec3s point3,
|
void triangle_create(vertex_t v1, vertex_t v2, vertex_t v3, uint8_t material_id, triangle_collection_t* collection)
|
||||||
vec3s normal1, vec3s normal2, vec3s normal3,
|
|
||||||
uint8_t material_id, triangle_collection_t* collection)
|
|
||||||
{
|
{
|
||||||
|
vec3s edge1 = glms_vec3_sub(v2.position, v1.position);
|
||||||
|
vec3s edge2 = glms_vec3_sub(v3.position, v1.position);
|
||||||
|
vec3s normal = glms_vec3_normalize(glms_vec3_cross(edge1, edge2));
|
||||||
|
|
||||||
|
triangle_t triangle = {
|
||||||
|
.vertices = {v1, v2, v3},
|
||||||
|
.face_normal = normal,
|
||||||
|
.material_id = material_id,
|
||||||
|
};
|
||||||
|
|
||||||
if (collection->count >= collection->size)
|
if (collection->count >= collection->size)
|
||||||
{
|
{
|
||||||
triangle_collection_resize(collection, collection->size * 2);
|
triangle_collection_resize(collection, collection->size * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
triangle_t triangle;
|
|
||||||
triangle.point_1 = point1;
|
|
||||||
triangle.point_2 = point2;
|
|
||||||
triangle.point_3 = point3;
|
|
||||||
triangle.material_id = material_id;
|
|
||||||
|
|
||||||
triangle.normal_1 = normal1;
|
|
||||||
triangle.normal_2 = normal2;
|
|
||||||
triangle.normal_3 = normal3;
|
|
||||||
|
|
||||||
vec3s edge1 = glms_vec3_sub(point2, point1);
|
|
||||||
vec3s edge2 = glms_vec3_sub(point3, point1);
|
|
||||||
triangle.normal_face = glms_vec3_normalize(glms_vec3_cross(edge1, edge2));
|
|
||||||
|
|
||||||
collection->buffer[collection->count] = triangle;
|
collection->buffer[collection->count] = triangle;
|
||||||
collection->count++;
|
collection->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void triangle_create(vec3s point1, vec3s point2, vec3s point3, uint8_t material_id, triangle_collection_t* collection)
|
|
||||||
{
|
|
||||||
vec3s edge1 = glms_vec3_sub(point2, point1);
|
|
||||||
vec3s edge2 = glms_vec3_sub(point3, point1);
|
|
||||||
vec3s normal = glms_vec3_normalize(glms_vec3_cross(edge1, edge2));
|
|
||||||
triangle_create_with_normals(point1, point2, point3, normal, normal, normal, material_id, collection);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,14 +17,11 @@ vec3s evaluate_bsdf_directional(directional_light_t light, const light_shading_c
|
|||||||
return glms_vec3_zero();
|
return glms_vec3_zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
ray_t shadow_ray = {
|
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->hit_point, context->normal), wi);
|
||||||
.origin = BIAS_RAY_ORIGION(context->hit_point, context->normal),
|
|
||||||
.direction = wi,
|
|
||||||
};
|
|
||||||
|
|
||||||
float closest = FLT_MAX;
|
float closest = FLT_MAX;
|
||||||
hit_result_t shadow_hit = {1};
|
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,
|
ray_intersect_bvh(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0,
|
||||||
&closest, &shadow_hit);
|
&closest, &shadow_hit);
|
||||||
if (shadow_hit.hit)
|
if (shadow_hit.hit)
|
||||||
{
|
{
|
||||||
@@ -34,11 +31,12 @@ vec3s evaluate_bsdf_directional(directional_light_t light, const light_shading_c
|
|||||||
shading_context_t shading_context = {
|
shading_context_t shading_context = {
|
||||||
.normal = context->normal,
|
.normal = context->normal,
|
||||||
.wi = wi,
|
.wi = wi,
|
||||||
.wo = glms_vec3_negate(context->wo)
|
.wo = glms_vec3_negate(context->wo),
|
||||||
|
.uv = context->uv,
|
||||||
};
|
};
|
||||||
vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context);
|
vec3s bsdf = evaluate_material_bsdf(context->material, &shading_context);
|
||||||
|
|
||||||
vec3s light_radiance = glms_vec3_scale(light.color, light.intensity);
|
vec3s light_radiance = glms_vec3_scale(light.color, light.intensity);
|
||||||
vec3s light_contribute = glms_vec3_scale(glms_vec3_mul(throughput, bsdf), fmaxf(0.0f, n_dot_l));
|
vec3s light_contribute = glms_vec3_scale(glms_vec3_mul(throughput, bsdf), fmaxf(0.0f, n_dot_l)); // we always assume pdf = 1.0f for directional light
|
||||||
return glms_vec3_mul(light_radiance, light_contribute);
|
return glms_vec3_mul(light_radiance, light_contribute);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ vec3s evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* c
|
|||||||
if (context == NULL)
|
if (context == NULL)
|
||||||
{
|
{
|
||||||
return glms_vec3_mul(sky_color, throughput);
|
return glms_vec3_mul(sky_color, throughput);
|
||||||
// return sky_data.color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t d1 = sobol_get_dimension(context->bounce_depth, PRNG_LIGHT_U);
|
uint16_t d1 = sobol_get_dimension(context->bounce_depth, PRNG_LIGHT_U);
|
||||||
@@ -20,14 +19,11 @@ vec3s evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* c
|
|||||||
vec3s wi = random_uniform_cdf_direction(context->normal, sample_index, d1, d2);
|
vec3s wi = random_uniform_cdf_direction(context->normal, sample_index, d1, d2);
|
||||||
float pdf = 1.0f / (4.0f * (float)M_PI);
|
float pdf = 1.0f / (4.0f * (float)M_PI);
|
||||||
|
|
||||||
ray_t shadow_ray = {
|
ray_t shadow_ray = ray_create(BIAS_RAY_ORIGION(context->hit_point, context->normal), wi);
|
||||||
.origin = BIAS_RAY_ORIGION(context->hit_point, context->normal),
|
|
||||||
.direction = wi,
|
|
||||||
};
|
|
||||||
|
|
||||||
float closest = FLT_MAX;
|
float closest = FLT_MAX;
|
||||||
hit_result_t shadow_hit = {1};
|
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);
|
ray_intersect_bvh(&shadow_ray, context->bvh_tree->nodes, context->bvh_tree->primitive_indices, context->bvh_tree->triangles, 0, &closest, &shadow_hit);
|
||||||
if (shadow_hit.hit)
|
if (shadow_hit.hit)
|
||||||
{
|
{
|
||||||
return glms_vec3_zero();
|
return glms_vec3_zero();
|
||||||
@@ -36,14 +32,15 @@ vec3s evaluate_bsdf_const_sky(const void* data, const light_shading_context_t* c
|
|||||||
shading_context_t shading_context = {
|
shading_context_t shading_context = {
|
||||||
.normal = context->normal,
|
.normal = context->normal,
|
||||||
.wi = wi,
|
.wi = wi,
|
||||||
.wo = glms_vec3_negate(context->wo)
|
.wo = glms_vec3_negate(context->wo),
|
||||||
|
.uv = context->uv,
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
float pdf_bsdf = sample_material_bsdf_pdf(context->material, shading_context.normal, shading_context.wo, shading_context.wi, context->uv);
|
||||||
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);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "Material/Material.h"
|
#include "Material/Material.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
bool material_collection_init(size_t size, material_collection_t* materials)
|
|
||||||
|
|
||||||
|
bool material_collection_init(uint8_t size, material_collection_t* materials)
|
||||||
{
|
{
|
||||||
if (size > 254)
|
if (size > 254)
|
||||||
{
|
{
|
||||||
@@ -41,21 +43,12 @@ void material_collection_free(material_collection_t* materials)
|
|||||||
{
|
{
|
||||||
if (materials->buffer != NULL)
|
if (materials->buffer != NULL)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < materials->count; i++)
|
|
||||||
{
|
|
||||||
void* data = materials->buffer[i].data;
|
|
||||||
if (data != NULL)
|
|
||||||
{
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(materials->buffer);
|
free(materials->buffer);
|
||||||
materials->buffer = NULL;
|
materials->buffer = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
material_entity_t material_create(sample_bsdf_f sample, sample_bsdf_pdf_f sample_pdf, evaluate_bsdf_f evaluate, void* data, size_t size_of_data, 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)
|
||||||
{
|
{
|
||||||
material_t material = {0};
|
material_t material = {0};
|
||||||
|
|
||||||
@@ -64,16 +57,11 @@ material_entity_t material_create(sample_bsdf_f sample, sample_bsdf_pdf_f sample
|
|||||||
material_collection_resize(collection, collection->size * 2);
|
material_collection_resize(collection, collection->size * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(material.properties, properties, properties_size);
|
||||||
|
material.compute_surface_data = surface_data;
|
||||||
material.sample_bsdf = sample;
|
material.sample_bsdf = sample;
|
||||||
material.sample_bsdf_pdf = sample_pdf;
|
material.sample_bsdf_pdf = sample_pdf;
|
||||||
material.evaluate_bsdf = evaluate;
|
material.evaluate_bsdf = evaluate;
|
||||||
material.data = malloc(size_of_data);
|
|
||||||
if (material.data == NULL)
|
|
||||||
{
|
|
||||||
return (material_entity_t){.id = 255};
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(material.data, data, size_of_data);
|
|
||||||
|
|
||||||
material_entity_t entity = {.id = collection->count};
|
material_entity_t entity = {.id = collection->count};
|
||||||
|
|
||||||
@@ -83,23 +71,36 @@ material_entity_t material_create(sample_bsdf_f sample, sample_bsdf_pdf_f sample
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3s sample_material_bsdf(const material_t* material, vec3s normal, vec3s wo, uint32_t sample_index, uint32_t bounce, float* pdf_out)
|
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 wi = glms_vec3_zero();
|
vec3s wi = glms_vec3_zero();
|
||||||
if (material->sample_bsdf != NULL)
|
if (material->compute_surface_data != NULL && material->sample_bsdf != NULL)
|
||||||
{
|
{
|
||||||
wi = material->sample_bsdf(material->data, normal, wo, sample_index, bounce, pdf_out);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return wi;
|
return wi;
|
||||||
}
|
}
|
||||||
|
|
||||||
float sample_material_bsdf_pdf(const material_t* material, vec3s normal, vec3s wo, vec3s wi)
|
float sample_material_bsdf_pdf(const material_t* material, vec3s normal, vec3s wo, vec3s wi, vec2s uv)
|
||||||
{
|
{
|
||||||
float pdf = 0.0f;
|
float pdf = 0.0f;
|
||||||
if (material->sample_bsdf_pdf != NULL)
|
if (material->compute_surface_data != NULL && material->sample_bsdf_pdf != NULL)
|
||||||
{
|
{
|
||||||
pdf = material->sample_bsdf_pdf(material->data, normal, wo, wi);
|
shading_context_t context =
|
||||||
|
{
|
||||||
|
.normal = normal,
|
||||||
|
.wo = wo,
|
||||||
|
.wi = wi,
|
||||||
|
.uv = uv,
|
||||||
|
};
|
||||||
|
pdf = material->sample_bsdf_pdf(&context, material->properties, material->compute_surface_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pdf;
|
return pdf;
|
||||||
@@ -108,9 +109,9 @@ float sample_material_bsdf_pdf(const material_t* material, vec3s normal, vec3s w
|
|||||||
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)
|
||||||
{
|
{
|
||||||
vec3s bsdf_color = glms_vec3_zero();
|
vec3s bsdf_color = glms_vec3_zero();
|
||||||
if (material->evaluate_bsdf != NULL)
|
if (material->compute_surface_data != NULL && material->evaluate_bsdf != NULL)
|
||||||
{
|
{
|
||||||
bsdf_color = material->evaluate_bsdf(context, material->data);
|
bsdf_color = material->evaluate_bsdf(context, material->properties, material->compute_surface_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bsdf_color;
|
return bsdf_color;
|
||||||
|
|||||||
@@ -6,14 +6,39 @@
|
|||||||
static float DIELECTRIC_REFLECTIVE_F0 = 0.04f; // Standard dielectric reflectivity coef at incident angle (= 4%)
|
static float DIELECTRIC_REFLECTIVE_F0 = 0.04f; // Standard dielectric reflectivity coef at incident angle (= 4%)
|
||||||
static vec3s DIELECTRIC_REFLECTIVE = {0.04f, 0.04f, 0.04f}; // Standard dielectric reflectivity coef at incident angle (= 4%)
|
static vec3s DIELECTRIC_REFLECTIVE = {0.04f, 0.04f, 0.04f}; // Standard dielectric reflectivity coef at incident angle (= 4%)
|
||||||
|
|
||||||
// Simple lit, but keep it unbiased as much as possible
|
void simple_lit_data_default(const shading_context_t* context, const void* properties, void* data_out)
|
||||||
vec3s sample_bsdf_simple_lit(const void* data, vec3s normal, vec3s wo, uint32_t sample_index, uint32_t bounce, float* pdf_out)
|
|
||||||
{
|
{
|
||||||
simple_lit_data_t shading_data = *(const simple_lit_data_t*)data;
|
const simple_lit_properties_t* prop = (simple_lit_properties_t*)properties;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
data->albedo = glms_vec3_mul(data->albedo, glms_vec3(texture_sample(prop->albedo_texture, context->uv.x, context->uv.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
data->roughness = prop->roughness;
|
||||||
|
if (prop->roughness_texture != NULL && prop->roughness_texture->data != NULL)
|
||||||
|
{
|
||||||
|
data->roughness = data->roughness * texture_sample(prop->roughness_texture, context->uv.x, context->uv.y).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->metallic = prop->metallic;
|
||||||
|
if (prop->metallic_texture != NULL && prop->metallic_texture->data != NULL)
|
||||||
|
{
|
||||||
|
data->metallic = data->metallic * texture_sample(prop->metallic_texture, context->uv.x, context->uv.y).x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple lit, but keep it unbiased as much as possible
|
||||||
|
vec3s sample_bsdf_simple_lit(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data, uint32_t sample_index, uint32_t bounce, float* pdf_out)
|
||||||
|
{
|
||||||
|
simple_lit_data_t shading_data;
|
||||||
|
compute_surface_data(context, properties, &shading_data);
|
||||||
|
|
||||||
//TODO: having a bsdf data struct to avoid recomputing the same thing in both sample and evaluate
|
//TODO: having a bsdf data struct to avoid recomputing the same thing in both sample and evaluate
|
||||||
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, shading_data.albedo, shading_data.metallic);
|
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, shading_data.albedo, shading_data.metallic);
|
||||||
float cos_theta_0 = fmaxf(glms_vec3_dot(normal, wo), 0.0f);
|
float cos_theta_0 = fmaxf(glms_vec3_dot(context->normal, context->wo), 0.0f);
|
||||||
vec3s f = fresnel_schlick_vec3(f0, cos_theta_0);
|
vec3s f = fresnel_schlick_vec3(f0, cos_theta_0);
|
||||||
float lum_f = (f.x + f.y + f.z) / 3.0f;
|
float lum_f = (f.x + f.y + f.z) / 3.0f;
|
||||||
|
|
||||||
@@ -38,7 +63,7 @@ vec3s sample_bsdf_simple_lit(const void* data, vec3s normal, vec3s wo, uint32_t
|
|||||||
|
|
||||||
if (lob_sample < prob_diffuse) // Diffuse Lobe
|
if (lob_sample < prob_diffuse) // Diffuse Lobe
|
||||||
{
|
{
|
||||||
wi = random_cosine_direction(normal, sample_index, d1, d2);
|
wi = random_cosine_direction(context->normal, sample_index, d1, d2);
|
||||||
}
|
}
|
||||||
else // Specular Lobe
|
else // Specular Lobe
|
||||||
{
|
{
|
||||||
@@ -61,11 +86,11 @@ vec3s sample_bsdf_simple_lit(const void* data, vec3s normal, vec3s wo, uint32_t
|
|||||||
|
|
||||||
vec3s tangent_u; // World-space tangent (U)
|
vec3s tangent_u; // World-space tangent (U)
|
||||||
vec3s bitangent_v; // World-space bitangent (V)
|
vec3s bitangent_v; // World-space bitangent (V)
|
||||||
create_orthonormal_basis(normal, &tangent_u, &bitangent_v);
|
create_orthonormal_basis(context->normal, &tangent_u, &bitangent_v);
|
||||||
|
|
||||||
vec3s scaled_u = glms_vec3_scale(tangent_u, h_ts.x);
|
vec3s scaled_u = glms_vec3_scale(tangent_u, h_ts.x);
|
||||||
vec3s scaled_v = glms_vec3_scale(bitangent_v, h_ts.y);
|
vec3s scaled_v = glms_vec3_scale(bitangent_v, h_ts.y);
|
||||||
vec3s scaled_n = glms_vec3_scale(normal, h_ts.z);
|
vec3s scaled_n = glms_vec3_scale(context->normal, h_ts.z);
|
||||||
|
|
||||||
// Transform h from tangent space to world space
|
// Transform h from tangent space to world space
|
||||||
vec3s h_ws;
|
vec3s h_ws;
|
||||||
@@ -74,37 +99,37 @@ vec3s sample_bsdf_simple_lit(const void* data, vec3s normal, vec3s wo, uint32_t
|
|||||||
h_ws = glms_vec3_normalize(h_ws);
|
h_ws = glms_vec3_normalize(h_ws);
|
||||||
|
|
||||||
// wi is simple now, just reflect wo around normal
|
// wi is simple now, just reflect wo around normal
|
||||||
wi = glms_vec3_reflect(glms_vec3_negate(wo), h_ws);
|
wi = glms_vec3_reflect(glms_vec3_negate(context->wo), h_ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final check to ensure wi is in the correct hemisphere
|
// Final check to ensure wi is in the correct hemisphere
|
||||||
if (glms_vec3_dot(wi, normal) < 0.0f)
|
if (glms_vec3_dot(wi, context->normal) < 0.0f)
|
||||||
{
|
{
|
||||||
*pdf_out = 0.0f;
|
*pdf_out = 0.0f;
|
||||||
return glms_vec3_zero();
|
return glms_vec3_zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
float pdf_diffuse = pdf_cosine_weighted_hemisphere(normal, wi);
|
float pdf_diffuse = pdf_cosine_weighted_hemisphere(context->normal, wi);
|
||||||
float pdf_specular = pdf_blinn_phong_lobe(normal, wi, wo, shading_data.roughness);
|
float pdf_specular = pdf_blinn_phong_lobe(context->normal, wi, context->wo, shading_data.roughness);
|
||||||
*pdf_out = prob_diffuse * pdf_diffuse + prob_specular * pdf_specular;
|
*pdf_out = prob_diffuse * pdf_diffuse + prob_specular * pdf_specular;
|
||||||
|
|
||||||
return wi;
|
return wi;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Most of the calculation here is same as in sample_bsdf_simple_lit, we can optimize this by using a bsdf data struct to avoid recomputing the same thing in both sample and evaluate
|
float sample_bsdf_pdf_simple_lit(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data)
|
||||||
float sample_bsdf_pdf_simple_lit(const void* data, vec3s normal, vec3s wo, vec3s wi)
|
|
||||||
{
|
{
|
||||||
// If wi is below the horizon relative to the normal, PDF must be 0
|
// If wi is below the horizon relative to the normal, PDF must be 0
|
||||||
if (glms_vec3_dot(normal, wi) <= 0.0f) // Use <= to be safe
|
if (glms_vec3_dot(context->normal, context->wi) <= 0.0f) // Use <= to be safe
|
||||||
{
|
{
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_lit_data_t shading_data = *(const simple_lit_data_t*)data;
|
simple_lit_data_t shading_data;
|
||||||
|
compute_surface_data(context, properties, &shading_data);
|
||||||
|
|
||||||
// Again, we need bsdf data;
|
// Again, we need bsdf data;
|
||||||
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, shading_data.albedo, shading_data.metallic);
|
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, shading_data.albedo, shading_data.metallic);
|
||||||
float cos_theta_o = fmaxf(glms_vec3_dot(normal, wo), 0.0f); // Use 'o' for outgoing (wo)
|
float cos_theta_o = fmaxf(glms_vec3_dot(context->normal, context->wo), 0.0f); // Use 'o' for outgoing (wo)
|
||||||
float F = glms_vec3_max(fresnel_schlick_vec3(f0, cos_theta_o));
|
float F = glms_vec3_max(fresnel_schlick_vec3(f0, cos_theta_o));
|
||||||
|
|
||||||
float prob_specular = glm_lerp(F, 1.0f, shading_data.metallic);
|
float prob_specular = glm_lerp(F, 1.0f, shading_data.metallic);
|
||||||
@@ -118,25 +143,25 @@ float sample_bsdf_pdf_simple_lit(const void* data, vec3s normal, vec3s wo, vec3s
|
|||||||
prob_diffuse /= total_prob;
|
prob_diffuse /= total_prob;
|
||||||
prob_specular /= total_prob;
|
prob_specular /= total_prob;
|
||||||
|
|
||||||
float pdf_diff = pdf_cosine_weighted_hemisphere(normal, wi);
|
float pdf_diff = pdf_cosine_weighted_hemisphere(context->normal, context->wi);
|
||||||
float diffuse_pdf_component = prob_diffuse * pdf_diff;
|
float diffuse_pdf_component = prob_diffuse * pdf_diff;
|
||||||
|
|
||||||
float pdf_spec = pdf_blinn_phong_lobe(normal, wo, wi, shading_data.roughness);
|
float pdf_spec = pdf_blinn_phong_lobe(context->normal, context->wo, context->wi, shading_data.roughness);
|
||||||
float specular_pdf_component = prob_specular * pdf_spec;
|
float specular_pdf_component = prob_specular * pdf_spec;
|
||||||
|
|
||||||
return diffuse_pdf_component + specular_pdf_component;
|
return diffuse_pdf_component + specular_pdf_component;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3s evaluate_bsdf_simple_lit(const shading_context_t* context, const void* data)
|
vec3s evaluate_bsdf_simple_lit(const shading_context_t* context, const void* properties, const compute_surface_data_f compute_surface_data)
|
||||||
{
|
{
|
||||||
simple_lit_data_t shading_data = *(const simple_lit_data_t*)data;
|
simple_lit_data_t shading_data;
|
||||||
shading_context_t shading_context = *context;
|
compute_surface_data(context, properties, &shading_data);
|
||||||
|
|
||||||
vec3s h = glms_vec3_normalize(glms_vec3_add(shading_context.wi, shading_context.wo));
|
vec3s h = glms_vec3_normalize(glms_vec3_add(context->wi, context->wo));
|
||||||
float n_dot_l = fmaxf(FLT_EPSILON, glms_vec3_dot(shading_context.normal, shading_context.wi));
|
float n_dot_l = fmaxf(FLT_EPSILON, glms_vec3_dot(context->normal, context->wi));
|
||||||
float n_dot_v = fmaxf(FLT_EPSILON, glms_vec3_dot(shading_context.normal, shading_context.wo));
|
float n_dot_v = fmaxf(FLT_EPSILON, glms_vec3_dot(context->normal, context->wo));
|
||||||
float n_dot_h = glms_vec3_dot(shading_context.normal, h);
|
float n_dot_h = glms_vec3_dot(context->normal, h);
|
||||||
float v_dot_h = glms_vec3_dot(shading_context.wo, h);
|
float v_dot_h = glms_vec3_dot(context->wo, h);
|
||||||
|
|
||||||
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, shading_data.albedo, shading_data.metallic);
|
vec3s f0 = glms_vec3_lerp(DIELECTRIC_REFLECTIVE, shading_data.albedo, shading_data.metallic);
|
||||||
|
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ camera_t camera_create(vec3s position, versors rotation, float focal_length, flo
|
|||||||
};
|
};
|
||||||
|
|
||||||
return camera;
|
return camera;
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ static void ray_intersect_bvh_count(ray_t ray, bvh_tree_t bvh_tree, uint64_t nod
|
|||||||
const bvh_node_t* node = &bvh_tree.nodes[node_index];
|
const bvh_node_t* node = &bvh_tree.nodes[node_index];
|
||||||
|
|
||||||
float enter, exit;
|
float enter, exit;
|
||||||
if (!ray_intersect_aabb(ray, node->bounds, &enter, &exit))
|
if (!ray_intersect_aabb(&ray, node->bounds, &enter, &exit))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -33,11 +33,9 @@ static void ray_intersect_bvh_count(ray_t ray, bvh_tree_t bvh_tree, uint64_t nod
|
|||||||
|
|
||||||
vec4s render_debug(scene_t* scene, ray_t ray, uint16_t sample_index, int flag)
|
vec4s render_debug(scene_t* scene, ray_t ray, uint16_t sample_index, int flag)
|
||||||
{
|
{
|
||||||
vec4s result = glms_vec4_zero();
|
|
||||||
|
|
||||||
if (scene == NULL)
|
if (scene == NULL)
|
||||||
{
|
{
|
||||||
return result;
|
return glms_vec4_zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (flag & 0xFF)
|
switch (flag & 0xFF)
|
||||||
@@ -46,20 +44,23 @@ vec4s render_debug(scene_t* scene, ray_t ray, uint16_t sample_index, int flag)
|
|||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
ray_intersect_bvh_count(ray, scene->bvh_tree, 0, &count);
|
ray_intersect_bvh_count(ray, scene->bvh_tree, 0, &count);
|
||||||
|
|
||||||
|
vec4s result = glms_vec4_zero();
|
||||||
for (uint32_t i = 0; i < count; i++)
|
for (uint32_t i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
result = glms_vec4_add(result, DEBUG_COLOR_BVH);
|
result = glms_vec4_add(result, DEBUG_COLOR_BVH);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
break;
|
|
||||||
case DEBUG_SOBOL:
|
case DEBUG_SOBOL:
|
||||||
uint16_t i = sample_index ^ (sample_index >> 1);
|
uint16_t i = sample_index ^ (sample_index >> 1);
|
||||||
float sobol_sample_value = sobol_sample(i, 1); // Assuming dimension 0 for simplicity
|
float sobol_sample_value = sobol_sample(i, 1); // Assuming dimension 0 for simplicity
|
||||||
result = glms_vec4_add(result, (vec4s){sobol_sample_value, sobol_sample_value, sobol_sample_value, 1.0f});
|
return (vec4s){sobol_sample_value, sobol_sample_value, sobol_sample_value, 1.0f};
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
case DEBUG_UV:
|
||||||
|
hit_result_t hit_result = ray_intersect_scene(&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:
|
||||||
|
return glms_vec4_zero();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,9 +76,8 @@ unsigned char* render_target_to_char(render_target_t* render_target)
|
|||||||
|
|
||||||
void render_target_free(render_target_t* target)
|
void render_target_free(render_target_t* target)
|
||||||
{
|
{
|
||||||
if (target->buffer != NULL)
|
if (target != NULL && target->buffer != NULL)
|
||||||
{
|
{
|
||||||
free(target->buffer);
|
free(target->buffer);
|
||||||
target->buffer = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ static inline uint16_t get_sample_count(uint16_t sample_count, int flag)
|
|||||||
{
|
{
|
||||||
case DEBUG_BVH:
|
case DEBUG_BVH:
|
||||||
case DEBUG_SOBOL:
|
case DEBUG_SOBOL:
|
||||||
|
case DEBUG_UV:
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
return sample_count;
|
return sample_count;
|
||||||
@@ -45,6 +46,8 @@ static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s
|
|||||||
uint32_t pixel_id = y * config->width + x;
|
uint32_t pixel_id = y * config->width + x;
|
||||||
|
|
||||||
uint16_t sample_count = get_sample_count(config->sample_count, flag);
|
uint16_t sample_count = get_sample_count(config->sample_count, flag);
|
||||||
|
float inv_sample = 1.0f / (float)sample_count;
|
||||||
|
|
||||||
vec2s position_ndc = compute_ndc((float)x, (float)y, config->width, config->height);
|
vec2s position_ndc = compute_ndc((float)x, (float)y, config->width, config->height);
|
||||||
vec3s camera_right = quat_get_right(scene->camera.rotation);
|
vec3s camera_right = quat_get_right(scene->camera.rotation);
|
||||||
vec3s camera_up = quat_get_up(scene->camera.rotation);
|
vec3s camera_up = quat_get_up(scene->camera.rotation);
|
||||||
@@ -60,10 +63,7 @@ static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s
|
|||||||
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(camera_right, sensor_offset_x));
|
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(camera_right, sensor_offset_x));
|
||||||
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(camera_up, sensor_offset_y));
|
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(camera_up, sensor_offset_y));
|
||||||
|
|
||||||
ray_t ray = {
|
ray_t ray = ray_create(scene->camera.position, glms_vec3_normalize(glms_vec3_sub(image_plane_point, scene->camera.position)));
|
||||||
.origin = scene->camera.position,
|
|
||||||
.direction = glms_vec3_normalize(glms_vec3_sub(image_plane_point, scene->camera.position))
|
|
||||||
};
|
|
||||||
|
|
||||||
vec4s out_color = glms_vec4_zero();
|
vec4s out_color = glms_vec4_zero();
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s
|
|||||||
accumulated_color = glms_vec4_add(accumulated_color, out_color);
|
accumulated_color = glms_vec4_add(accumulated_color, out_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
*pixel_color = glms_vec4_scale(accumulated_color, 1.0f / (float)sample_count);
|
*pixel_color = glms_vec4_scale(accumulated_color, inv_sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Progressive rendering
|
// TODO: Progressive rendering
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
#include "Rendering/Scene.h"
|
#include "Rendering/Scene.h"
|
||||||
|
|
||||||
bool scene_init(scene_t* scene, uint64_t triangle_count, uint8_t material_count, uint32_t punctual_light_count)
|
bool scene_init(scene_t* scene, uint64_t triangle_count, uint16_t texture_count, uint8_t material_count, uint32_t punctual_light_count)
|
||||||
{
|
{
|
||||||
scene_t temp = {0};
|
scene_t temp = {0};
|
||||||
|
|
||||||
if (!triangle_collection_init(&temp.triangles, triangle_count))
|
if (!triangle_collection_init(triangle_count, &temp.triangles))
|
||||||
{
|
{
|
||||||
goto triangle_failed;
|
goto triangle_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!texture_collection_init(texture_count, &temp.textures))
|
||||||
|
{
|
||||||
|
goto texture_failed;
|
||||||
|
}
|
||||||
|
|
||||||
if (!material_collection_init(material_count, &temp.materials))
|
if (!material_collection_init(material_count, &temp.materials))
|
||||||
{
|
{
|
||||||
goto material_failed;
|
goto material_failed;
|
||||||
@@ -33,6 +38,8 @@ bool scene_init(scene_t* scene, uint64_t triangle_count, uint8_t material_count,
|
|||||||
light_failed:
|
light_failed:
|
||||||
material_collection_free(&temp.materials);
|
material_collection_free(&temp.materials);
|
||||||
material_failed:
|
material_failed:
|
||||||
|
texture_collection_free(&temp.textures);
|
||||||
|
texture_failed:
|
||||||
triangle_collection_free(&temp.triangles);
|
triangle_collection_free(&temp.triangles);
|
||||||
triangle_failed:
|
triangle_failed:
|
||||||
return false;
|
return false;
|
||||||
@@ -58,8 +65,14 @@ bool scene_build_bvh(scene_t* scene)
|
|||||||
|
|
||||||
void scene_free(scene_t* scene)
|
void scene_free(scene_t* scene)
|
||||||
{
|
{
|
||||||
|
if (scene == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bvh_tree_free(&scene->bvh_tree);
|
bvh_tree_free(&scene->bvh_tree);
|
||||||
triangle_collection_free(&scene->triangles);
|
triangle_collection_free(&scene->triangles);
|
||||||
|
texture_collection_free(&scene->textures);
|
||||||
material_collection_free(&scene->materials);
|
material_collection_free(&scene->materials);
|
||||||
light_collection_free(&scene->lights);
|
light_collection_free(&scene->lights);
|
||||||
}
|
}
|
||||||
|
|||||||
198
source/Rendering/Texture.c
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
#include "Rendering/Texture.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
#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};
|
||||||
|
temp.buffer = (texture_t*)malloc(size * sizeof(texture_t));
|
||||||
|
if (temp.buffer == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp.size = size;
|
||||||
|
temp.count = 0;
|
||||||
|
*textures = temp;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void texture_collection_resize(texture_collection_t* textures, uint16_t size)
|
||||||
|
{
|
||||||
|
texture_t* temp = (texture_t*)realloc(textures->buffer, size * sizeof(texture_t));
|
||||||
|
if (temp != NULL)
|
||||||
|
{
|
||||||
|
textures->buffer = temp;
|
||||||
|
textures->size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void texture_collection_free(texture_collection_t* textures)
|
||||||
|
{
|
||||||
|
if (textures == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < textures->count; i++)
|
||||||
|
{
|
||||||
|
texture_free(&textures->buffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(textures->buffer);
|
||||||
|
textures->buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_entity_t texture_load(const char* filename, bool srgb, texture_collection_t* textures)
|
||||||
|
{
|
||||||
|
int width, height, channels;
|
||||||
|
uint8_t* data = stbi_load(filename, &width, &height, &channels, 0);
|
||||||
|
if (data == NULL)
|
||||||
|
{
|
||||||
|
return invalid_texture_entity();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srgb)
|
||||||
|
{
|
||||||
|
// Convert to linear space if the texture is in sRGB format
|
||||||
|
for (int i = 0; i < width * height * channels; i++)
|
||||||
|
{
|
||||||
|
data[i] = (uint8_t)(powf(data[i] / 255.0f, 2.2f) * 255.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_t texture = {0};
|
||||||
|
texture.width = (uint32_t)width;
|
||||||
|
texture.height = (uint32_t)height;
|
||||||
|
texture.channel_count = (uint8_t)channels;
|
||||||
|
texture.data = data;
|
||||||
|
texture.wrap_mode = REPEAT;
|
||||||
|
texture.filter_mode = LINEAR;
|
||||||
|
|
||||||
|
if (textures->count >= textures->size)
|
||||||
|
{
|
||||||
|
texture_collection_resize(textures, textures->size * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_entity_t entity = {.id = textures->count};
|
||||||
|
|
||||||
|
textures->buffer[textures->count] = texture;
|
||||||
|
textures->count++;
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void warp_uv(wrap_mode_t mode, float* u, float* v)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case REPEAT:
|
||||||
|
*u = fmodf(fabsf(*u), 1.0f);
|
||||||
|
*v = fmodf(fabsf(*v), 1.0f);
|
||||||
|
break;
|
||||||
|
case CLAMP:
|
||||||
|
*u = fminf(fmaxf(*u, 0.0f), 1.0f);
|
||||||
|
*v = fminf(fmaxf(*v, 0.0f), 1.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static vec4s get_pixel_color(const texture_t* texture, uint32_t x, uint32_t y)
|
||||||
|
{
|
||||||
|
uint32_t pixel_index = y * texture->width + x;
|
||||||
|
if (pixel_index >= texture->width * texture->height)
|
||||||
|
{
|
||||||
|
return (vec4s){0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* pixel = &texture->data[pixel_index * texture->channel_count];
|
||||||
|
return (vec4s)
|
||||||
|
{
|
||||||
|
GET_CHANNEL_DATA(pixel, 0, texture->channel_count, 0),
|
||||||
|
GET_CHANNEL_DATA(pixel, 1, texture->channel_count, 0),
|
||||||
|
GET_CHANNEL_DATA(pixel, 2, texture->channel_count, 0),
|
||||||
|
GET_CHANNEL_DATA(pixel, 3, texture->channel_count, 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static vec4s nearest_filter(const texture_t* texture, float u, float v)
|
||||||
|
{
|
||||||
|
uint32_t x = (uint32_t)floorf(u * (texture->width - 1));
|
||||||
|
uint32_t y = (uint32_t)floorf(v * (texture->height - 1));
|
||||||
|
|
||||||
|
x = x < texture->width ? x : texture->width - 1;
|
||||||
|
y = y < texture->height ? y : texture->height - 1;
|
||||||
|
|
||||||
|
return get_pixel_color(texture, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static vec4s linear_filter(const texture_t* texture, float u, float v)
|
||||||
|
{
|
||||||
|
float x = u * (texture->width - 1);
|
||||||
|
float y = v * (texture->height - 1);
|
||||||
|
|
||||||
|
uint32_t x0 = (uint32_t)floorf(x);
|
||||||
|
uint32_t x1 = x0 + 1;
|
||||||
|
uint32_t y0 = (uint32_t)floorf(y);
|
||||||
|
uint32_t y1 = y0 + 1;
|
||||||
|
|
||||||
|
float sx = x - (float)x0;
|
||||||
|
float sy = y - (float)y0;
|
||||||
|
|
||||||
|
// Clamp to edges
|
||||||
|
x0 = x0 < texture->width ? x0 : texture->width - 1;
|
||||||
|
x1 = x1 < texture->width ? x1 : texture->width - 1;
|
||||||
|
y0 = y0 < texture->height ? y0 : texture->height - 1;
|
||||||
|
y1 = y1 < texture->height ? y1 : texture->height - 1;
|
||||||
|
|
||||||
|
// Sample 4 texels
|
||||||
|
vec4s c00 = get_pixel_color(texture, x0, y0);
|
||||||
|
vec4s c10 = get_pixel_color(texture, x1, y0);
|
||||||
|
vec4s c01 = get_pixel_color(texture, x0, y1);
|
||||||
|
vec4s c11 = get_pixel_color(texture, x1, y1);
|
||||||
|
|
||||||
|
// Interpolate along x
|
||||||
|
vec4s c0 = glms_vec4_lerp(c00, c10, sx);
|
||||||
|
vec4s c1 = glms_vec4_lerp(c01, c11, sx);
|
||||||
|
|
||||||
|
// Interpolate along y
|
||||||
|
vec4s result = glms_vec4_lerp(c0, c1, sy);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline vec4s filter_texture(const texture_t* texture, float u, float v)
|
||||||
|
{
|
||||||
|
switch (texture->filter_mode)
|
||||||
|
{
|
||||||
|
case NEAREST:
|
||||||
|
return nearest_filter(texture, u, v);
|
||||||
|
case LINEAR:
|
||||||
|
return linear_filter(texture, u, v);
|
||||||
|
default:
|
||||||
|
return (vec4s){0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4s texture_sample(const texture_t* texture, float u, float v)
|
||||||
|
{
|
||||||
|
warp_uv(texture->wrap_mode, &u, &v);
|
||||||
|
return filter_texture(texture, u, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void texture_free(texture_t* texture)
|
||||||
|
{
|
||||||
|
if (texture != NULL && texture->data != NULL)
|
||||||
|
{
|
||||||
|
stbi_image_free(texture->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,19 +3,20 @@
|
|||||||
#include <svpng.inc>
|
#include <svpng.inc>
|
||||||
|
|
||||||
#include "Algorithm/Sobol.h"
|
#include "Algorithm/Sobol.h"
|
||||||
|
// #include "Geometry/GeometryUtilities.h"
|
||||||
#include "Geometry/Mesh.h"
|
#include "Geometry/Mesh.h"
|
||||||
#include "Lighting/SkyLight.h"
|
#include "Lighting/SkyLight.h"
|
||||||
#include "Material/SimpleLit.h"
|
// #include "Material/SimpleLit.h"
|
||||||
#include "Rendering/PostProcessing.h"
|
#include "Rendering/PostProcessing.h"
|
||||||
#include "Rendering/Scene.h"
|
#include "Rendering/Scene.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
|
||||||
#define TITLE "Path Tracing"
|
#define TITLE "Path Tracing"
|
||||||
#define SPONZA_PATH "./assets/sponza.obj"
|
#define SPONZA_PATH "./assets/sponza.fbx"
|
||||||
|
|
||||||
static bool scene_setup(scene_t* scene)
|
static bool scene_setup(scene_t* scene)
|
||||||
{
|
{
|
||||||
if (!scene_init(scene, 67000, 8, 1))
|
if (!scene_init(scene, 167000, 3, 8, 1))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -26,7 +27,7 @@ static bool scene_setup(scene_t* scene)
|
|||||||
// TODO: Standardize light unit
|
// TODO: Standardize light unit
|
||||||
light_entity_t sun = light_create_directional_light(&scene->lights);
|
light_entity_t sun = light_create_directional_light(&scene->lights);
|
||||||
directional_light_t* sun_light = &scene->lights.directional_lights[sun.id];
|
directional_light_t* sun_light = &scene->lights.directional_lights[sun.id];
|
||||||
sun_light->direction = glms_vec3_normalize((vec3s){-0.5f, 1.0f, 0.15f});
|
sun_light->direction = glms_vec3_normalize((vec3s){-0.5f, 1.0f, 0.25f});
|
||||||
sun_light->color = (vec3s){1.0f, 0.93f, 0.87f};
|
sun_light->color = (vec3s){1.0f, 0.93f, 0.87f};
|
||||||
sun_light->intensity = 2.0f;
|
sun_light->intensity = 2.0f;
|
||||||
sun_light->angular_diameter = 0.53f;
|
sun_light->angular_diameter = 0.53f;
|
||||||
@@ -42,16 +43,8 @@ static bool scene_setup(scene_t* scene)
|
|||||||
|
|
||||||
static bool load_assets(scene_t* scene)
|
static bool load_assets(scene_t* scene)
|
||||||
{
|
{
|
||||||
simple_lit_data_t floor_lit_data =
|
mesh_load(SPONZA_PATH, scene);
|
||||||
{
|
// quad_create((vec3s){0.0f, 0.0f, 0.0f}, (vec3s){0.0f, 1.0f, 0.0f}, (vec3s){1.0f, 0.0f, 0.0f}, 10.0f, floor_material.id, &scene->triangles);
|
||||||
.albedo = (vec3s){1.0f, 1.0f, 1.0f},
|
|
||||||
.roughness = 0.95f,
|
|
||||||
.metallic = 0.0f,
|
|
||||||
};
|
|
||||||
|
|
||||||
material_entity_t floor_material = material_create_simple_lit(&floor_lit_data, &scene->materials);
|
|
||||||
|
|
||||||
mesh_load(SPONZA_PATH, floor_material.id, &scene->triangles, &scene->materials);
|
|
||||||
|
|
||||||
return scene_build_bvh(scene);
|
return scene_build_bvh(scene);
|
||||||
}
|
}
|
||||||
@@ -157,14 +150,14 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
|||||||
{
|
{
|
||||||
omp_set_num_threads(16);
|
omp_set_num_threads(16);
|
||||||
|
|
||||||
scene_t scene;
|
scene_t scene = {0};
|
||||||
render_target_t img;
|
render_target_t img = {0};
|
||||||
render_job_t* job = NULL;
|
render_job_t* job = NULL;
|
||||||
|
|
||||||
rendering_config_t config = {
|
rendering_config_t config = {
|
||||||
.width = 1920 / 2,
|
.width = 1920 / 2,
|
||||||
.height = 1080 / 2,
|
.height = 1080 / 2,
|
||||||
.sample_count = 64 * 4,
|
.sample_count = 64 * 1,
|
||||||
.max_depth = 4,
|
.max_depth = 4,
|
||||||
.bucket_size = 64,
|
.bucket_size = 64,
|
||||||
};
|
};
|
||||||
|
|||||||