aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/aabb.hpp9
-rw-r--r--include/bvh-node.hpp74
-rw-r--r--include/gltf.hpp34
-rw-r--r--include/scene.hpp45
-rw-r--r--include/triangle.hpp25
-rw-r--r--include/utils.hpp1
-rw-r--r--include/vk-renderer.hpp12
-rw-r--r--shaders/compute.comp104
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/gltf.cpp104
-rw-r--r--src/main.cpp56
-rw-r--r--src/scene.cpp53
-rw-r--r--src/vk-renderer.cpp28
13 files changed, 453 insertions, 96 deletions
diff --git a/include/aabb.hpp b/include/aabb.hpp
index 76a6872..2630a17 100644
--- a/include/aabb.hpp
+++ b/include/aabb.hpp
@@ -10,6 +10,15 @@ class aabb {
aabb() = default;
aabb(vec3 min_point, vec3 max_point): minimum(min_point), maximum(max_point) {}
aabb(vec3 position, float radius): minimum(position - vec3(radius)), maximum(position + vec3(radius)) {}
+ aabb(point3 v1, point3 v2, point3 v3) {
+ minimum.x = fmin(fmin(v1.x, v2.x), v3.x);
+ minimum.y = fmin(fmin(v1.y, v2.y), v3.y);
+ minimum.z = fmin(fmin(v1.z, v2.z), v3.z);
+
+ maximum.x = fmax(fmax(v1.x, v2.x), v3.x);
+ maximum.y = fmax(fmax(v1.y, v2.y), v3.y);
+ maximum.z = fmax(fmax(v1.z, v2.z), v3.z);
+ }
static aabb surrounding_box(aabb box0, aabb box1) {
point3 min_point(fmin(box0.minimum.x, box1.minimum.x),
diff --git a/include/bvh-node.hpp b/include/bvh-node.hpp
index 16c3cb3..805edf2 100644
--- a/include/bvh-node.hpp
+++ b/include/bvh-node.hpp
@@ -6,16 +6,17 @@
#include "aabb.hpp"
#include "sphere.hpp"
+#include "triangle.hpp"
class bvh_node {
public:
bvh_node() = default;
- bvh_node(sphere& sphere, int32_t sphere_id): bounding_box(sphere.bounding_box), sphere_id(sphere_id){}
+ bvh_node(sphere& sphere, int32_t sphere_id): bounding_box(sphere.bounding_box), primitive_id(sphere_id){}
aabb bounding_box;
int32_t next_id = -1;
- int32_t sphere_id = -1;
+ int32_t primitive_id = -1;
uint32_t padding[2];
};
@@ -26,21 +27,21 @@ struct temp_node : public bvh_node {
class bvh {
public:
- void build(sphere* spheres, uint32_t spheres_count) {
- nodes = std::vector<bvh_node>(2 * spheres_count - 1);
- temp_nodes = std::vector<temp_node>(2 * spheres_count - 1);
- leafs = std::vector<temp_node>(spheres_count);
- this->spheres = spheres;
+ bvh(std::vector<sphere>& spheres, std::vector<bvh_node>& nodes)
+ :spheres(spheres), nodes(nodes) {
+ nodes = std::vector<bvh_node>(2 * spheres.size() - 1);
+ temp_nodes = std::vector<temp_node>(2 * spheres.size() - 1);
+ leafs = std::vector<temp_node>(spheres.size());
- for (uint32_t id = 0; id < spheres_count; id++) {
+ for (uint32_t id = 0; id < spheres.size(); id++) {
leafs[id].bounding_box = spheres[id].bounding_box;
- leafs[id].sphere_id = id;
+ leafs[id].primitive_id = id;
}
temp_nodes[0] = temp_node();
- temp_nodes[0].bounding_box = compute_bounds(0, spheres_count);
- subdivide(0, 0, spheres_count);
+ temp_nodes[0].bounding_box = compute_bounds(0, spheres.size());
+ subdivide(0, 0, spheres.size());
set_depth_first_order();
@@ -48,7 +49,7 @@ public:
auto old_node = temp_nodes[id];
auto &node = nodes[old_node.df_id];
- node.sphere_id = old_node.sphere_id;
+ node.primitive_id = old_node.primitive_id;
node.bounding_box = old_node.bounding_box;
if (old_node.next_id != -1) {
@@ -59,6 +60,39 @@ public:
// exporter();
}
+ // bvh(std::vector<triangle>& triangles, std::vector<bvh_node>& nodes)
+ // :triangles(triangles), nodes(nodes) {
+ // nodes.resize(2 * triangles.size() - 1);
+ // temp_nodes = std::vector<temp_node>(2 * triangles.size() - 1);
+ // leafs = std::vector<temp_node>(triangles.size());
+
+ // for (uint32_t id = 0; id < triangles.size(); id++) {
+ // leafs[id].bounding_box = triangles[id].bounding_box;
+ // leafs[id].primitive_id = id;
+ // }
+
+ // temp_nodes[0] = temp_node();
+
+ // temp_nodes[0].bounding_box = compute_bounds(0, triangles.size());
+ // subdivide(0, 0, triangles.size());
+
+ // set_depth_first_order();
+
+ // for (uint32_t id = 0; id < temp_nodes.size(); id++) {
+ // auto old_node = temp_nodes[id];
+ // auto &node = nodes[old_node.df_id];
+
+ // node.primitive_id = old_node.primitive_id;
+ // node.bounding_box = old_node.bounding_box;
+
+ // if (old_node.next_id != -1) {
+ // node.next_id = temp_nodes[old_node.next_id].df_id;
+ // }
+ // }
+
+ // // exporter();
+ // }
+
//-------------------------
// BVH exporter for graphviz
//-------------------------
@@ -92,7 +126,7 @@ public:
return -1;
}
- if (nodes[id].sphere_id == -1) {
+ if (nodes[id].primitive_id == -1) {
int32_t left = id + 1;
int32_t next_id;
@@ -102,7 +136,7 @@ public:
if (next_id != -1) {
return traverse_depth_first_ordered(nodes, id, next_id);
}
- } else if (nodes[id].sphere_id != -1 && nodes[id].next_id != -1) {
+ } else if (nodes[id].primitive_id != -1 && nodes[id].next_id != -1) {
std::cout << "\t " << parent_id << " -> " << id << ";\n";
return nodes[id].next_id;
} else {
@@ -119,7 +153,8 @@ private:
for (uint32_t box_id = begin; box_id < end; box_id++) {
auto leaf = leafs[box_id];
- global_box = aabb::surrounding_box(global_box, spheres[leaf.sphere_id].bounding_box);
+ global_box = aabb::surrounding_box(global_box, spheres[leaf.primitive_id].bounding_box);
+ // global_box = aabb::surrounding_box(global_box, triangles[leaf.primitive_id].bounding_box);
}
return global_box;
@@ -161,7 +196,7 @@ private:
std::sort(leafs.begin() + begin, leafs.begin() + end,
[&](const bvh_node& a, const bvh_node& b) {
- return spheres[a.sphere_id].center[split_axis] < spheres[b.sphere_id].center[split_axis];
+ return spheres[a.primitive_id].center[split_axis] < spheres[b.primitive_id].center[split_axis];
}
);
@@ -191,10 +226,13 @@ private:
}
public:
- std::vector<bvh_node> nodes;
+ std::vector<bvh_node>& nodes;
std::vector<temp_node> temp_nodes;
std::vector<temp_node> leafs;
- sphere* spheres;
+
+ std::vector<sphere>& spheres;
+ // std::vector<triangle>& triangles;
+
uint32_t next_node_id = 0;
};
diff --git a/include/gltf.hpp b/include/gltf.hpp
new file mode 100644
index 0000000..80f2749
--- /dev/null
+++ b/include/gltf.hpp
@@ -0,0 +1,34 @@
+#ifndef __GLTF_HPP_
+#define __GLTF_HPP_
+
+#include <filesystem>
+#include <vector>
+
+#include <nlohmann/json.hpp>
+
+using json = nlohmann::json;
+
+#include <vec3.hpp>
+
+struct mesh_part {
+ std::vector<uint16_t> indices;
+ std::vector<vec3> positions;
+ std::vector<vec3> normals;
+};
+
+struct mesh {
+ std::vector<std::vector<mesh_part>> nodes;
+};
+
+class gltf {
+public:
+ static mesh load(std::filesystem::path &path, std::string &filename);
+
+private:
+
+ static void load_node(json &gltf_json, json &node, std::vector<std::vector<uint8_t>> &buffers_content, mesh& gltf_mesh);
+
+ static void load_primitive(json &gltf_json, json &primitive, std::vector<std::vector<uint8_t>> &buffers_content, mesh& gltf_mesh);
+};
+
+#endif
diff --git a/include/scene.hpp b/include/scene.hpp
index b7e1100..364e3a7 100644
--- a/include/scene.hpp
+++ b/include/scene.hpp
@@ -3,39 +3,48 @@
#include "vec3.hpp"
#include "sphere.hpp"
+#include "triangle.hpp"
#include "camera.hpp"
#include "bvh-node.hpp"
class scene {
-public:
- scene(uint32_t width, uint32_t height);
+ struct metadata {
+ color sky_color = { 0.5, 0.7, 1.0 };
+ color ground_color = { 1.0, 1.0, 1.0 };
+
+ camera cam;
- color sky_color = { 0.5, 0.7, 1.0 };
- color ground_color = { 1.0, 1.0, 1.0 };
+ uint32_t max_bounce = 50;
- camera cam;
+ // Output image resolution
+ uint32_t width;
+ uint32_t height;
- sphere spheres[512] = {};
- bvh_node nodes[1024] = {};
+ uint32_t sample_index = 0;
- uint32_t max_bounce = 50;
+ uint32_t spheres_count = 0;
+ // uint32_t triangles_count = 0;
+ uint32_t enable_dof = true;
+ uint32_t debug_bvh = false;
+ uint32_t padding;
- // Output image resolution
- uint32_t width;
- uint32_t height;
+ metadata(camera cam, uint32_t width, uint32_t height)
+ : cam(cam), width(width), height(height) {}
+ };
- uint32_t sample_index = 0;
+ void random_scene();
- uint32_t spheres_count = 0;
- uint32_t enable_dof = true;
- uint32_t debug_bvh = false;
- uint32_t padding;
+public:
+ scene(camera cam, uint32_t width, uint32_t height);
-private:
+ metadata meta;
- uint32_t random_scene(sphere* world);
+ // Geometry & BVH
+ std::vector<sphere> spheres;
+ // std::vector<triangle> triangles;
+ std::vector<bvh_node> nodes;
};
#endif // !__SCENE_HPP_
diff --git a/include/triangle.hpp b/include/triangle.hpp
new file mode 100644
index 0000000..12c0b69
--- /dev/null
+++ b/include/triangle.hpp
@@ -0,0 +1,25 @@
+#ifndef __TRIANGLE_HPP_
+#define __TRIANGLE_HPP_
+
+#include "aabb.hpp"
+#include "material.hpp"
+
+struct vertex {
+ vec3 position;
+ vec3 normal;
+};
+
+struct triangle {
+ triangle() = default;
+ triangle(vertex v1, vertex v2, vertex v3)
+ : v1(v1), v2(v2), v3(v3), bounding_box(v1.position, v2.position, v3.position)
+ {}
+
+ vertex v1;
+ vertex v2;
+ vertex v3;
+
+ aabb bounding_box;
+};
+
+#endif // !__TRIANGLE_HPP_
diff --git a/include/utils.hpp b/include/utils.hpp
index b00db81..e7178d8 100644
--- a/include/utils.hpp
+++ b/include/utils.hpp
@@ -2,6 +2,7 @@
#define __UTILS_HPP_
#include <string>
+#include <filesystem>
#include <vector>
std::vector<uint8_t> read_file(const char* path);
diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp
index b478b25..775ea89 100644
--- a/include/vk-renderer.hpp
+++ b/include/vk-renderer.hpp
@@ -11,7 +11,7 @@ class window;
class vkrenderer {
public:
- vkrenderer(window& wnd, size_t scene_buffer_size);
+ vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_buffer_size, size_t bvh_buffer_size);
~vkrenderer();
@@ -31,6 +31,14 @@ class vkrenderer {
return scene_buffer.alloc_info.pMappedData;
}
+ inline void* geometry_buffer_ptr() {
+ return geometry_buffer.alloc_info.pMappedData;
+ }
+
+ inline void* bvh_buffer_ptr() {
+ return bvh_buffer.alloc_info.pMappedData;
+ }
+
private:
void handle_swapchain_result(VkResult function_result);
@@ -52,6 +60,8 @@ class vkrenderer {
Pipeline compute_pipeline;
Buffer scene_buffer;
+ Buffer geometry_buffer;
+ Buffer bvh_buffer;
std::vector<VkDescriptorSetLayoutBinding> tonemapping_sets_bindings;
diff --git a/shaders/compute.comp b/shaders/compute.comp
index 2f6c5f5..75b7696 100644
--- a/shaders/compute.comp
+++ b/shaders/compute.comp
@@ -43,6 +43,17 @@ struct sphere {
float[3] padding;
};
+struct vertex {
+ vec4 position;
+ vec4 normal;
+};
+struct triangle {
+ vertex v1;
+ vertex v2;
+ vertex v3;
+ aabb bb;
+};
+
struct camera {
vec4 position;
@@ -61,31 +72,38 @@ struct camera {
struct bvh_node {
aabb bb;
int next_id;
- int sphere_id;
+ int primitive_id;
uint[2] padding;
};
-layout(set = 0, binding = 0) buffer Inputs {
+layout(set = 0, binding = 0) buffer scene_metadata {
vec4 sky_color;
vec4 ground_color;
camera cam;
- sphere[512] spheres;
- bvh_node[1024] nodes;
-
uint max_bounce;
uint width;
uint height;
uint sample_index;
uint spheres_count;
+ // uint triangles_count;
bool enable_dof;
bool debug_bvh;
uint padding;
};
-layout(set = 0, binding = 1, rgba32f) uniform writeonly image2D output_image;
-layout(set = 0, binding = 2, rgba32f) uniform readonly image2D accumulation_image;
+layout(set = 0, binding = 1) buffer geometry {
+ sphere[] spheres;
+ // triangle[] triangles;
+};
+
+layout(set = 0, binding = 2) buffer bvh {
+ bvh_node[] nodes;
+};
+
+layout(set = 0, binding = 3, rgba32f) uniform writeonly image2D output_image;
+layout(set = 0, binding = 4, rgba32f) uniform readonly image2D accumulation_image;
vec3 at(ray r, float t) {
return r.origin + r.direction * t;
@@ -112,6 +130,14 @@ vec3 unit_vec(inout uint seed) {
return vec3(cos(a) * r, sin(a) * r, z);
}
+vec3 diffuse_reflection_cosine_weighted(inout uint seed) {
+ float r = rand(seed);
+ float radius = sqrt(r);
+ float theta = 2.0 * PI * rand(seed);
+
+ return vec3(cos(theta) * radius, sin(theta) * radius, sqrt(1 - r));
+}
+
vec2 disk_vec(inout uint seed) {
float z = rand(seed) * 2.0 - 1.0;
float a = 2.0 * PI * rand(seed);
@@ -137,10 +163,12 @@ bool hit_aabb(aabb b, ray r, float min_t, float max_t) {
uint hit_aabbs(ray r, float min_t, float max_t) {
uint hit_count = 0;
for (uint idx = 0; idx <= spheres_count * 2; idx++) {
+ // for (uint idx = 0; idx <= triangles_count * 2; idx++) {
hit_count += uint(hit_aabb(nodes[idx].bb, r, min_t, max_t));
- if (nodes[idx].sphere_id >= 0) {
- hit_count += uint(hit_aabb(spheres[nodes[idx].sphere_id].bb, r, min_t, max_t));
+ if (nodes[idx].primitive_id >= 0) {
+ hit_count += uint(hit_aabb(spheres[nodes[idx].primitive_id].bb, r, min_t, max_t));
+ // hit_count += uint(hit_aabb(triangles[nodes[idx].primitive_id].bb, r, min_t, max_t));
}
}
@@ -180,6 +208,33 @@ bool hit_sphere(sphere s, ray r, float min_t, float max_t, out hit_info info) {
return true;
}
+bool hit_triangle(triangle tri, ray r, float min_t, float max_t, out hit_info info) {
+ vec3 v2v1 = tri.v2.position.xyz - tri.v1.position.xyz;
+ vec3 v3v1 = tri.v3.position.xyz - tri.v1.position.xyz;
+
+ vec3 originv1 = r.origin - tri.v1.position.xyz;
+ vec3 normal = cross(v2v1, v3v1);
+ vec3 q = cross(originv1, r.direction);
+ float d = 1 / dot(r.direction, normal);
+ float u = d * dot(-q, v3v1);
+ float v = d * dot(q, v2v1);
+ float t = d * dot(-normal, originv1);
+
+ if (u < 0 || u > 1 || v < 0|| u + v > 1) {
+ return false;
+ }
+
+ info.t = t;
+ info.point = at(r, info.t);
+
+ vec3 outward_normal = normal;
+ info.front_face = dot(outward_normal, r.direction) < 0.0;
+ info.normal = info.front_face ? outward_normal : -outward_normal;
+ info.mat = material(vec4(1.0), vec4(0.0), 1.0, 1.5, LAMBERTIAN_MATERIAL, 0);
+
+ return true;
+}
+
bool hit_node(ray r, float min_t, float max_t, out hit_info info) {
hit_info temp_info;
float closest_t = max_t;
@@ -188,12 +243,17 @@ bool hit_node(ray r, float min_t, float max_t, out hit_info info) {
while(id != -1) {
// Leafs
- if (nodes[id].sphere_id != -1) {
- if (hit_sphere(spheres[nodes[id].sphere_id], r, min_t, closest_t, temp_info)) {
+ if (nodes[id].primitive_id != -1) {
+ if (hit_sphere(spheres[nodes[id].primitive_id], r, min_t, closest_t, temp_info)) {
info = temp_info;
closest_t = temp_info.t;
hit = true;
}
+ // if (hit_triangle(triangles[nodes[id].primitive_id], r, min_t, closest_t, temp_info)) {
+ // info = temp_info;
+ // closest_t = temp_info.t;
+ // hit = true;
+ // }
id = nodes[id].next_id;
} else { // Internal nodes
if (hit_aabb(nodes[id].bb, r, min_t, closest_t)) {
@@ -211,6 +271,10 @@ bool hit_spheres(ray r, float min_t, float max_t, out hit_info info) {
return hit_node(r, min_t, max_t, info);
}
+bool hit_triangles(ray r, float min_t, float max_t, out hit_info info) {
+ return hit_node(r, min_t, max_t, info);
+}
+
bool lambertian_scattering(material mat, ray incident, inout uint seed, hit_info info, out vec4 attenuation, out ray scattered) {
attenuation = mat.albedo;
scattered = ray(info.point, normalize(info.normal + unit_vec(seed)));
@@ -263,14 +327,21 @@ vec4 ray_color(ray r, uint seed) {
vec4 throughput = vec4(1.0);
ray current_ray = r;
while (hit_spheres(current_ray, 0.001, 1e15, info) && bounces < max_bounce) {
+ // while (hit_triangles(current_ray, 0.001, 1e15, info) && bounces < max_bounce) {
ray scattered;
vec4 attenuation = vec4(0.0);
- if ((info.mat.type == LAMBERTIAN_MATERIAL && lambertian_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
- (info.mat.type == METAL_MATERIAL && metal_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
- (info.mat.type == DIELECTRIC_MATERIAL && dielectric_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
- info.mat.type == EMISSIVE_MATERIAL) {
+ // if ((info.mat.type == LAMBERTIAN_MATERIAL && lambertian_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
+ // (info.mat.type == METAL_MATERIAL && metal_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
+ // (info.mat.type == DIELECTRIC_MATERIAL && dielectric_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
+ // info.mat.type == EMISSIVE_MATERIAL) {
+ lambertian_scattering(info.mat, current_ray, seed, info, attenuation, scattered);
final_color += info.mat.emissive * throughput;
throughput *= attenuation;
+
+ // float NdotR = dot(info.normal, scattered.direction);
+ // float PDF = NdotR / PI;
+ // vec4 BRDF = attenuation / PI;
+ // throughput = (throughput * NdotR / PDF) * BRDF;
current_ray = scattered;
// Russian Roulette
@@ -285,11 +356,12 @@ vec4 ray_color(ray r, uint seed) {
// // Add the energy we 'lose' by randomly terminating paths
// throughput *= 1.0 / p;
// }
- }
+ // }
bounces++;
}
return throughput;
+ // return final_color;
}
void main() {
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b2b34b6..b871d67 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,3 +1,5 @@
+find_package(nlohmann_json CONFIG REQUIRED)
+
add_definitions(-DNOMINMAX -D_USE_MATH_DEFINES)
include_directories(${CMAKE_SOURCE_DIR}/include)
@@ -22,6 +24,7 @@ add_executable(
vk-api.cpp
window.cpp
scene.cpp
+ gltf.cpp
)
if(UNIX AND NOT APPLE)
@@ -29,3 +32,4 @@ if(UNIX AND NOT APPLE)
endif()
target_link_libraries(path-tracer PRIVATE ${LIBRARIES})
+target_link_libraries(path-tracer PRIVATE nlohmann_json nlohmann_json::nlohmann_json)
diff --git a/src/gltf.cpp b/src/gltf.cpp
new file mode 100644
index 0000000..0e74aaf
--- /dev/null
+++ b/src/gltf.cpp
@@ -0,0 +1,104 @@
+#include "gltf.hpp"
+
+#include <fstream>
+#include <cstring>
+
+#include "utils.hpp"
+
+mesh gltf::load(std::filesystem::path &path, std::string &filename) {
+ std::fstream f(path / filename);
+ json gltf_json;
+
+ f >> gltf_json;
+
+ auto scene_index = gltf_json["scene"].get<uint32_t>();
+ auto scenes = gltf_json["scenes"];
+ auto scene = scenes[scene_index];
+
+ auto buffers = gltf_json["buffers"];
+ auto buffer_index = 0;
+ auto buffers_content = std::vector<std::vector<uint8_t>>(buffers.size());
+ for (auto &buffer: buffers) {
+ auto buffer_path = (path / buffer["uri"].get<std::string>()).string();
+ buffers_content[buffer_index] = read_file(buffer_path);
+ buffer_index++;
+ }
+
+ auto nodes = gltf_json["nodes"];
+ auto gltf_mesh = mesh();
+
+ for (auto &node: nodes) {
+ gltf_mesh.nodes.push_back(std::vector<mesh_part>());
+ load_node(gltf_json, node, buffers_content, gltf_mesh);
+ }
+
+ // return std::move(gltf_mesh);
+ return gltf_mesh;
+}
+
+void gltf::load_node(json &gltf_json, json &node, std::vector<std::vector<uint8_t>> &buffers_content, mesh& gltf_mesh) {
+ auto mesh_index = node["mesh"].get<uint32_t>();
+ auto mesh = gltf_json["meshes"][mesh_index];
+ auto primitives = mesh["primitives"];
+
+ for (auto &primitive: primitives) {
+ gltf_mesh.nodes.back().push_back(mesh_part());
+ load_primitive(gltf_json, primitive, buffers_content, gltf_mesh);
+ }
+}
+
+void gltf::load_primitive(json &gltf_json, json &primitive, std::vector<std::vector<uint8_t>> &buffers_content, mesh& gltf_mesh) {
+ auto accessors = gltf_json["accessors"];
+ auto &mesh_part = gltf_mesh.nodes.back().back();
+
+ {
+ auto indices_accessor_index = primitive["indices"].get<uint32_t>();
+ auto indices_view_index = accessors[indices_accessor_index]["bufferView"].get<uint32_t>();
+ auto indices_view = gltf_json["bufferViews"][indices_view_index];
+
+ auto indices_buffer_index = indices_view["buffer"].get<uint32_t>();
+ auto indices_offset = indices_view["byteOffset"].get<size_t>();
+ auto indices_length = indices_view["byteLength"].get<size_t>();
+
+ auto indices_buffer = buffers_content[indices_buffer_index];
+ void* indices_start = indices_buffer.data() + indices_offset;
+
+ mesh_part.indices.resize(indices_length / sizeof(uint16_t));
+
+ std::memcpy(mesh_part.indices.data(), indices_start, indices_length);
+ }
+
+ {
+ auto positions_accessor_index = primitive["attributes"]["POSITION"].get<uint32_t>();
+ auto positions_view_index = accessors[positions_accessor_index]["bufferView"].get<uint32_t>();
+ auto positions_view = gltf_json["bufferViews"][positions_view_index];
+
+ auto positions_buffer_index = positions_view["buffer"].get<uint32_t>();
+ auto positions_offset = positions_view["byteOffset"].get<size_t>();
+ auto positions_length = positions_view["byteLength"].get<size_t>();
+
+ auto positions_buffer = buffers_content[positions_buffer_index];
+ void* positions_start = positions_buffer.data() + positions_offset;
+
+ mesh_part.positions.resize(positions_length / (sizeof(float) * 3));
+
+ std::memcpy(mesh_part.positions.data(), positions_start, positions_length);
+ }
+
+ {
+ auto normals_accessor_index = primitive["attributes"]["NORMAL"].get<uint32_t>();
+ auto normals_view_index = accessors[normals_accessor_index]["bufferView"].get<uint32_t>();
+ auto normals_view = gltf_json["bufferViews"][normals_view_index];
+
+ auto normals_buffer_index = normals_view["buffer"].get<uint32_t>();
+ auto normals_offset = normals_view["byteOffset"].get<size_t>();
+ auto normals_length = normals_view["byteLength"].get<size_t>();
+
+ auto normals_buffer = buffers_content[normals_buffer_index];
+ void* normals_start = normals_buffer.data() + normals_offset;
+
+ mesh_part.normals.resize(normals_length / (sizeof(float) * 3));
+
+ std::memcpy(mesh_part.normals.data(), normals_start, normals_length);
+ }
+}
diff --git a/src/main.cpp b/src/main.cpp
index 3678f2a..875527f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -54,12 +54,22 @@ int main() {
uint64_t frame_count = 0;
auto start = std::chrono::high_resolution_clock::now();
auto end = std::chrono::high_resolution_clock::now();
- auto main_scene = scene(width, height);
+
+ point3 position = { 13.0, 2.0, 3.0 };
+ point3 target = { 0.0, 0.0, 0.0 };
+ auto v_fov = 20;
+ auto aperture = 0.1;
+ auto focus_distance = 10;
+ auto cam = camera(position, target, v_fov, (float)width / (float)height, aperture, focus_distance);
+ auto main_scene = scene(cam, width, height);
auto can_render = true;
- vkrenderer renderer { wnd, sizeof(main_scene) };
+ // vkrenderer renderer { wnd, sizeof(main_scene.meta), sizeof(main_scene.triangles[0]) * main_scene.triangles.size(), sizeof(main_scene.nodes[0]) * main_scene.nodes.size() };
+ vkrenderer renderer { wnd, sizeof(main_scene.meta), sizeof(main_scene.spheres[0]) * main_scene.spheres.size(), sizeof(main_scene.nodes[0]) * main_scene.nodes.size() };
- // Upload scene
- std::memcpy(renderer.scene_buffer_ptr(), &main_scene, sizeof(main_scene));
+ // Upload scene content
+ std::memcpy(renderer.scene_buffer_ptr(), &main_scene.meta, sizeof(main_scene.meta));
+ std::memcpy(renderer.geometry_buffer_ptr(), main_scene.spheres.data(), sizeof(main_scene.spheres[0]) * main_scene.spheres.size());
+ std::memcpy(renderer.bvh_buffer_ptr(), main_scene.nodes.data(), sizeof(main_scene.nodes[0]) * main_scene.nodes.size());
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize.x = (float)width;
@@ -85,8 +95,8 @@ int main() {
width = event.width;
height = event.height;
- ((scene*) renderer.scene_buffer_ptr())->width = width;
- ((scene*) renderer.scene_buffer_ptr())->height = height;
+ ((scene*) renderer.scene_buffer_ptr())->meta.width = width;
+ ((scene*) renderer.scene_buffer_ptr())->meta.height = height;
io.DisplaySize.x = (float)width;
io.DisplaySize.y = (float)height;
@@ -96,8 +106,8 @@ int main() {
} else {
can_render = true;
renderer.recreate_swapchain();
- ((scene*) renderer.scene_buffer_ptr())->cam.set_aspect_ratio((float)event.width / (float)event.height);
- ((scene*) renderer.scene_buffer_ptr())->sample_index = 0;
+ ((scene*) renderer.scene_buffer_ptr())->meta.cam.set_aspect_ratio((float)event.width / (float)event.height);
+ ((scene*) renderer.scene_buffer_ptr())->meta.sample_index = 0;
}
reset_accumulation = true;
@@ -114,44 +124,44 @@ int main() {
switch (event.key) {
case KEYS::W: {
- move_vec = ((scene*) renderer.scene_buffer_ptr())->cam.forward.unit() * move_speed;
+ move_vec = ((scene*) renderer.scene_buffer_ptr())->meta.cam.forward.unit() * move_speed;
break;
}
case KEYS::S: {
- move_vec = -((scene*) renderer.scene_buffer_ptr())->cam.forward.unit() * move_speed;
+ move_vec = -((scene*) renderer.scene_buffer_ptr())->meta.cam.forward.unit() * move_speed;
break;
}
case KEYS::D: {
- move_vec = ((scene*) renderer.scene_buffer_ptr())->cam.right.unit() * move_speed;
+ move_vec = ((scene*) renderer.scene_buffer_ptr())->meta.cam.right.unit() * move_speed;
break;
}
case KEYS::A: {
- move_vec = -((scene*) renderer.scene_buffer_ptr())->cam.right.unit() * move_speed;
+ move_vec = -((scene*) renderer.scene_buffer_ptr())->meta.cam.right.unit() * move_speed;
break;
}
case KEYS::E: {
- ((scene*) renderer.scene_buffer_ptr())->cam.rotate_y(0.001f * delta_time);
+ ((scene*) renderer.scene_buffer_ptr())->meta.cam.rotate_y(0.001f * delta_time);
reset_accumulation = true;
break;
}
case KEYS::Q: {
- ((scene*) renderer.scene_buffer_ptr())->cam.rotate_y(-0.001f * delta_time);
+ ((scene*) renderer.scene_buffer_ptr())->meta.cam.rotate_y(-0.001f * delta_time);
reset_accumulation = true;
break;
}
case KEYS::SPACE: {
- move_vec = ((scene*) renderer.scene_buffer_ptr())->cam.up.unit() * move_speed;
+ move_vec = ((scene*) renderer.scene_buffer_ptr())->meta.cam.up.unit() * move_speed;
break;
}
case KEYS::CTRL: {
- move_vec = -((scene*) renderer.scene_buffer_ptr())->cam.up.unit() * move_speed;
+ move_vec = -((scene*) renderer.scene_buffer_ptr())->meta.cam.up.unit() * move_speed;
break;
}
default:
break;
}
- ((scene*) renderer.scene_buffer_ptr())->cam.move(move_vec);
+ ((scene*) renderer.scene_buffer_ptr())->meta.cam.move(move_vec);
if (!move_vec.near_zero()) {
reset_accumulation = true;
@@ -200,15 +210,15 @@ int main() {
ImGui::Text("frame per second %u\n", static_cast<uint32_t>(1000.f / delta_time));
ImGui::Text("frame time %f ms\n", delta_time);
- ImGui::Text("frame count %u\n", ((scene*) renderer.scene_buffer_ptr())->sample_index);
+ ImGui::Text("frame count %u\n", ((scene*) renderer.scene_buffer_ptr())->meta.sample_index);
- if (ImGui::Checkbox("depth of field", (bool*)&((scene*) renderer.scene_buffer_ptr())->enable_dof)) {
+ if (ImGui::Checkbox("depth of field", (bool*)&((scene*) renderer.scene_buffer_ptr())->meta.enable_dof)) {
reset_accumulation = true;
}
- ImGui::SliderInt("bounces", (int32_t*)&((scene*) renderer.scene_buffer_ptr())->max_bounce, 2, 250);
+ ImGui::SliderInt("bounces", (int32_t*)&((scene*) renderer.scene_buffer_ptr())->meta.max_bounce, 2, 250);
- if (ImGui::Checkbox("debug bvh", (bool*)&((scene*) renderer.scene_buffer_ptr())->debug_bvh)) {
+ if (ImGui::Checkbox("debug bvh", (bool*)&((scene*) renderer.scene_buffer_ptr())->meta.debug_bvh)) {
reset_accumulation = true;
}
@@ -226,13 +236,13 @@ int main() {
renderer.begin_frame();
if (reset_accumulation) {
- ((scene*) renderer.scene_buffer_ptr())->sample_index = 0;
+ ((scene*) renderer.scene_buffer_ptr())->meta.sample_index = 0;
renderer.reset_accumulation();
}
renderer.compute(width, height);
- ((scene*) renderer.scene_buffer_ptr())->sample_index++;
+ ((scene*) renderer.scene_buffer_ptr())->meta.sample_index++;
renderer.ui();
diff --git a/src/scene.cpp b/src/scene.cpp
index 68929d8..9fd57eb 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -1,14 +1,15 @@
#include "scene.hpp"
+#include <filesystem>
+
#include "utils.hpp"
+#include "gltf.hpp"
// Return the number of instantiated spheres
-uint32_t scene::random_scene(sphere *world) {
+void scene::random_scene() {
material ground_material = { { 0.5, 0.5, 0.5 } };
ground_material.type = MATERIAL_TYPE::LAMBERTIAN;
- world[0] = sphere{ { 0, -1000, 0 }, ground_material, 1000 };
-
- uint32_t world_sphere_index = 1;
+ spheres.emplace_back(vec3 { 0, -1000, 0 }, ground_material, 1000);
int32_t spheres_count = 11;
for (int a = -spheres_count; a < spheres_count; a++) {
@@ -34,8 +35,7 @@ uint32_t scene::random_scene(sphere *world) {
sphere_material.type = MATERIAL_TYPE::DIELECTRIC;
}
- world[world_sphere_index] = { center, sphere_material, 0.2 };
- world_sphere_index++;
+ spheres.emplace_back(center, sphere_material, 0.2);
}
}
}
@@ -43,34 +43,55 @@ uint32_t scene::random_scene(sphere *world) {
material material1 = {};
material1.ior = 1.5;
material1.type = MATERIAL_TYPE::DIELECTRIC;
- world[world_sphere_index] = { { 0, 1, 0 }, material1, 1.0 };
+ spheres.emplace_back(vec3 { 0, 1, 0 }, material1, 1.0);
material material2 = {};
material2.albedo = color{ 0.4, 0.2, 0.1 };
material2.type = MATERIAL_TYPE::LAMBERTIAN;
- world[world_sphere_index + 1] = { { -4, 1, 0 }, material2, 1.0 };
+ spheres.emplace_back(vec3 { -4, 1, 0 }, material2, 1.0);
material material3 = {};
material3.albedo = color{ 0.7, 0.6, 0.5 };
material3.fuzz = 0.0;
material3.type = MATERIAL_TYPE::METAL;
- world[world_sphere_index + 2] = { { 4, 1, 0 }, material3, 1.0 };
+ spheres.emplace_back(vec3 { 4, 1, 0 }, material3, 1.0);
material material4 = {};
material4.albedo = color{ 0.0, 0.0, 0.0 };
material4.emissive = color{ 1.0, 1.0, 1.0 } * 1000.0;
material4.fuzz = 0.0;
material4.type = MATERIAL_TYPE::EMISSIVE;
- world[world_sphere_index + 3] = { { 2, 1.5, 2 }, material4, 0.5 };
+ spheres.emplace_back(vec3 { 2, 1.5, 2 }, material4, 0.5);
- return world_sphere_index + 4;
+ spheres_count = spheres.size();
}
-scene::scene(uint32_t width, uint32_t height)
- :width(width), height(height), spheres_count(random_scene(spheres)),
- cam({ 13.0, 2.0, 3.0 }, { 0.0, 0.0, 0.0 }, 20.0, (float)width / (float)height, 0.1, 10) {
- bvh builder;
- builder.build(spheres, spheres_count);
+scene::scene(camera cam, uint32_t width, uint32_t height)
+ :meta(cam, width, height){
+
+ // auto sponza_path = std::filesystem::path("../models/sponza");
+ // auto sponza_filename = std::string("Sponza.gltf");
+ // auto mesh = gltf::load(sponza_path, sponza_filename);
+
+ // auto node = mesh.nodes[0];
+ // for (auto& mesh_part: node) {
+ // for (size_t i = 0; i < mesh_part.indices.size(); i += 3) {
+ // auto i1 = mesh_part.indices[i];
+ // auto i2 = mesh_part.indices[i + 1];
+ // auto i3 = mesh_part.indices[i + 2];
+
+ // auto v1 = vertex { .position = mesh_part.positions[i1], .normal = mesh_part.normals[i1] };
+ // auto v2 = vertex { .position = mesh_part.positions[i2], .normal = mesh_part.normals[i2] };
+ // auto v3 = vertex { .position = mesh_part.positions[i3], .normal = mesh_part.normals[i3] };
+
+ // triangles.emplace_back(v1, v2, v3);
+ // }
+ // }
+
+ random_scene();
+
+ // bvh builder(triangles, nodes);
+ bvh builder(spheres, nodes);
// builder.exporter();
for (uint32_t idx = 0; idx < builder.nodes.size(); idx++) {
diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp
index caa27f8..b31d934 100644
--- a/src/vk-renderer.cpp
+++ b/src/vk-renderer.cpp
@@ -24,7 +24,7 @@ struct UiTransforms {
float translate_x, translate_y;
};
-vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size) {
+vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_buffer_size, size_t bvh_buffer_size) {
platform_surface = api.create_surface(wnd);
swapchain = api.create_swapchain(
platform_surface,
@@ -45,13 +45,27 @@ vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size) {
},
{
.binding = 1,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = VK_NULL_HANDLE,
},
{
.binding = 2,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = VK_NULL_HANDLE,
+ },
+ {
+ .binding = 3,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
+ .pImmutableSamplers = VK_NULL_HANDLE,
+ },
+ {
+ .binding = 4,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
@@ -94,9 +108,13 @@ vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size) {
acquire_semaphores = api.create_semaphores(swapchain.image_count);
scene_buffer = api.create_buffer(scene_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ geometry_buffer = api.create_buffer(geometry_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ bvh_buffer = api.create_buffer(bvh_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
for (size_t index = 0; index < swapchain.image_count; index++) {
api.update_descriptor_set_buffer(compute_shader_sets[index], compute_sets_bindings[0], scene_buffer);
+ api.update_descriptor_set_buffer(compute_shader_sets[index], compute_sets_bindings[1], geometry_buffer);
+ api.update_descriptor_set_buffer(compute_shader_sets[index], compute_sets_bindings[2], bvh_buffer);
}
std::vector<VkFormat> attachments_format { swapchain.surface_format.format };
@@ -215,6 +233,8 @@ vkrenderer::~vkrenderer() {
VKRESULT(vkWaitForFences(api.context.device, submission_fences.size(), submission_fences.data(), VK_TRUE, UINT64_MAX))
api.destroy_buffer(scene_buffer);
+ api.destroy_buffer(geometry_buffer);
+ api.destroy_buffer(bvh_buffer);
api.destroy_fences(submission_fences);
api.destroy_semaphores(execution_semaphores);
api.destroy_semaphores(acquire_semaphores);
@@ -308,8 +328,8 @@ void vkrenderer::begin_frame() {
auto output_image = accumulation_images[0];
auto accumulation_image = accumulation_images[1];
- api.update_descriptor_set_image(compute_shader_sets[swapchain_image_index], compute_sets_bindings[1], output_image.view, VK_NULL_HANDLE);
- api.update_descriptor_set_image(compute_shader_sets[swapchain_image_index], compute_sets_bindings[2], accumulation_image.view, VK_NULL_HANDLE);
+ api.update_descriptor_set_image(compute_shader_sets[swapchain_image_index], compute_sets_bindings[3], output_image.view, VK_NULL_HANDLE);
+ api.update_descriptor_set_image(compute_shader_sets[swapchain_image_index], compute_sets_bindings[4], accumulation_image.view, VK_NULL_HANDLE);
api.update_descriptor_set_image(tonemapping_shader_sets[swapchain_image_index], tonemapping_sets_bindings[0], swapchain.images[swapchain_image_index].view, VK_NULL_HANDLE);
api.update_descriptor_set_image(tonemapping_shader_sets[swapchain_image_index], tonemapping_sets_bindings[1], output_image.view, VK_NULL_HANDLE);