aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/aabb.hpp24
-rw-r--r--include/gltf.hpp10
-rw-r--r--include/scene.hpp20
-rw-r--r--include/triangle.hpp21
-rw-r--r--include/vk-api.hpp1
-rw-r--r--include/vk-renderer.hpp25
-rw-r--r--shaders/compute.comp67
-rw-r--r--shaders/include/brdf.h99
-rw-r--r--shaders/include/color_utils.h26
-rw-r--r--shaders/include/math.h45
-rw-r--r--shaders/include/rand.h12
-rw-r--r--shaders/include/ray.h155
-rw-r--r--shaders/tonemapping.comp4
-rw-r--r--shaders/ui.frag2
-rw-r--r--shaders/ui.vert2
-rw-r--r--src/gltf.cpp34
-rw-r--r--src/main.cpp63
-rw-r--r--src/scene.cpp51
-rw-r--r--src/vk-api.cpp14
-rw-r--r--src/vk-renderer.cpp89
20 files changed, 550 insertions, 214 deletions
diff --git a/include/aabb.hpp b/include/aabb.hpp
index 5f819db..475c04e 100644
--- a/include/aabb.hpp
+++ b/include/aabb.hpp
@@ -12,22 +12,15 @@ class aabb {
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(triangle &tri) {
- auto &v1 = tri.v1.position;
- auto &v2 = tri.v2.position;
- auto &v3 = tri.v3.position;
-
- // 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);
+ auto &v1 = tri.p1;
+ auto &v2 = tri.p2;
+ auto &v3 = tri.p3;
+ // TODO: Use vector 3 functions
minimum.v[0] = fmin(fmin(v1.v[0], v2.v[0]), v3.v[0]);
minimum.v[1] = fmin(fmin(v1.v[1], v2.v[1]), v3.v[1]);
minimum.v[2] = fmin(fmin(v1.v[2], v2.v[2]), v3.v[2]);
- // 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);
-
maximum.v[0] = fmax(fmax(v1.v[0], v2.v[0]), v3.v[0]);
maximum.v[1] = fmax(fmax(v1.v[1], v2.v[1]), v3.v[1]);
maximum.v[2] = fmax(fmax(v1.v[2], v2.v[2]), v3.v[2]);
@@ -46,14 +39,6 @@ class aabb {
int32_t maximum_axis() {
vec3 diag = diagonal();
- // if (diag.x > diag.y && diag.x > diag.z) {
- // return 0;
- // } else if (diag.y > diag.z) {
- // return 1;
- // } else {
- // return 2;
- // }
-
if (diag.v[0] > diag.v[1] && diag.v[0] > diag.v[2]) {
return 0;
} else if (diag.v[1] > diag.v[2]) {
@@ -73,7 +58,6 @@ class aabb {
float surface_area() {
auto diag = diagonal();
- // return 2.f * (diag.x * diag.y + diag.x * diag.z + diag.y * diag.z);
return 2.f * (diag.v[0] * diag.v[1] + diag.v[0] * diag.v[2] + diag.v[1] * diag.v[2]);
}
diff --git a/include/gltf.hpp b/include/gltf.hpp
index 0a63ba6..7df5e7a 100644
--- a/include/gltf.hpp
+++ b/include/gltf.hpp
@@ -16,14 +16,18 @@ using json = nlohmann::json;
struct mesh_part {
std::vector<uint16_t> indices;
- std::vector<vec3> positions;
- std::vector<vec3> normals;
- std::vector<vec3> uvs;
+ std::vector<float> positions;
+ std::vector<float> normals;
+ std::vector<float> uvs;
material mat;
+ uint32_t triangles_count = 0;
+ uint32_t vertices_count = 0;
};
struct mesh {
std::vector<mesh_part> parts;
+ uint32_t triangles_count = 0;
+ uint32_t vertices_count = 0;
};
struct node {
diff --git a/include/scene.hpp b/include/scene.hpp
index 82ffb3d..2c945d4 100644
--- a/include/scene.hpp
+++ b/include/scene.hpp
@@ -34,11 +34,27 @@ class scene {
public:
scene(camera cam, uint32_t width, uint32_t height, vkrenderer &renderer);
+ void* scene_buffer_ptr() {
+ return scene_buffer.alloc_info.pMappedData;
+ }
+
metadata meta;
// Geometry & BVH
- // std::vector<sphere> spheres;
- std::vector<triangle> triangles;
+ std::vector<uint32_t> indices;
+ std::vector<float> positions;
+ std::vector<float> normals;
+ std::vector<float> uvs;
+ std::vector<material> materials;
+
+ Buffer scene_buffer;
+ Buffer indices_buffer;
+ Buffer positions_buffer;
+ Buffer normals_buffer;
+ Buffer uvs_buffer;
+ Buffer bvh_buffer;
+ Buffer materials_buffer;
+
std::vector<packed_bvh_node> packed_nodes;
};
diff --git a/include/triangle.hpp b/include/triangle.hpp
index 5a62aec..4d3550b 100644
--- a/include/triangle.hpp
+++ b/include/triangle.hpp
@@ -1,28 +1,21 @@
#ifndef __TRIANGLE_HPP_
#define __TRIANGLE_HPP_
-#include "material.hpp"
-
-struct vertex {
- vec3 position;
- vec3 normal;
- vec3 uv;
-};
+#include "vec3.hpp"
struct triangle {
triangle() = default;
- triangle(vertex v1, vertex v2, vertex v3, material mat)
- : v1(v1), v2(v2), v3(v3), mat(mat)
+ triangle(vec3 p1, vec3 p2, vec3 p3)
+ : p1(p1), p2(p2), p3(p3)
{}
vec3 center() {
- return (v1.position + v2.position + v3.position) / 3.f;
+ return (p1 + p2 + p3) / 3.f;
}
- vertex v1;
- vertex v2;
- vertex v3;
- material mat;
+ vec3 p1;
+ vec3 p2;
+ vec3 p3;
};
#endif // !__TRIANGLE_HPP_
diff --git a/include/vk-api.hpp b/include/vk-api.hpp
index 8612e00..7953817 100644
--- a/include/vk-api.hpp
+++ b/include/vk-api.hpp
@@ -49,7 +49,6 @@ struct global_descriptor {
VkPipelineLayout pipeline_layout;
VkDescriptorSet set;
- // TODO: Use constant here
std::vector<uint32_t> index_pool[3];
global_descriptor() {
diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp
index 78d7028..dada742 100644
--- a/include/vk-renderer.hpp
+++ b/include/vk-renderer.hpp
@@ -27,24 +27,18 @@ class vkrenderer {
void recreate_swapchain();
- void create_scene_buffer(size_t size);
-
- void create_geometry_buffer(size_t size);
-
- void create_bvh_buffer(size_t size);
-
- inline void* scene_buffer_ptr() {
- return scene_buffer.alloc_info.pMappedData;
- }
-
- void update_geometry_buffer(void* data);
-
- void update_bvh_buffer(void* data);
-
void update_image(image img, void* data, size_t size);
vkapi api;
+ VkDeviceAddress scene_buffer_addr;
+ VkDeviceAddress indices_buffer_addr;
+ VkDeviceAddress positions_buffer_addr;
+ VkDeviceAddress normals_buffer_addr;
+ VkDeviceAddress uvs_buffer_addr;
+ VkDeviceAddress bvh_buffer_addr;
+ VkDeviceAddress materials_buffer_addr;
+
private:
void handle_swapchain_result(VkResult function_result);
@@ -62,9 +56,6 @@ class vkrenderer {
Pipeline compute_pipeline;
- Buffer scene_buffer;
- Buffer geometry_buffer;
- Buffer bvh_buffer;
Buffer staging_buffer;
diff --git a/shaders/compute.comp b/shaders/compute.comp
index 015ef1e..2663592 100644
--- a/shaders/compute.comp
+++ b/shaders/compute.comp
@@ -6,12 +6,6 @@
#extension GL_EXT_buffer_reference : require
#extension GL_EXT_nonuniform_qualifier : require
-const float PI = 3.141592653589793f;
-const float TWO_PI = PI * 2.0f;
-
-const uint DIFFUSE = 1;
-const uint SPECULAR = 2;
-
#include "math.h"
#include "color_utils.h"
#include "rand.h"
@@ -52,7 +46,6 @@ struct triangle {
vertex v1;
vertex v2;
vertex v3;
- material mat;
};
struct camera {
@@ -91,9 +84,24 @@ layout(buffer_reference) readonly buffer scene_metadata {
int downscale_factor;
};
-layout(buffer_reference) readonly buffer primitives_array {
- // sphere[] spheres;
- triangle triangles[];
+layout(buffer_reference) readonly buffer indices_array {
+ uint indices[];
+};
+
+layout(buffer_reference) readonly buffer positions_array {
+ float positions[];
+};
+
+layout(buffer_reference) readonly buffer normals_array {
+ float normals[];
+};
+
+layout(buffer_reference) readonly buffer uvs_array {
+ float uvs[];
+};
+
+layout(buffer_reference) readonly buffer materials_array {
+ material materials[];
};
layout(buffer_reference) readonly buffer nodes_array {
@@ -106,8 +114,12 @@ layout(set = 0, binding = 2, rgba32f) uniform image2D images[];
layout(push_constant) uniform buffers {
scene_metadata scene;
- primitives_array geometry;
nodes_array bvh;
+ indices_array indices_arr;
+ positions_array positions_arr;
+ normals_array normals_arr;
+ uvs_array uvs_arr;
+ materials_array materials_arr;
uint output_image_index;
uint accumulation_image_index;
uint padding[2];
@@ -128,12 +140,36 @@ vec3 ray_color(ray r, uint seed) {
- // TODO: Interpolation function
- triangle tri = bufs.geometry.triangles[info.id];
+ // TODO: Interpolation function & indices decoding function
+ uint id1 = bufs.indices_arr.indices[info.id * 3] & 0x00ffffff;
+ uint id2 = bufs.indices_arr.indices[info.id * 3 + 1] & 0x00ffffff;
+ uint id3 = bufs.indices_arr.indices[info.id * 3 + 2] & 0x00ffffff;
+ uint mat_id = (bufs.indices_arr.indices[info.id * 3] & 0xff000000) >> 8
+ | (bufs.indices_arr.indices[info.id * 3 + 1] & 0xff000000) >> 16
+ | (bufs.indices_arr.indices[info.id * 3 + 2] & 0xff000000) >> 24;
+
+ vec3 p1 = vec3(bufs.positions_arr.positions[id1 * 3], bufs.positions_arr.positions[id1 * 3 + 1], bufs.positions_arr.positions[id1 * 3 + 2]);
+ vec3 p2 = vec3(bufs.positions_arr.positions[id2 * 3], bufs.positions_arr.positions[id2 * 3 + 1], bufs.positions_arr.positions[id2 * 3 + 2]);
+ vec3 p3 = vec3(bufs.positions_arr.positions[id3 * 3], bufs.positions_arr.positions[id3 * 3 + 1], bufs.positions_arr.positions[id3 * 3 + 2]);
+
+ vec3 n1 = vec3(bufs.normals_arr.normals[id1 * 3], bufs.normals_arr.normals[id1 * 3 + 1], bufs.normals_arr.normals[id1 * 3 + 2]);
+ vec3 n2 = vec3(bufs.normals_arr.normals[id2 * 3], bufs.normals_arr.normals[id2 * 3 + 1], bufs.normals_arr.normals[id2 * 3 + 2]);
+ vec3 n3 = vec3(bufs.normals_arr.normals[id3 * 3], bufs.normals_arr.normals[id3 * 3 + 1], bufs.normals_arr.normals[id3 * 3 + 2]);
+
+ vec2 uv1 = vec2(bufs.uvs_arr.uvs[id1 * 2], bufs.uvs_arr.uvs[id1 * 2 + 1]);
+ vec2 uv2 = vec2(bufs.uvs_arr.uvs[id2 * 2], bufs.uvs_arr.uvs[id2 * 2 + 1]);
+ vec2 uv3 = vec2(bufs.uvs_arr.uvs[id3 * 2], bufs.uvs_arr.uvs[id3 * 2 + 1]);
+
+ vertex v1 = vertex(p1, n1, uv1);
+ vertex v2 = vertex(p2, n2, uv2);
+ vertex v3 = vertex(p3, n3, uv3);
+
+ triangle tri = triangle(v1, v2, v3);
+
info.shading_normal = normalize(tri.v1.normal * info.barycentrics.x + tri.v2.normal * info.barycentrics.y + tri.v3.normal * info.barycentrics.z);
info.uv = tri.v1.uv * info.barycentrics.x + tri.v2.uv * info.barycentrics.y + tri.v3.uv * info.barycentrics.z;
- material mat = tri.mat;
+ material mat = bufs.materials_arr.materials[mat_id];
info.color = srgb_to_linear(texture(
sampler2D(
textures[nonuniformEXT(mat.base_color_texture.texture_id)],
@@ -149,12 +185,13 @@ vec3 ray_color(ray r, uint seed) {
+
if (dot(info.geometry_normal, v) < 0.f) info.geometry_normal = -info.geometry_normal;
if (dot(info.geometry_normal, info.shading_normal) < 0.0f) info.shading_normal = -info.shading_normal;
uint brdf_type;
- if (mat.metalness == 1.f && mat.metalness == 0.f) {
+ if (info.metalness_roughness.x == 1.f && info.metalness_roughness.y == 0.f) {
brdf_type = SPECULAR;
} else {
float brdf_probability = get_brdf_probability(info.color, info.metalness_roughness.x, -r.direction, info.shading_normal);
diff --git a/shaders/include/brdf.h b/shaders/include/brdf.h
new file mode 100644
index 0000000..cafe289
--- /dev/null
+++ b/shaders/include/brdf.h
@@ -0,0 +1,99 @@
+// Specifies minimal reflectance for dielectrics (when metalness is zero)
+// Nothing has lower reflectance than 2%, but we use 4% to have consistent results with UE4, Frostbite, et al.
+#define MIN_DIELECTRICS_F0 0.04f
+
+const uint DIFFUSE = 1;
+const uint SPECULAR = 2;
+
+// Samples a microfacet normal for the GGX distribution using VNDF method.
+// Source: "Sampling the GGX Distribution of Visible Normals" by Heitz
+// See also https://hal.inria.fr/hal-00996995v1/document and http://jcgt.org/published/0007/04/01/
+// Random variables 'u' must be in <0;1) interval
+// PDF is 'G1(NdotV) * D'
+vec3 sample_GGXVNDF(vec3 Ve, vec2 alpha2D, uint seed) {
+ // Section 3.2: transforming the view direction to the hemisphere configuration
+ vec3 Vh = normalize(vec3(alpha2D.x * Ve.x, alpha2D.y * Ve.y, Ve.z));
+
+ // Section 4.1: orthonormal basis (with special case if cross product is zero)
+ float lensq = Vh.x * Vh.x + Vh.y * Vh.y;
+ vec3 T1 = lensq > 0.0f ? vec3(-Vh.y, Vh.x, 0.0f) * inversesqrt(lensq) : vec3(1.0f, 0.0f, 0.0f);
+ vec3 T2 = cross(Vh, T1);
+
+ // Section 4.2: parameterization of the projected area
+ float r = sqrt(rand(seed));
+ float phi = TWO_PI * rand(seed);
+ float t1 = r * cos(phi);
+ float t2 = r * sin(phi);
+ float s = 0.5f * (1.0f + Vh.z);
+ t2 = mix(sqrt(1.0f - t1 * t1), t2, s);
+
+ // Section 4.3: reprojection onto hemisphere
+ vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0f, 1.0f - t1 * t1 - t2 * t2)) * Vh;
+
+ // Section 3.4: transforming the normal back to the ellipsoid configuration
+ return normalize(vec3(alpha2D.x * Nh.x, alpha2D.y * Nh.y, max(0.0f, Nh.z)));
+}
+
+// Smith G1 term (masking function) further optimized for GGX distribution (by substituting G_a into G1_GGX)
+float Smith_G1_GGX(float alpha, float NdotS, float alpha_squared, float NdotS_squared) {
+ return 2.0f / (sqrt(((alpha_squared * (1.0f - NdotS_squared)) + NdotS_squared) / NdotS_squared) + 1.0f);
+}
+
+// Weight for the reflection ray sampled from GGX distribution using VNDF method
+float specular_sample_weight_GGXVNDF(float alpha, float alpha_squared, float NdotL, float NdotV, float HdotL, float NdotH) {
+#if USE_HEIGHT_CORRELATED_G2
+ return Smith_G2_Over_G1_Height_Correlated(alpha, alpha_squared, NdotL, NdotV);
+#else
+ return Smith_G1_GGX(alpha, NdotL, alpha_squared, NdotL * NdotL);
+#endif
+}
+
+vec3 base_color_to_specular_F0(vec3 base_color, float metalness) {
+ return mix(vec3(MIN_DIELECTRICS_F0), base_color, metalness);
+}
+
+vec3 base_color_to_diffuse_reflectance(vec3 base_color, float metalness) {
+ return base_color * (1.0f - metalness);
+}
+
+// Schlick's approximation to Fresnel term
+// f90 should be 1.0, except for the trick used by Schuler (see 'shadowed_F90' function)
+vec3 eval_fresnel_schlick(vec3 f0, float f90, float NdotS) {
+ return f0 + (f90 - f0) * pow(1.0f - NdotS, 5.0f);
+}
+
+vec3 eval_fresnel(vec3 f0, float f90, float NdotS) {
+ // Default is Schlick's approximation
+ return eval_fresnel_schlick(f0, f90, NdotS);
+}
+
+// Attenuates F90 for very low F0 values
+// Source: "An efficient and Physically Plausible Real-Time Shading Model" in ShaderX7 by Schuler
+// Also see section "Overbright highlights" in Hoffman's 2010 "Crafting Physically Motivated Shading Models for Game Development" for discussion
+// IMPORTANT: Note that when F0 is calculated using metalness, it's value is never less than MIN_DIELECTRICS_F0, and therefore,
+// this adjustment has no effect. To be effective, F0 must be authored separately, or calculated in different way. See main text for discussion.
+float shadowed_F90(vec3 F0) {
+ // This scaler value is somewhat arbitrary, Schuler used 60 in his article. In here, we derive it from MIN_DIELECTRICS_F0 so
+ // that it takes effect for any reflectance lower than least reflective dielectrics
+ //const float t = 60.0f;
+ const float t = (1.f / MIN_DIELECTRICS_F0);
+ return min(1.f, t * luminance(F0));
+}
+
+float get_brdf_probability(vec3 color, float metalness, vec3 view, vec3 shading_normal) {
+ // Evaluate Fresnel term using the shading normal
+ // Note: we use the shading normal instead of the microfacet normal (half-vector) for Fresnel term here. That's suboptimal for rough surfaces at grazing angles, but half-vector is yet unknown at this point
+ vec3 specular_F0 = vec3(luminance(base_color_to_specular_F0(color, metalness)));
+ float diffuse_reflectance = luminance(base_color_to_diffuse_reflectance(color, metalness));
+ float fresnel = clamp(luminance(eval_fresnel(specular_F0, shadowed_F90(specular_F0), max(0.0f, dot(view, shading_normal)))), 0.0, 1.0);
+
+ // Approximate relative contribution of BRDFs using the Fresnel term
+ float specular = fresnel;
+ float diffuse = diffuse_reflectance * (1.0f - fresnel); //< If diffuse term is weighted by Fresnel, apply it here as well
+
+ // Return probability of selecting specular BRDF over diffuse BRDF
+ float p = (specular / max(0.0001f, (specular + diffuse)));
+
+ // Clamp probability to avoid undersampling of less prominent BRDF
+ return clamp(p, 0.1f, 0.9f);
+}
diff --git a/shaders/include/color_utils.h b/shaders/include/color_utils.h
new file mode 100644
index 0000000..11c2d9e
--- /dev/null
+++ b/shaders/include/color_utils.h
@@ -0,0 +1,26 @@
+vec3 linear_to_srgb(vec3 color)
+{
+ color = clamp(color, 0.0f, 1.0f);
+
+ return mix(
+ pow(color, vec3(1.0f / 2.4f)) * 1.055f - 0.055f,
+ color * 12.92f,
+ less_than(color, 0.0031308f)
+ );
+}
+
+vec3 srgb_to_linear(vec3 color)
+{
+ color = clamp(color, 0.0f, 1.0f);
+
+ return mix(
+ pow(((color + 0.055f) / 1.055f), vec3(2.4f)),
+ color / 12.92f,
+ less_than(color, 0.04045f)
+ );
+}
+
+float luminance(vec3 rgb)
+{
+ return dot(rgb, vec3(0.2126f, 0.7152f, 0.0722f));
+}
diff --git a/shaders/include/math.h b/shaders/include/math.h
new file mode 100644
index 0000000..cc4e2f4
--- /dev/null
+++ b/shaders/include/math.h
@@ -0,0 +1,45 @@
+const float PI = 3.141592653589793f;
+const float TWO_PI = PI * 2.0f;
+
+vec3 less_than(vec3 vec, float value)
+{
+ return vec3(
+ (vec.x < value) ? 1.0f : 0.0f,
+ (vec.y < value) ? 1.0f : 0.0f,
+ (vec.z < value) ? 1.0f : 0.0f);
+}
+
+vec3 sample_hemisphere(vec2 randoms) {
+ float radius = sqrt(randoms[0]);
+ float theta = 2.0 * PI * randoms[1];
+
+ return vec3(cos(theta) * radius, sin(theta) * radius, sqrt(1 - randoms[0]));
+}
+
+vec2 disk_vec(vec2 randoms) {
+ float z = randoms[0] * 2.0 - 1.0;
+ float a = 2.0 * PI * randoms[1];
+ float r = sqrt(1.0 - z * z);
+
+ return vec2(cos(a) * r, sin(a) * r);
+}
+
+// Calculates rotation quaternion from axis vector to the vector (0, 0, 1)
+// Input vector must be normalized!
+vec4 rotation_to_z_axis(vec3 axis) {
+ // Handle special case when axis is exact or near opposite of (0, 0, 1)
+ if (axis.z < -0.99999f) return vec4(1.0f, 0.0f, 0.0f, 0.0f);
+
+ return normalize(vec4(axis.y, -axis.x, 0.0f, 1.0f + axis.z));
+}
+
+vec4 invert_rotation(vec4 q) {
+ return vec4(-q.xyz, q.w);
+}
+
+// Optimized point rotation using quaternion
+// Source: https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion
+vec3 rotate_point(vec4 q, vec3 v) {
+ const vec3 q_axis = q.xyz;
+ return 2.0f * dot(q_axis, v) * q_axis + (q.w * q.w - dot(q_axis, q_axis)) * v + 2.0f * q.w * cross(q_axis, v);
+}
diff --git a/shaders/include/rand.h b/shaders/include/rand.h
new file mode 100644
index 0000000..e1f8b27
--- /dev/null
+++ b/shaders/include/rand.h
@@ -0,0 +1,12 @@
+uint pcg_hash(inout uint seed)
+{
+ uint state = seed;
+ seed *= 747796405u + 2891336453u;
+ uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
+ return (word >> 22u) ^ word;
+}
+
+float rand(inout uint seed)
+{
+ return float(pcg_hash(seed)) / 4294967296.0;
+}
diff --git a/shaders/include/ray.h b/shaders/include/ray.h
new file mode 100644
index 0000000..38e5c16
--- /dev/null
+++ b/shaders/include/ray.h
@@ -0,0 +1,155 @@
+struct ray {
+ vec3 origin;
+ vec3 direction;
+ float min_t;
+ float max_t;
+};
+
+vec3 at(ray r, float t) {
+ return r.origin + r.direction * t;
+}
+
+struct hit_info {
+ vec3 point;
+ vec3 barycentrics;
+ vec3 geometry_normal;
+ vec3 shading_normal;
+ vec3 color;
+ vec2 metalness_roughness;
+ vec2 uv;
+ float t;
+ uint id;
+};
+
+bool hit_aabb(vec3 minimum, vec3 maximum, ray r) {
+ const vec3 invdir = 1.0 / r.direction;
+ const vec3 f = (maximum.xyz - r.origin.xyz) * invdir;
+ const vec3 n = (minimum.xyz - r.origin.xyz) * invdir;
+
+ const vec3 tmax = max(f, n);
+ const vec3 tmin = min(f, n);
+
+ const float t1 = min(min(tmax.x, min(tmax.y, tmax.z)), r.max_t);
+ const float t0 = max(max(max(tmin.x, max(tmin.y, tmin.z)), r.min_t), 0.0f);
+
+ return t1 >= t0;
+}
+
+uint hit_aabbs(ray r) {
+ uint hit_count = 0;
+ int id = 0;
+
+ while(id != -1) {
+ if (bufs.bvh.nodes[id].primitive_id != -1) {
+ // triangle tri = bufs.geometry.triangles[bufs.bvh.nodes[id].primitive_id];
+ // vec3 minimum = min(tri.v1.position, min(tri.v2.position, tri.v3.position)).xyz;
+ // vec3 maximum = max(tri.v1.position, max(tri.v2.position, tri.v3.position)).xyz;
+
+ // if (hit_aabb(minimum, maximum, r)) {
+ // hit_count++;
+ // }
+ id = bufs.bvh.nodes[id].next_id;
+ } else if (hit_aabb(bufs.bvh.nodes[id].min, bufs.bvh.nodes[id].max, r)) {
+ hit_count++;
+ id++;
+ } else {
+ id = bufs.bvh.nodes[id].next_id;
+ }
+ }
+
+ return hit_count;
+}
+
+bool hit_sphere(sphere s, ray r, out hit_info info) {
+ vec3 origin_center = r.origin - s.position.xyz;
+
+ float a = dot(r.direction, r.direction);
+ float half_b = dot(r.direction, origin_center);
+ float c = dot(origin_center, origin_center) - s.radius * s.radius;
+ float discriminant = half_b * half_b - a * c;
+
+ if (discriminant < 0) {
+ return false;
+ }
+
+ float sqrt_discriminant = sqrt(discriminant);
+ float root = (-half_b - sqrt_discriminant) / a;
+ if (root < r.min_t || root > r.max_t) {
+ root = (-half_b + sqrt_discriminant) / a;
+
+ if (root < r.min_t || root > r.max_t) {
+ return false;
+ }
+ }
+
+ info.t = root;
+ // info.point = at(r, info.t);
+
+ // vec3 outward_normal = (info.point - s.position.xyz) / s.radius;
+ // bool front_face = dot(outward_normal, r.direction) < 0.0;
+ // info.normal = front_face ? outward_normal : -outward_normal;
+
+ return true;
+}
+
+bool hit_triangle(uint id, ray r, out hit_info info) {
+ uint id1 = bufs.indices_arr.indices[id * 3] & 0x00ffffff;
+ uint id2 = bufs.indices_arr.indices[id * 3 + 1] & 0x00ffffff;
+ uint id3 = bufs.indices_arr.indices[id * 3 + 2] & 0x00ffffff;
+
+ vec3 p1 = vec3(bufs.positions_arr.positions[id1 * 3], bufs.positions_arr.positions[id1 * 3 + 1], bufs.positions_arr.positions[id1 * 3 + 2]);
+ vec3 p2 = vec3(bufs.positions_arr.positions[id2 * 3], bufs.positions_arr.positions[id2 * 3 + 1], bufs.positions_arr.positions[id2 * 3 + 2]);
+ vec3 p3 = vec3(bufs.positions_arr.positions[id3 * 3], bufs.positions_arr.positions[id3 * 3 + 1], bufs.positions_arr.positions[id3 * 3 + 2]);
+
+ vec3 v2v1 = p2 - p1;
+ vec3 v3v1 = p3 - p1;
+
+ vec3 originv1 = r.origin - p1;
+ vec3 normal = cross(v2v1, v3v1);
+ vec3 q = cross(originv1, r.direction);
+ float d = 1.0 / 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.0 || u > 1.0 || v < 0.0 || u + v > 1.0 || t < r.min_t || t > r.max_t) {
+ return false;
+ }
+
+ info.t = t;
+ info.barycentrics = vec3(1 - u - v, u, v);
+ info.geometry_normal = normalize(normal);
+ info.id = id;
+
+ return true;
+}
+
+bool hit_node(ray r, out hit_info info) {
+ hit_info temp_info;
+ bool hit = false;
+ int id = 0;
+
+ while(id != -1) {
+ // Leafs
+ if (bufs.bvh.nodes[id].primitive_id != -1) {
+ // if (hit_sphere(bufs.geometry.spheres[bufs.bvh.nodes[id].primitive_id], r, temp_info)) {
+ // info = temp_info;
+ // r.max_t = temp_info.t;
+ // hit = true;
+ // }
+ if (hit_triangle(bufs.bvh.nodes[id].primitive_id, r, temp_info)) {
+ info = temp_info;
+ r.max_t = temp_info.t;
+ hit = true;
+ }
+ id = bufs.bvh.nodes[id].next_id;
+ } else if (hit_aabb(bufs.bvh.nodes[id].min, bufs.bvh.nodes[id].max, r)) {
+ id++;
+ } else {
+ id = bufs.bvh.nodes[id].next_id;
+ }
+ }
+
+ info.point = at(r, info.t);
+ return hit;
+}
diff --git a/shaders/tonemapping.comp b/shaders/tonemapping.comp
index 660327d..35a7a13 100644
--- a/shaders/tonemapping.comp
+++ b/shaders/tonemapping.comp
@@ -12,8 +12,8 @@ layout(set = 0, binding = 2, rgba32f) uniform image2D images[];
layout(push_constant) uniform constants {
scene_metadata scene;
- uint output_image_index;
- uint accumulation_image_index;
+ layout(offset = 56) uint output_image_index;
+ layout(offset = 60) uint accumulation_image_index;
} consts;
void main() {
diff --git a/shaders/ui.frag b/shaders/ui.frag
index c4e0150..dd0fdd4 100644
--- a/shaders/ui.frag
+++ b/shaders/ui.frag
@@ -11,7 +11,7 @@ layout(set = 0, binding = 0) uniform sampler samplers[];
layout(set = 0, binding = 1) uniform texture2D textures[];
layout(push_constant) uniform constants {
- layout(offset = 56) uint texture_index;
+ layout(offset = 96) uint texture_index;
uint sampler_index;
} consts;
diff --git a/shaders/ui.vert b/shaders/ui.vert
index dd71ef6..a9f0670 100644
--- a/shaders/ui.vert
+++ b/shaders/ui.vert
@@ -12,7 +12,7 @@ layout(buffer_reference) readonly buffer vertices {
};
layout(push_constant) uniform constants {
- layout(offset = 32) vertices vertex_buffer;
+ layout(offset = 64) vertices vertex_buffer;
vec2 scale;
vec2 translate;
} consts;
diff --git a/src/gltf.cpp b/src/gltf.cpp
index bfd7522..61c68ac 100644
--- a/src/gltf.cpp
+++ b/src/gltf.cpp
@@ -8,8 +8,6 @@
#include "utils.hpp"
-const vec3 scale (0.00800000037997961);
-
node gltf::load(std::filesystem::path &path, std::string &filename, vkrenderer &renderer) {
std::fstream f(path / filename);
json gltf_json;
@@ -73,7 +71,10 @@ std::vector<mesh> gltf::load_meshes(json &gltf_json, std::vector<std::vector<uin
auto &mesh = meshes[mesh_index];
for (auto& primitive: primitives) {
- mesh.parts.emplace_back(load_primitive(gltf_json, primitive, buffers_content, materials));
+ auto &&part = load_primitive(gltf_json, primitive, buffers_content, materials);
+ mesh.vertices_count += part.vertices_count;
+ mesh.triangles_count += part.triangles_count;
+ mesh.parts.emplace_back(std::move(part));
}
}
@@ -204,7 +205,6 @@ mesh_part gltf::load_primitive(json &gltf_json, json &primitive, std::vector<std
uint16_t* indices_start = (uint16_t*)(indices_buffer.data() + indices_offset);
part.indices.resize(indices_length / sizeof(uint16_t));
-
std::memcpy(part.indices.data(), indices_start, indices_length);
}
@@ -220,12 +220,8 @@ mesh_part gltf::load_primitive(json &gltf_json, json &primitive, std::vector<std
auto &positions_buffer = buffers_content[positions_buffer_index];
float* positions_start = (float*)(positions_buffer.data() + positions_offset);
- size_t positions_count = positions_length / (sizeof(float) * 3);
- part.positions.resize(positions_count);
-
- for (size_t i = 0; i < positions_count; i++) {
- part.positions[i] = vec3(positions_start[i * 3], positions_start[i * 3 + 1], positions_start[i * 3 + 2]) * scale;
- }
+ part.positions.resize(positions_length / sizeof(float));
+ std::memcpy(part.positions.data(), positions_start, positions_length);
}
{
@@ -240,12 +236,8 @@ mesh_part gltf::load_primitive(json &gltf_json, json &primitive, std::vector<std
auto &normals_buffer = buffers_content[normals_buffer_index];
float* normals_start = (float*)(normals_buffer.data() + normals_offset);
- size_t normals_count = normals_length / (sizeof(float) * 3);
- part.normals.resize(normals_count);
-
- for (size_t i = 0; i < normals_count; i++) {
- part.normals[i] = vec3(normals_start[i * 3], normals_start[i * 3 + 1], normals_start[i * 3 + 2]);
- }
+ part.normals.resize(normals_length / sizeof(float));
+ std::memcpy(part.normals.data(), normals_start, normals_length);
}
{
@@ -260,15 +252,13 @@ mesh_part gltf::load_primitive(json &gltf_json, json &primitive, std::vector<std
auto &uvs_buffer = buffers_content[uvs_buffer_index];
float* uvs_start = (float*)(uvs_buffer.data() + uvs_offset);
- size_t uvs_count = uvs_length / (sizeof(float) * 2);
- part.uvs.resize(uvs_count);
-
- for (size_t i = 0; i < uvs_count; i++) {
- part.uvs[i] = vec3(uvs_start[i * 2], uvs_start[i * 2 + 1], 0.0);
- }
+ part.uvs.resize(uvs_length / sizeof(float));
+ std::memcpy(part.uvs.data(), uvs_start, uvs_length);
}
part.mat = materials[primitive["material"].get<uint32_t>()];
+ part.vertices_count = part.positions.size() / 3;
+ part.triangles_count = part.indices.size() / 3;
return std::move(part);
}
diff --git a/src/main.cpp b/src/main.cpp
index 287b0eb..06c351c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -63,17 +63,14 @@ int main() {
vkrenderer renderer { wnd };
auto main_scene = scene(cam, width, height, renderer);
- // vkrenderer renderer { wnd, sizeof(main_scene.meta), sizeof(main_scene.spheres[0]) * main_scene.spheres.size(), sizeof(main_scene.packed_nodes[0]) * main_scene.packed_nodes.size() };
- renderer.create_scene_buffer(sizeof(main_scene.meta));
- renderer.create_geometry_buffer(sizeof(main_scene.triangles[0]) * main_scene.triangles.size());
- renderer.create_bvh_buffer(sizeof(main_scene.packed_nodes[0]) * main_scene.packed_nodes.size());
-
- // Upload scene content
- std::memcpy(renderer.scene_buffer_ptr(), &main_scene.meta, sizeof(main_scene.meta));
- renderer.update_geometry_buffer(main_scene.triangles.data());
- // renderer.update_geometry_buffer(main_scene.spheres.data());
- renderer.update_bvh_buffer(main_scene.packed_nodes.data());
+ renderer.scene_buffer_addr = main_scene.scene_buffer.device_address;
+ renderer.indices_buffer_addr = main_scene.indices_buffer.device_address;
+ renderer.positions_buffer_addr = main_scene.positions_buffer.device_address;
+ renderer.normals_buffer_addr = main_scene.normals_buffer.device_address;
+ renderer.uvs_buffer_addr = main_scene.uvs_buffer.device_address;
+ renderer.materials_buffer_addr = main_scene.materials_buffer.device_address;
+ renderer.bvh_buffer_addr = main_scene.bvh_buffer.device_address;
auto can_render = true;
@@ -101,8 +98,8 @@ int main() {
width = event.width;
height = event.height;
- ((scene*) renderer.scene_buffer_ptr())->meta.width = width;
- ((scene*) renderer.scene_buffer_ptr())->meta.height = height;
+ ((scene*) main_scene.scene_buffer_ptr())->meta.width = width;
+ ((scene*) main_scene.scene_buffer_ptr())->meta.height = height;
io.DisplaySize.x = (float)width;
io.DisplaySize.y = (float)height;
@@ -112,8 +109,8 @@ int main() {
} else {
can_render = true;
renderer.recreate_swapchain();
- ((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;
+ ((scene*) main_scene.scene_buffer_ptr())->meta.cam.set_aspect_ratio((float)event.width / (float)event.height);
+ ((scene*) main_scene.scene_buffer_ptr())->meta.sample_index = 0;
}
reset_accumulation = true;
@@ -121,7 +118,7 @@ int main() {
break;
}
case EVENT_TYPES::KEY_PRESS: {
- auto move_speed = 0.01f * delta_time;
+ auto move_speed = 1.f * delta_time;
if (wnd.keyboard[KEYS::LSHIFT] || wnd.keyboard[KEYS::RSHIFT]) {
move_speed *= 10.f;
}
@@ -130,44 +127,44 @@ int main() {
switch (event.key) {
case KEYS::W: {
- move_vec = ((scene*) renderer.scene_buffer_ptr())->meta.cam.forward * move_speed;
+ move_vec = ((scene*) main_scene.scene_buffer_ptr())->meta.cam.forward * move_speed;
break;
}
case KEYS::S: {
- move_vec = -((scene*) renderer.scene_buffer_ptr())->meta.cam.forward * move_speed;
+ move_vec = -((scene*) main_scene.scene_buffer_ptr())->meta.cam.forward * move_speed;
break;
}
case KEYS::D: {
- move_vec = ((scene*) renderer.scene_buffer_ptr())->meta.cam.right * move_speed;
+ move_vec = ((scene*) main_scene.scene_buffer_ptr())->meta.cam.right * move_speed;
break;
}
case KEYS::A: {
- move_vec = -((scene*) renderer.scene_buffer_ptr())->meta.cam.right * move_speed;
+ move_vec = -((scene*) main_scene.scene_buffer_ptr())->meta.cam.right * move_speed;
break;
}
case KEYS::E: {
- ((scene*) renderer.scene_buffer_ptr())->meta.cam.rotate_y(0.001f * delta_time);
+ ((scene*) main_scene.scene_buffer_ptr())->meta.cam.rotate_y(0.001f * delta_time);
reset_accumulation = true;
break;
}
case KEYS::Q: {
- ((scene*) renderer.scene_buffer_ptr())->meta.cam.rotate_y(-0.001f * delta_time);
+ ((scene*) main_scene.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())->meta.cam.up * move_speed;
+ move_vec = ((scene*) main_scene.scene_buffer_ptr())->meta.cam.up * move_speed;
break;
}
case KEYS::LCTRL: {
- move_vec = -((scene*) renderer.scene_buffer_ptr())->meta.cam.up * move_speed;
+ move_vec = -((scene*) main_scene.scene_buffer_ptr())->meta.cam.up * move_speed;
break;
}
default:
break;
}
- ((scene*) renderer.scene_buffer_ptr())->meta.cam.move(move_vec);
+ ((scene*) main_scene.scene_buffer_ptr())->meta.cam.move(move_vec);
if (!move_vec.near_zero()) {
reset_accumulation = true;
@@ -216,19 +213,19 @@ 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())->meta.sample_index);
+ ImGui::Text("frame count %u\n", ((scene*) main_scene.scene_buffer_ptr())->meta.sample_index);
- if (ImGui::Checkbox("depth of field", (bool*)&((scene*) renderer.scene_buffer_ptr())->meta.enable_dof)) {
+ if (ImGui::Checkbox("depth of field", (bool*)&((scene*) main_scene.scene_buffer_ptr())->meta.enable_dof)) {
reset_accumulation = true;
}
- ImGui::SliderInt("max bounces", (int32_t*)&((scene*) renderer.scene_buffer_ptr())->meta.max_bounce, 1, 250);
- ImGui::SliderInt("min bounces", (int32_t*)&((scene*) renderer.scene_buffer_ptr())->meta.min_bounce, 1, ((scene*) renderer.scene_buffer_ptr())->meta.max_bounce);
- if (ImGui::SliderInt("downscale factor", (int32_t*)&((scene*) renderer.scene_buffer_ptr())->meta.downscale_factor, 1, 32)) {
+ ImGui::SliderInt("max bounces", (int32_t*)&((scene*) main_scene.scene_buffer_ptr())->meta.max_bounce, 1, 250);
+ ImGui::SliderInt("min bounces", (int32_t*)&((scene*) main_scene.scene_buffer_ptr())->meta.min_bounce, 1, ((scene*) main_scene.scene_buffer_ptr())->meta.max_bounce);
+ if (ImGui::SliderInt("downscale factor", (int32_t*)&((scene*) main_scene.scene_buffer_ptr())->meta.downscale_factor, 1, 32)) {
reset_accumulation = true;
}
- if (ImGui::Checkbox("debug bvh", (bool*)&((scene*) renderer.scene_buffer_ptr())->meta.debug_bvh)) {
+ if (ImGui::Checkbox("debug bvh", (bool*)&((scene*) main_scene.scene_buffer_ptr())->meta.debug_bvh)) {
reset_accumulation = true;
}
@@ -246,14 +243,14 @@ int main() {
renderer.begin_frame();
if (reset_accumulation) {
- ((scene*) renderer.scene_buffer_ptr())->meta.sample_index = 0;
+ ((scene*) main_scene.scene_buffer_ptr())->meta.sample_index = 0;
renderer.reset_accumulation();
}
- float scale = (float)((scene*) renderer.scene_buffer_ptr())->meta.downscale_factor;
+ float scale = (float)((scene*) main_scene.scene_buffer_ptr())->meta.downscale_factor;
renderer.compute(width / scale, height / scale);
- ((scene*) renderer.scene_buffer_ptr())->meta.sample_index++;
+ ((scene*) main_scene.scene_buffer_ptr())->meta.sample_index++;
renderer.ui();
diff --git a/src/scene.cpp b/src/scene.cpp
index d162b3a..9caed7b 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -66,6 +66,9 @@ scene::scene(camera cam, uint32_t width, uint32_t height, vkrenderer &renderer)
// auto sponza_filename = std::string("Sponza.gltf");
// auto root_node = gltf::load(sponza_path, sponza_filename, renderer);
+ std::vector<triangle> triangles;
+ auto triangles_offset = 0;
+ auto vertices_offset = 0;
std::queue<node> nodes_to_load {};
nodes_to_load.push(root_node);
@@ -74,18 +77,37 @@ scene::scene(camera cam, uint32_t width, uint32_t height, vkrenderer &renderer)
if (node.mesh) {
auto &mesh = node.mesh.value();
+
+ indices.resize(indices.size() + mesh.triangles_count * 3);
+ positions.resize(positions.size() + mesh.vertices_count * 3);
+ normals.resize(normals.size() + mesh.vertices_count * 3);
+ uvs.resize(uvs.size() + mesh.vertices_count * 2);
+
+
for (auto& mesh_part: mesh.parts) {
+ std::memcpy(positions.data() + vertices_offset * 3, mesh_part.positions.data(), mesh_part.positions.size() * sizeof(float));
+ std::memcpy(normals.data() + vertices_offset * 3, mesh_part.normals.data(), mesh_part.normals.size() * sizeof(float));
+ std::memcpy(uvs.data() + vertices_offset * 2, mesh_part.uvs.data(), mesh_part.uvs.size() * sizeof(float));
+
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], .uv = mesh_part.uvs[i1] };
- auto v2 = vertex { .position = mesh_part.positions[i2], .normal = mesh_part.normals[i2], .uv = mesh_part.uvs[i2] };
- auto v3 = vertex { .position = mesh_part.positions[i3], .normal = mesh_part.normals[i3], .uv = mesh_part.uvs[i3] };
+ auto p1 = vec3(mesh_part.positions[i1 * 3], mesh_part.positions[i1 * 3 + 1], mesh_part.positions[i1 * 3 + 2]);
+ auto p2 = vec3(mesh_part.positions[i2 * 3], mesh_part.positions[i2 * 3 + 1], mesh_part.positions[i2 * 3 + 2]);
+ auto p3 = vec3(mesh_part.positions[i3 * 3], mesh_part.positions[i3 * 3 + 1], mesh_part.positions[i3 * 3 + 2]);
- triangles.emplace_back(v1, v2, v3, mesh_part.mat);
+ indices[triangles_offset * 3 + i] = (i1 + vertices_offset) | (0xff000000 & (materials.size() << 8));
+ indices[triangles_offset * 3 + i + 1] = (i2 + vertices_offset) | (0xff000000 & (materials.size() << 16));
+ indices[triangles_offset * 3 + i + 2] = (i3 + vertices_offset) | (0xff000000 & (materials.size() << 24));
+
+ triangles.emplace_back(p1, p2, p3);
+ materials.push_back(mesh_part.mat);
}
+
+ triangles_offset += mesh_part.triangles_count;
+ vertices_offset += mesh_part.vertices_count;
}
}
@@ -100,4 +122,25 @@ scene::scene(camera cam, uint32_t width, uint32_t height, vkrenderer &renderer)
bvh builder(triangles, packed_nodes);
// bvh builder(spheres, packed_nodes);
+
+ scene_buffer = renderer.api.create_buffer(sizeof(meta), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ std::memcpy(scene_buffer.alloc_info.pMappedData, &meta, sizeof(meta));
+
+ indices_buffer = renderer.api.create_buffer(indices.size() * sizeof(indices[0]), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ std::memcpy(indices_buffer.alloc_info.pMappedData, indices.data(), indices.size() * sizeof(indices[0]));
+
+ positions_buffer = renderer.api.create_buffer(positions.size() * sizeof(positions[0]), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ std::memcpy(positions_buffer.alloc_info.pMappedData, positions.data(), positions.size() * sizeof(positions[0]));
+
+ normals_buffer = renderer.api.create_buffer(normals.size() * sizeof(normals[0]), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ std::memcpy(normals_buffer.alloc_info.pMappedData, normals.data(), normals.size() * sizeof(normals[0]));
+
+ uvs_buffer = renderer.api.create_buffer(uvs.size() * sizeof(uvs[0]), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ std::memcpy(uvs_buffer.alloc_info.pMappedData, uvs.data(), uvs.size() * sizeof(uvs[0]));
+
+ bvh_buffer = renderer.api.create_buffer(packed_nodes.size() * sizeof(packed_nodes[0]), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ std::memcpy(bvh_buffer.alloc_info.pMappedData, packed_nodes.data(), packed_nodes.size() * sizeof(packed_nodes[0]));
+
+ materials_buffer = renderer.api.create_buffer(materials.size() * sizeof(materials[0]), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
+ std::memcpy(materials_buffer.alloc_info.pMappedData, materials.data(), materials.size() * sizeof(materials[0]));
}
diff --git a/src/vk-api.cpp b/src/vk-api.cpp
index efcd073..3391246 100644
--- a/src/vk-api.cpp
+++ b/src/vk-api.cpp
@@ -98,17 +98,17 @@ vkapi::vkapi() {
{
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.offset = 0,
- .size = 32,
+ .size = 64,
},
{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
- .offset = 32,
- .size = 24,
+ .offset = 64,
+ .size = 32,
},
{
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
- .offset = 56,
- .size = 8,
+ .offset = 96,
+ .size = 32,
},
};
@@ -159,13 +159,13 @@ Buffer vkapi::create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, V
VKRESULT(vmaCreateBuffer(context.allocator, &buffer_info, &alloc_create_info, &buffer.handle, &buffer.alloc, &buffer.alloc_info))
- buffer.size = data_size;
-
VkBufferDeviceAddressInfo buffer_device_address_info = {};
buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
buffer_device_address_info.pNext = VK_NULL_HANDLE;
buffer_device_address_info.buffer = buffer.handle;
+ buffer.size = data_size;
+
buffer.device_address = vkGetBufferDeviceAddress(context.device, &buffer_device_address_info);
return std::move(buffer);
diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp
index 4ac1cd0..ba5f017 100644
--- a/src/vk-renderer.cpp
+++ b/src/vk-renderer.cpp
@@ -143,9 +143,6 @@ vkrenderer::vkrenderer(window& wnd) {
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_buffer(staging_buffer);
api.destroy_fences(submission_fences);
api.destroy_semaphores(execution_semaphores);
@@ -267,12 +264,12 @@ void vkrenderer::ui() {
-1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x),
-1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y),
};
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 32, 8, (void*)&ui_vertex_buffers[virtual_frame_index].device_address);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 40, 8, (void*)&scale);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 48, 8, (void*)&translate);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 64, 8, (void*)&ui_vertex_buffers[virtual_frame_index].device_address);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 72, 8, (void*)&scale);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 80, 8, (void*)&translate);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 56, 4, (void*)&ui_texture.bindless_sampled_index);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 60, 4, (void*)&ui_texture_sampler.bindless_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 96, 4, (void*)&ui_texture.bindless_sampled_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 100, 4, (void*)&ui_texture_sampler.bindless_index);
off_t vertex_buffer_offset = 0;
off_t index_buffer_offset = 0;
@@ -304,19 +301,23 @@ void vkrenderer::ui() {
void vkrenderer::compute(uint32_t width, uint32_t height) {
auto cmd_buf = command_buffers[virtual_frame_index];
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, (void*)&scene_buffer.device_address);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 8, 8, (void*)&geometry_buffer.device_address);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 16, 8, (void*)&bvh_buffer.device_address);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 24, 4, (void*)&accumulation_images[0].bindless_storage_index);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 28, 4, (void*)&accumulation_images[1].bindless_storage_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, (void*)&scene_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 8, 8, (void*)&bvh_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 16, 8, (void*)&indices_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 24, 8, (void*)&positions_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 32, 8, (void*)&normals_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 40, 8, (void*)&uvs_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 48, 8, (void*)&materials_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 56, 4, (void*)&accumulation_images[0].bindless_storage_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 60, 4, (void*)&accumulation_images[1].bindless_storage_index);
api.run_compute_pipeline(cmd_buf, compute_pipeline, (width / 8) + 1, (height / 8) + 1, 1);
api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, swapchain.images[swapchain_image_index]);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, (void*)&scene_buffer.device_address);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 8, 4, (void*)&swapchain.images[swapchain_image_index].bindless_storage_index);
- vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 12, 4, (void*)&accumulation_images[0].bindless_storage_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, (void*)&scene_buffer_addr);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 56, 4, (void*)&swapchain.images[swapchain_image_index].bindless_storage_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 60, 4, (void*)&accumulation_images[0].bindless_storage_index);
api.run_compute_pipeline(cmd_buf, tonemapping_pipeline, (width / 8) + 1, (height / 8) + 1, 1);
}
@@ -405,62 +406,6 @@ void vkrenderer::handle_swapchain_result(VkResult function_result) {
}
}
-
-void vkrenderer::create_scene_buffer(size_t size) {
- scene_buffer = api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
-}
-
-void vkrenderer::create_geometry_buffer(size_t size) {
- geometry_buffer = api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
-}
-
-void vkrenderer::create_bvh_buffer(size_t size) {
- bvh_buffer = api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
-}
-
-// TODO: Integrate into the API so that we no longer have to wait for the fence
-void vkrenderer::update_geometry_buffer(void* data) {
- VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX))
- VKRESULT(vkResetFences(api.context.device, 1, &submission_fences[virtual_frame_index]))
-
- auto cmd_buf = command_buffers[virtual_frame_index];
- api.start_record(cmd_buf);
-
- auto staging_buffer = api.create_buffer(geometry_buffer.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
- std::memcpy(staging_buffer.alloc_info.pMappedData, data, staging_buffer.size);
-
- api.copy_buffer(cmd_buf, staging_buffer, geometry_buffer, staging_buffer.size);
-
- api.end_record(cmd_buf);
-
- api.submit(cmd_buf, VK_NULL_HANDLE, VK_NULL_HANDLE, submission_fences[virtual_frame_index]);
-
- VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX))
-
- api.destroy_buffer(staging_buffer);
-}
-
-void vkrenderer::update_bvh_buffer(void* data) {
- VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX))
- VKRESULT(vkResetFences(api.context.device, 1, &submission_fences[virtual_frame_index]))
-
- auto cmd_buf = command_buffers[virtual_frame_index];
- api.start_record(cmd_buf);
-
- auto staging_buffer = api.create_buffer(bvh_buffer.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
- std::memcpy(staging_buffer.alloc_info.pMappedData, data, staging_buffer.size);
-
- api.copy_buffer(cmd_buf, staging_buffer, bvh_buffer, staging_buffer.size);
-
- api.end_record(cmd_buf);
-
- api.submit(cmd_buf, VK_NULL_HANDLE, VK_NULL_HANDLE, submission_fences[virtual_frame_index]);
-
- VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX))
-
- api.destroy_buffer(staging_buffer);
-}
-
void vkrenderer::update_image(image img, void* data, size_t size) {
if (staging_buffer.size < size) {
api.destroy_buffer(staging_buffer);