From 3dd870b001bef62aaa501257352d968d1346c7f2 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Sun, 25 Jul 2021 11:58:01 +0200 Subject: Use a different buffer for scene info, geometry, bvh and load gltf --- include/aabb.hpp | 9 +++++ include/bvh-node.hpp | 74 +++++++++++++++++++++++++--------- include/gltf.hpp | 34 ++++++++++++++++ include/scene.hpp | 45 ++++++++++++--------- include/triangle.hpp | 25 ++++++++++++ include/utils.hpp | 1 + include/vk-renderer.hpp | 12 +++++- shaders/compute.comp | 104 ++++++++++++++++++++++++++++++++++++++++-------- src/CMakeLists.txt | 4 ++ src/gltf.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 56 +++++++++++++++----------- src/scene.cpp | 53 ++++++++++++++++-------- src/vk-renderer.cpp | 28 +++++++++++-- 13 files changed, 453 insertions(+), 96 deletions(-) create mode 100644 include/gltf.hpp create mode 100644 include/triangle.hpp create mode 100644 src/gltf.cpp 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(2 * spheres_count - 1); - temp_nodes = std::vector(2 * spheres_count - 1); - leafs = std::vector(spheres_count); - this->spheres = spheres; + bvh(std::vector& spheres, std::vector& nodes) + :spheres(spheres), nodes(nodes) { + nodes = std::vector(2 * spheres.size() - 1); + temp_nodes = std::vector(2 * spheres.size() - 1); + leafs = std::vector(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& triangles, std::vector& nodes) + // :triangles(triangles), nodes(nodes) { + // nodes.resize(2 * triangles.size() - 1); + // temp_nodes = std::vector(2 * triangles.size() - 1); + // leafs = std::vector(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 nodes; + std::vector& nodes; std::vector temp_nodes; std::vector leafs; - sphere* spheres; + + std::vector& spheres; + // std::vector& 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 +#include + +#include + +using json = nlohmann::json; + +#include + +struct mesh_part { + std::vector indices; + std::vector positions; + std::vector normals; +}; + +struct mesh { + std::vector> 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> &buffers_content, mesh& gltf_mesh); + + static void load_primitive(json &gltf_json, json &primitive, std::vector> &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 spheres; + // std::vector triangles; + std::vector 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 +#include #include std::vector 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 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 +#include + +#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(); + auto scenes = gltf_json["scenes"]; + auto scene = scenes[scene_index]; + + auto buffers = gltf_json["buffers"]; + auto buffer_index = 0; + auto buffers_content = std::vector>(buffers.size()); + for (auto &buffer: buffers) { + auto buffer_path = (path / buffer["uri"].get()).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()); + 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> &buffers_content, mesh& gltf_mesh) { + auto mesh_index = node["mesh"].get(); + 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> &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(); + auto indices_view_index = accessors[indices_accessor_index]["bufferView"].get(); + auto indices_view = gltf_json["bufferViews"][indices_view_index]; + + auto indices_buffer_index = indices_view["buffer"].get(); + auto indices_offset = indices_view["byteOffset"].get(); + auto indices_length = indices_view["byteLength"].get(); + + 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(); + auto positions_view_index = accessors[positions_accessor_index]["bufferView"].get(); + auto positions_view = gltf_json["bufferViews"][positions_view_index]; + + auto positions_buffer_index = positions_view["buffer"].get(); + auto positions_offset = positions_view["byteOffset"].get(); + auto positions_length = positions_view["byteLength"].get(); + + 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(); + auto normals_view_index = accessors[normals_accessor_index]["bufferView"].get(); + auto normals_view = gltf_json["bufferViews"][normals_view_index]; + + auto normals_buffer_index = normals_view["buffer"].get(); + auto normals_offset = normals_view["byteOffset"].get(); + auto normals_length = normals_view["byteLength"].get(); + + 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(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 + #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 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); -- cgit v1.3