diff options
| author | ladevieq <ladevie.quentin@gmail.com> | 2021-09-26 23:57:26 +0200 |
|---|---|---|
| committer | ladevieq <ladevie.quentin@gmail.com> | 2021-09-26 23:57:26 +0200 |
| commit | c5119193ffaedf4ac94fecfb434a3292a4746259 (patch) | |
| tree | 398031c5d1e920fec21e53feacd1d55ba8a79dad | |
| parent | bbba71cfe5a9545f1a87c70eb3cab3b6b08b1b25 (diff) | |
Refactor gltf loading and triangles attributes
| -rw-r--r-- | include/aabb.hpp | 24 | ||||
| -rw-r--r-- | include/gltf.hpp | 10 | ||||
| -rw-r--r-- | include/scene.hpp | 20 | ||||
| -rw-r--r-- | include/triangle.hpp | 21 | ||||
| -rw-r--r-- | include/vk-api.hpp | 1 | ||||
| -rw-r--r-- | include/vk-renderer.hpp | 25 | ||||
| -rw-r--r-- | shaders/compute.comp | 67 | ||||
| -rw-r--r-- | shaders/include/brdf.h | 99 | ||||
| -rw-r--r-- | shaders/include/color_utils.h | 26 | ||||
| -rw-r--r-- | shaders/include/math.h | 45 | ||||
| -rw-r--r-- | shaders/include/rand.h | 12 | ||||
| -rw-r--r-- | shaders/include/ray.h | 155 | ||||
| -rw-r--r-- | shaders/tonemapping.comp | 4 | ||||
| -rw-r--r-- | shaders/ui.frag | 2 | ||||
| -rw-r--r-- | shaders/ui.vert | 2 | ||||
| -rw-r--r-- | src/gltf.cpp | 34 | ||||
| -rw-r--r-- | src/main.cpp | 63 | ||||
| -rw-r--r-- | src/scene.cpp | 51 | ||||
| -rw-r--r-- | src/vk-api.cpp | 14 | ||||
| -rw-r--r-- | src/vk-renderer.cpp | 89 |
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); |
