diff --git a/include/vkcv/DrawcallRecording.hpp b/include/vkcv/DrawcallRecording.hpp index 0929ad038fb95ec1573e7c76e5ce13adb84ab760..9f162a499a38d5633703f70eec8a8682e3328d72 100644 --- a/include/vkcv/DrawcallRecording.hpp +++ b/include/vkcv/DrawcallRecording.hpp @@ -37,11 +37,12 @@ namespace vkcv { }; struct DrawcallInfo { - inline DrawcallInfo(const Mesh& mesh, const std::vector<DescriptorSetUsage>& descriptorSets) - : mesh(mesh), descriptorSets(descriptorSets) {} + inline DrawcallInfo(const Mesh& mesh, const std::vector<DescriptorSetUsage>& descriptorSets, const uint32_t instanceCount = 1) + : mesh(mesh), descriptorSets(descriptorSets), instanceCount(instanceCount){} Mesh mesh; std::vector<DescriptorSetUsage> descriptorSets; + uint32_t instanceCount; }; void recordDrawcall( diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp index b1dd56d5ddb29d6f986bfa490d3cb7bdfb37c4ca..5e6dbaa3306f8d2aa6fc44d7dd1fadd9b79be3b4 100644 --- a/include/vkcv/PipelineConfig.hpp +++ b/include/vkcv/PipelineConfig.hpp @@ -18,16 +18,21 @@ namespace vkcv { enum class CullMode{ None, Front, Back }; enum class DepthTest { None, Less, LessEqual, Greater, GreatherEqual, Equal }; + // add more as needed + // alternatively we could expose the blend factors directly + enum class BlendMode{ None, Additive }; + struct PipelineConfig { - ShaderProgram m_ShaderProgram; - uint32_t m_Width; - uint32_t m_Height; - PassHandle m_PassHandle; - VertexLayout m_VertexLayout; - std::vector<vk::DescriptorSetLayout> m_DescriptorLayouts; - bool m_UseDynamicViewport; - bool m_UseConservativeRasterization = false; - PrimitiveTopology m_PrimitiveTopology = PrimitiveTopology::TriangleList; + ShaderProgram m_ShaderProgram; + uint32_t m_Width; + uint32_t m_Height; + PassHandle m_PassHandle; + VertexLayout m_VertexLayout; + std::vector<vk::DescriptorSetLayout> m_DescriptorLayouts; + bool m_UseDynamicViewport; + bool m_UseConservativeRasterization = false; + PrimitiveTopology m_PrimitiveTopology = PrimitiveTopology::TriangleList; + BlendMode m_blendMode = BlendMode::None; bool m_EnableDepthClamping = false; Multisampling m_multisampling = Multisampling::None; CullMode m_culling = CullMode::None; diff --git a/modules/camera/include/vkcv/camera/Camera.hpp b/modules/camera/include/vkcv/camera/Camera.hpp index ce32d3f8a0c6ee3e0dd882f24a9ac2d12c14a024..9d85df7dce6d043630fd9d39287cace8530dbd6a 100644 --- a/modules/camera/include/vkcv/camera/Camera.hpp +++ b/modules/camera/include/vkcv/camera/Camera.hpp @@ -75,7 +75,7 @@ namespace vkcv::camera { * @brief Gets the current projection of the camera * @return The current projection matrix */ - const glm::mat4& getProjection() const; + glm::mat4 getProjection() const; /** * @brief Gets the model-view-projection matrix of the camera with y-axis-correction applied diff --git a/modules/camera/src/vkcv/camera/Camera.cpp b/modules/camera/src/vkcv/camera/Camera.cpp index 18bf94463a0e2c4cb7d64526f4c30835cb451eb2..3541b1a5bc1253c6b0f2b044d757341855a5e900 100644 --- a/modules/camera/src/vkcv/camera/Camera.cpp +++ b/modules/camera/src/vkcv/camera/Camera.cpp @@ -37,22 +37,22 @@ namespace vkcv::camera { m_view = view; } - const glm::mat4& Camera::getProjection() const { - return m_projection; + const glm::mat4 y_correction( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + glm::mat4 Camera::getProjection() const { + return y_correction * m_projection; } void Camera::setProjection(const glm::mat4& projection) { - m_projection = projection; + m_projection = glm::inverse(y_correction) * projection; } glm::mat4 Camera::getMVP() const { - const glm::mat4 y_correction ( - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); - return y_correction * m_projection * m_view; } diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index 34fbcb0cf8dd3f1d34efd2cc8424994c7da76e32..1c6e3afe2347f6ef8ea8a62be7acbe0ea750497d 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -3,5 +3,6 @@ add_subdirectory(bloom) add_subdirectory(first_triangle) add_subdirectory(first_mesh) +add_subdirectory(particle_simulation) add_subdirectory(first_scene) -add_subdirectory(voxelization) \ No newline at end of file +add_subdirectory(voxelization) diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp index eccc0af7331dc140f3a15ddf12c5645e685abc90..6e53eb8c5ec1825135778dc91b11dd6e45f44276 100644 --- a/projects/cmd_sync_test/src/main.cpp +++ b/projects/cmd_sync_test/src/main.cpp @@ -175,8 +175,8 @@ int main(int argc, const char** argv) { std::vector<vkcv::DrawcallInfo> shadowDrawcalls; for (const auto& position : instancePositions) { modelMatrices.push_back(glm::translate(glm::mat4(1.f), position)); - drawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, { descriptorUsage })); - shadowDrawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, {})); + drawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, { descriptorUsage },1)); + shadowDrawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, {},1)); } modelMatrices.back() *= glm::scale(glm::mat4(1.f), glm::vec3(10.f, 1.f, 10.f)); diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index dc43c905784525a34732bc0e66343fbdcc17a639..e7546fc3a143b3638cceb36869c519336ebec751 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -83,6 +83,7 @@ int main(int argc, const char** argv) { firstMeshProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; + std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); @@ -149,7 +150,7 @@ int main(int argc, const char** argv) { const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices); vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); - vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage }); + vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage },1); vkcv::camera::CameraManager cameraManager(window); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 420400cdd04865ddd48eec7cf6000e36417d8095..521818732f7a60eabe9f0c2c080c6d343a71b1d8 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -199,7 +199,7 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSets[i]).vulkanHandle); - drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage})); + drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage},1)); } std::vector<glm::mat4> modelMatrices; diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 20cfdddf5c1baa9e8727312daa36de94bd56672f..5bdd55a263f4d81d8f424c056d7d6c0b54ccb1ca 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -167,7 +167,7 @@ int main(int argc, const char** argv) { vkcv::ImageHandle swapchainImageHandle = vkcv::ImageHandle::createSwapchainImageHandle(); const vkcv::Mesh renderMesh({}, triangleIndexBuffer.getVulkanHandle(), 3); - vkcv::DrawcallInfo drawcall(renderMesh, {}); + vkcv::DrawcallInfo drawcall(renderMesh, {},1); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); diff --git a/projects/particle_simulation/.gitignore b/projects/particle_simulation/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4964f89e973f38358aa57f564f56d3d4b0c328a9 --- /dev/null +++ b/projects/particle_simulation/.gitignore @@ -0,0 +1 @@ +particle_simulation \ No newline at end of file diff --git a/projects/particle_simulation/CMakeLists.txt b/projects/particle_simulation/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a665202c521ac10ae94905cb7580205e897eef9 --- /dev/null +++ b/projects/particle_simulation/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.16) +project(particle_simulation) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(particle_simulation + src/main.cpp + src/ParticleSystem.hpp + src/ParticleSystem.cpp + src/Particle.hpp + src/Particle.cpp + src/BloomAndFlares.hpp + src/BloomAndFlares.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(particle_simulation PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(particle_simulation PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(particle_simulation PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(particle_simulation SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(particle_simulation vkcv vkcv_testing vkcv_camera vkcv_shader_compiler) diff --git a/projects/particle_simulation/shaders/bloom/composite.comp b/projects/particle_simulation/shaders/bloom/composite.comp new file mode 100644 index 0000000000000000000000000000000000000000..87b5ddb975106232d1cd3b6e5b8dc7e623dd0b59 --- /dev/null +++ b/projects/particle_simulation/shaders/bloom/composite.comp @@ -0,0 +1,38 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D blurImage; +layout(set=0, binding=1) uniform texture2D lensImage; +layout(set=0, binding=2) uniform sampler linearSampler; +layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D colorBuffer; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / textureSize(sampler2D(blurImage, linearSampler), 0); + vec2 UV = pixel_coord.xy * pixel_size; + + vec4 composite_color = vec4(0.0f); + + vec3 blur_color = texture(sampler2D(blurImage, linearSampler), UV).rgb; + vec3 lens_color = texture(sampler2D(lensImage, linearSampler), UV).rgb; + vec3 main_color = imageLoad(colorBuffer, pixel_coord).rgb; + + // composite blur and lens features + float bloom_weight = 0.01f; + float lens_weight = 0.f; + float main_weight = 1 - (bloom_weight + lens_weight); + + composite_color.rgb = blur_color * bloom_weight + + lens_color * lens_weight + + main_color * main_weight; + + imageStore(colorBuffer, pixel_coord, composite_color); +} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/bloom/downsample.comp b/projects/particle_simulation/shaders/bloom/downsample.comp new file mode 100644 index 0000000000000000000000000000000000000000..2ab00c7c92798769153634f3479c5b7f3fb61d94 --- /dev/null +++ b/projects/particle_simulation/shaders/bloom/downsample.comp @@ -0,0 +1,76 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D inBlurImage; +layout(set=0, binding=1) uniform sampler inImageSampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform writeonly image2D outBlurImage; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outBlurImage)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / imageSize(outBlurImage); + vec2 UV = pixel_coord.xy * pixel_size; + vec2 UV_offset = UV + 0.5f * pixel_size; + + vec2 color_fetches[13] = { + // center neighbourhood (RED) + vec2(-1, 1), // LT + vec2(-1, -1), // LB + vec2( 1, -1), // RB + vec2( 1, 1), // RT + + vec2(-2, 2), // LT + vec2( 0, 2), // CT + vec2( 2, 2), // RT + + vec2(0 ,-2), // LC + vec2(0 , 0), // CC + vec2(2, 0), // CR + + vec2(-2, -2), // LB + vec2(0 , -2), // CB + vec2(2 , -2) // RB + }; + + float color_weights[13] = { + // 0.5f + 1.f/8.f, + 1.f/8.f, + 1.f/8.f, + 1.f/8.f, + + // 0.125f + 1.f/32.f, + 1.f/16.f, + 1.f/32.f, + + // 0.25f + 1.f/16.f, + 1.f/8.f, + 1.f/16.f, + + // 0.125f + 1.f/32.f, + 1.f/16.f, + 1.f/32.f + }; + + vec3 sampled_color = vec3(0.0f); + + for(uint i = 0; i < 13; i++) + { + vec2 color_fetch = UV_offset + color_fetches[i] * pixel_size; + vec3 color = texture(sampler2D(inBlurImage, inImageSampler), color_fetch).rgb; + color *= color_weights[i]; + sampled_color += color; + } + + imageStore(outBlurImage, pixel_coord, vec4(sampled_color, 1.f)); +} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/bloom/lensFlares.comp b/projects/particle_simulation/shaders/bloom/lensFlares.comp new file mode 100644 index 0000000000000000000000000000000000000000..ce27d8850b709f61332d467914ddc944dc63109f --- /dev/null +++ b/projects/particle_simulation/shaders/bloom/lensFlares.comp @@ -0,0 +1,109 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D blurBuffer; +layout(set=0, binding=1) uniform sampler linearSampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D lensBuffer; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +vec3 sampleColorChromaticAberration(vec2 _uv) +{ + vec2 toCenter = (vec2(0.5) - _uv); + + vec3 colorScales = vec3(-1, 0, 1); + float aberrationScale = 0.1; + vec3 scaleFactors = colorScales * aberrationScale; + + float r = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.r).r; + float g = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.g).g; + float b = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.b).b; + return vec3(r, g, b); +} + +// _uv assumed to be flipped UV coordinates! +vec3 ghost_vectors(vec2 _uv) +{ + vec2 ghost_vec = (vec2(0.5f) - _uv); + + const uint c_ghost_count = 64; + const float c_ghost_spacing = length(ghost_vec) / c_ghost_count; + + ghost_vec *= c_ghost_spacing; + + vec3 ret_color = vec3(0.0f); + + for (uint i = 0; i < c_ghost_count; ++i) + { + // sample scene color + vec2 s_uv = fract(_uv + ghost_vec * vec2(i)); + vec3 s = sampleColorChromaticAberration(s_uv); + + // tint/weight + float d = distance(s_uv, vec2(0.5)); + float weight = 1.0f - smoothstep(0.0f, 0.75f, d); + s *= weight; + + ret_color += s; + } + + ret_color /= c_ghost_count; + return ret_color; +} + +vec3 halo(vec2 _uv) +{ + const float c_aspect_ratio = float(imageSize(lensBuffer).x) / float(imageSize(lensBuffer).y); + const float c_radius = 0.6f; + const float c_halo_thickness = 0.1f; + + vec2 halo_vec = vec2(0.5) - _uv; + //halo_vec.x /= c_aspect_ratio; + halo_vec = normalize(halo_vec); + //halo_vec.x *= c_aspect_ratio; + + + //vec2 w_uv = (_uv - vec2(0.5, 0.0)) * vec2(c_aspect_ratio, 1.0) + vec2(0.5, 0.0); + vec2 w_uv = _uv; + float d = distance(w_uv, vec2(0.5)); // distance to center + + float distance_to_halo = abs(d - c_radius); + + float halo_weight = 0.0f; + if(abs(d - c_radius) <= c_halo_thickness) + { + float distance_to_border = c_halo_thickness - distance_to_halo; + halo_weight = distance_to_border / c_halo_thickness; + + //halo_weight = clamp((halo_weight / 0.4f), 0.0f, 1.0f); + halo_weight = pow(halo_weight, 2.0f); + + + //halo_weight = 1.0f; + } + + return sampleColorChromaticAberration(_uv + halo_vec) * halo_weight; +} + + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(lensBuffer)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / imageSize(lensBuffer); + vec2 UV = pixel_coord.xy * pixel_size; + + vec2 flipped_UV = vec2(1.0f) - UV; + + vec3 color = vec3(0.0f); + + color += ghost_vectors(flipped_UV); + color += halo(UV); + color *= 0.5f; + + imageStore(lensBuffer, pixel_coord, vec4(color, 0.0f)); +} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/bloom/upsample.comp b/projects/particle_simulation/shaders/bloom/upsample.comp new file mode 100644 index 0000000000000000000000000000000000000000..0ddeedb5b5af9e476dc19012fed6430544006c0e --- /dev/null +++ b/projects/particle_simulation/shaders/bloom/upsample.comp @@ -0,0 +1,45 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D inUpsampleImage; +layout(set=0, binding=1) uniform sampler inImageSampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D outUpsampleImage; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outUpsampleImage)))){ + return; + } + + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / imageSize(outUpsampleImage); + vec2 UV = pixel_coord.xy * pixel_size; + + const float gauss_kernel[3] = {1.f, 2.f, 1.f}; + const float gauss_weight = 16.f; + + vec3 sampled_color = vec3(0.f); + + for(int i = -1; i <= 1; i++) + { + for(int j = -1; j <= 1; j++) + { + vec2 sample_location = UV + vec2(j, i) * pixel_size; + vec3 color = texture(sampler2D(inUpsampleImage, inImageSampler), sample_location).rgb; + color *= gauss_kernel[j+1]; + color *= gauss_kernel[i+1]; + color /= gauss_weight; + + sampled_color += color; + } + } + + //vec3 prev_color = imageLoad(outUpsampleImage, pixel_coord).rgb; + //float bloomRimStrength = 0.75f; // adjust this to change strength of bloom + //sampled_color = mix(prev_color, sampled_color, bloomRimStrength); + + imageStore(outUpsampleImage, pixel_coord, vec4(sampled_color, 1.f)); +} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/particleShading.inc b/projects/particle_simulation/shaders/particleShading.inc new file mode 100644 index 0000000000000000000000000000000000000000..b2d1832b9ccd6ba05a585b59bdfdedd4729e80f8 --- /dev/null +++ b/projects/particle_simulation/shaders/particleShading.inc @@ -0,0 +1,6 @@ +float circleFactor(vec2 triangleCoordinates){ + // percentage of distance from center to circle edge + float p = clamp((0.4 - length(triangleCoordinates)) / 0.4, 0, 1); + // remapping for nice falloff + return sqrt(p); +} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/shader.vert b/projects/particle_simulation/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..0a889b35dbb750dc932de57b611f22acaa1ac3f2 --- /dev/null +++ b/projects/particle_simulation/shaders/shader.vert @@ -0,0 +1,45 @@ +#version 460 core +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 particle; + +struct Particle +{ + vec3 position; + float lifeTime; + vec3 velocity; + float padding_2; + vec3 reset_velocity; + float padding_3; +}; + +layout(std430, binding = 2) coherent buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout( push_constant ) uniform constants{ + mat4 view; + mat4 projection; +}; + +layout(location = 0) out vec2 passTriangleCoordinates; +layout(location = 1) out vec3 passVelocity; +layout(location = 2) out float passlifeTime; + +void main() +{ + int id = gl_InstanceIndex; + passVelocity = inParticle[id].velocity; + passlifeTime = inParticle[id].lifeTime; + // particle position in view space + vec4 positionView = view * vec4(inParticle[id].position, 1); + // by adding the triangle position in view space the mesh is always camera facing + positionView.xyz += particle; + // multiply with projection matrix for final position + gl_Position = projection * positionView; + + // 0.01 corresponds to vertex position size in main + float normalizationDivider = 0.012; + passTriangleCoordinates = particle.xy / normalizationDivider; +} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/shader_gravity.comp b/projects/particle_simulation/shaders/shader_gravity.comp new file mode 100644 index 0000000000000000000000000000000000000000..77954958c694a3c6c620818dd3b5d999e51b4a42 --- /dev/null +++ b/projects/particle_simulation/shaders/shader_gravity.comp @@ -0,0 +1,80 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout(local_size_x = 256) in; + +struct Particle +{ + vec3 position; + float lifeTime; + vec3 velocity; + float mass; + vec3 reset_velocity; + float _padding; +}; + +layout(std430, binding = 0) coherent buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout( push_constant ) uniform constants{ + float deltaTime; + float rand; +}; + +const int n = 4; +vec4 gravityPoint[n] = vec4[n]( + vec4(-0.8, -0.5, 0.0, 3), + vec4(-0.4, 0.5, 0.8, 2), + vec4( 0.8, 0.8, -0.3, 4), + vec4( 0.5, -0.7, -0.5, 1) +); + +const float G = 6.6743015e-11; +const float sim_d_factor = 10e11; +const float sim_g_factor = 10e30; +const float sim_t_factor = 5; +const float c = 299792458; + +void main() { + uint id = gl_GlobalInvocationID.x; + inParticle[id].lifeTime -= deltaTime; + vec3 pos = inParticle[id].position; + vec3 vel = inParticle[id].velocity; + float mass = inParticle[id].mass; + + if(inParticle[id].lifeTime < 0.f) + { + inParticle[id].lifeTime = 5.f * rand; + inParticle[id].mass *= rand; + + pos = vec3(0); + vel *= rand; + } + + for(int i = 0; i < n; i++) + { + vec3 d = (gravityPoint[i].xyz - pos) * sim_d_factor; + float r = length(d); + float g = G * (gravityPoint[i].w * sim_g_factor) / (r * r); + + if (r > 0) { + vec3 dvel = (deltaTime * sim_t_factor) * g * (d / r); + + vel = (vel + dvel) / (1.0 + dot(vel, dvel) / (c*c)); + } + } + + pos += vel * (deltaTime * sim_t_factor); + + vec3 a_pos = abs(pos); + + if ((a_pos.x > 2.0) || (a_pos.y > 2.0) || (a_pos.z > 2.0)) + { + inParticle[id].lifeTime *= 0.9; + } + + inParticle[id].position = pos; + inParticle[id].velocity = vel; +} diff --git a/projects/particle_simulation/shaders/shader_space.comp b/projects/particle_simulation/shaders/shader_space.comp new file mode 100644 index 0000000000000000000000000000000000000000..6e25fff8aec8ceab7c1ffdd9be65d9b8fa8f0974 --- /dev/null +++ b/projects/particle_simulation/shaders/shader_space.comp @@ -0,0 +1,73 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout(local_size_x = 256) in; + +struct Particle +{ + vec3 position; + float lifeTime; + vec3 velocity; + float padding_2; + vec3 reset_velocity; + float padding_3; +}; + +layout(std430, binding = 0) coherent buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout( push_constant ) uniform constants{ + float deltaTime; + float rand; +}; + +vec3 attraction(vec3 pos, vec3 attractPos) +{ + vec3 delta = attractPos - pos; + const float damp = 0.5; + float dDampedDot = dot(delta, delta) + damp; + float invDist = 1.0f / sqrt(dDampedDot); + float invDistCubed = invDist*invDist*invDist; + return delta * invDistCubed * 0.0035; +} + +vec3 repulsion(vec3 pos, vec3 attractPos) +{ + vec3 delta = attractPos - pos; + float targetDistance = sqrt(dot(delta, delta)); + return delta * (1.0 / (targetDistance * targetDistance * targetDistance)) * -0.000035; +} + + +const int n = 4; +vec3 gravity = vec3(0,-9.8,0); +vec3 gravityPoint[n] = vec3[n](vec3(-0.3, .5, -0.6),vec3(-0.2, 0.6, -0.3),vec3(.4, -0.4, 0.6),vec3(-.4, -0.4, -0.6)); +//vec3 gravityPoint[n] = vec3[n](vec3(-0.5, 0.5, 0)); +void main() { + uint id = gl_GlobalInvocationID.x; + inParticle[id].lifeTime -= deltaTime; + vec3 pos = inParticle[id].position; + vec3 vel = inParticle[id].velocity; + if(inParticle[id].lifeTime < 0.f) + { + inParticle[id].lifeTime = 5.f; + pos = vec3(0); + } + // inParticle[id].position += deltaTime * -normalize(max(2 - distance(inParticle[id].position,respawnPos),0.0) * respawnPos - inParticle[id].position); + + for(int i = 0; i < n; i++) + { + vel += deltaTime * deltaTime * normalize(max(2 - distance(pos,gravityPoint[i]),0.1) * gravityPoint[i] - pos); + } + + if((pos.x <= -2.0) || (pos.x > 2.0) || (pos.y <= -2.0) || (pos.y > 2.0)|| (pos.z <= -2.0) || (pos.z > 2.0)){ + vel = (-vel * 0.1); + } + + pos += normalize(vel) * deltaTime; + inParticle[id].position = pos; + float rand1 = rand; + inParticle[id].velocity = vel; +} diff --git a/projects/particle_simulation/shaders/shader_space.frag b/projects/particle_simulation/shaders/shader_space.frag new file mode 100644 index 0000000000000000000000000000000000000000..7f6d22065caa3c4b3ab2b1f697c9545a66d7bd54 --- /dev/null +++ b/projects/particle_simulation/shaders/shader_space.frag @@ -0,0 +1,46 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +#include "particleShading.inc" + +layout(location = 0) in vec2 passTriangleCoordinates; +layout(location = 1) in vec3 passVelocity; +layout(location = 2) in float passlifeTime; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=0) uniform uColor { + vec4 color; +} Color; + +layout(set=0,binding=1) uniform uPosition{ + vec2 position; +} Position; + + +void main() +{ + vec2 mouse = vec2(Position.position.x, Position.position.y); + + vec3 c0 = vec3(1, 1, 0.05); + vec3 c1 = vec3(1, passlifeTime * 0.5, 0.05); + vec3 c2 = vec3(passlifeTime * 0.5,passlifeTime * 0.5,0.05); + vec3 c3 = vec3(1, 0.05, 0.05); + + if(passlifeTime < 1){ + outColor = mix(c0, c1, passlifeTime ); + } + else if(passlifeTime < 2){ + outColor = mix(c1, c2, passlifeTime - 1); + } + else{ + outColor = mix(c2, c3, clamp((passlifeTime - 2) * 0.5, 0, 1)); + } + + // make the triangle look like a circle + outColor *= circleFactor(passTriangleCoordinates); + + // fade out particle shortly before it dies + outColor *= clamp(passlifeTime * 2, 0, 1); +} \ No newline at end of file diff --git a/projects/particle_simulation/shaders/shader_water.comp b/projects/particle_simulation/shaders/shader_water.comp new file mode 100644 index 0000000000000000000000000000000000000000..d1a0e761038b5fb367a33454c746871f1a6a4553 --- /dev/null +++ b/projects/particle_simulation/shaders/shader_water.comp @@ -0,0 +1,84 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout(local_size_x = 256) in; + +struct Particle +{ + vec3 position; + float lifeTime; + vec3 velocity; + float padding_2; + vec3 reset_velocity; + float padding_3; +}; + +layout(std430, binding = 0) coherent buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout( push_constant ) uniform constants{ + float deltaTime; + float rand; +}; + +vec3 attraction(vec3 pos, vec3 attractPos) +{ + vec3 delta = attractPos - pos; + const float damp = 0.5; + float dDampedDot = dot(delta, delta) + damp; + float invDist = 1.0f / sqrt(dDampedDot); + float invDistCubed = invDist*invDist*invDist; + return delta * invDistCubed * 0.0035; +} + +vec3 repulsion(vec3 pos, vec3 attractPos) +{ + vec3 delta = attractPos - pos; + float targetDistance = sqrt(dot(delta, delta)); + return delta * (1.0 / (targetDistance * targetDistance * targetDistance)) * -0.000035; +} + + +const int n = 3; +vec3 gravity = vec3(0,-9.8,0); +vec3 gravityPoint[n] = vec3[n](vec3(-0.5, 0.5, 0),vec3(0.5, 0.5, 0),vec3(0, -0.5, 0)); +//vec3 gravityPoint[n] = vec3[n](vec3(-0.5, 0.5, 0)); +void main() { + uint id = gl_GlobalInvocationID.x; + inParticle[id].lifeTime -= deltaTime; + vec3 pos = inParticle[id].position; + vec3 vel = inParticle[id].velocity; + if(inParticle[id].lifeTime < 0.f) + { + inParticle[id].lifeTime = 7.f; + pos = vec3(0); + vel = inParticle[id].reset_velocity; + inParticle[id].velocity = inParticle[id].reset_velocity; + } + // inParticle[id].position += deltaTime * -normalize(max(2 - distance(inParticle[id].position,respawnPos),0.0) * respawnPos - inParticle[id].position); + + for(int i = 0; i < n; i++) + { + vel += deltaTime * deltaTime * deltaTime * normalize(max(2 - distance(pos,gravityPoint[i]),0.1) * gravityPoint[i] - pos); + } + + //vec3 delta = respawnPos - pos; + //float targetDistane = sqrt(dot(delta,delta)); + //vel += repulsion(pos, respawnPos); + + //if((pos.x <= -1.0) || (pos.x > 1.0) || (pos.y <= -1.0) || (pos.y > 1.0)|| (pos.z <= -1.0) || (pos.z > 1.0)) + vel = (-vel * 0.01); + + if((pos.y <= -1.0) || (pos.y > 1.0)){ + vel = reflect(vel, vec3(0,1,0)); + } + + pos += normalize(vel) * deltaTime; + inParticle[id].position = pos; + + float weight = 1.0; + float rand1 = rand; + inParticle[id].velocity = vel; +} diff --git a/projects/particle_simulation/shaders/shader_water.frag b/projects/particle_simulation/shaders/shader_water.frag new file mode 100644 index 0000000000000000000000000000000000000000..b68f9572a91b05e836c3fead9ae9afd7ce16ba8e --- /dev/null +++ b/projects/particle_simulation/shaders/shader_water.frag @@ -0,0 +1,46 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +#include "particleShading.inc" + +layout(location = 0) in vec2 passTriangleCoordinates; +layout(location = 1) in vec3 passVelocity; +layout(location = 2) in float passlifeTime; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=0) uniform uColor { + vec4 color; +} Color; + +layout(set=0,binding=1) uniform uPosition{ + vec2 position; +} Position; + +void main() +{ + float normlt = 1-normalize(passlifeTime); + vec2 mouse = vec2(Position.position.x, Position.position.y); + + vec3 c0 = vec3(0.2,0.5,1); + vec3 c1 = vec3(0.3, 0.7,1); + vec3 c2 = vec3(0.5,0.9,1); + vec3 c3 = vec3(0.9,1,1); + + if(passlifeTime < 1){ + outColor = mix(c0, c1, passlifeTime ); + } + else if(passlifeTime < 2){ + outColor = mix(c1, c2, passlifeTime - 1); + } + else{ + outColor = mix(c2, c3, clamp((passlifeTime - 2) * 0.5, 0, 1)); + } + + // make the triangle look like a circle + outColor *= circleFactor(passTriangleCoordinates); + + // fade out particle shortly before it dies + outColor *= clamp(passlifeTime * 2, 0, 1); +} diff --git a/projects/particle_simulation/shaders/tonemapping.comp b/projects/particle_simulation/shaders/tonemapping.comp new file mode 100644 index 0000000000000000000000000000000000000000..26f0232d66e3475afdd1266c0cc6288b47ed1c38 --- /dev/null +++ b/projects/particle_simulation/shaders/tonemapping.comp @@ -0,0 +1,19 @@ +#version 440 + +layout(set=0, binding=0, rgba16f) uniform image2D inImage; +layout(set=0, binding=1, rgba8) uniform image2D outImage; + + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main(){ + + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(inImage)))){ + return; + } + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + vec3 linearColor = imageLoad(inImage, uv).rgb; + vec3 tonemapped = linearColor / (dot(linearColor, vec3(0.21, 0.71, 0.08)) + 1); // reinhard tonemapping + vec3 gammaCorrected = pow(tonemapped, vec3(1.f / 2.2f)); + imageStore(outImage, uv, vec4(gammaCorrected, 0.f)); +} \ No newline at end of file diff --git a/projects/particle_simulation/src/BloomAndFlares.cpp b/projects/particle_simulation/src/BloomAndFlares.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23ace2bc35a2e421613718c62380f9161a408f70 --- /dev/null +++ b/projects/particle_simulation/src/BloomAndFlares.cpp @@ -0,0 +1,274 @@ +#include "BloomAndFlares.hpp" +#include <vkcv/shader/GLSLCompiler.hpp> + +BloomAndFlares::BloomAndFlares( + vkcv::Core *p_Core, + vk::Format colorBufferFormat, + uint32_t width, + uint32_t height) : + + p_Core(p_Core), + m_ColorBufferFormat(colorBufferFormat), + m_Width(width), + m_Height(height), + m_LinearSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE)), + m_Blur(p_Core->createImage(colorBufferFormat, width, height, 1, true, true, false)), + m_LensFeatures(p_Core->createImage(colorBufferFormat, width, height, 1, false, true, false)) +{ + vkcv::shader::GLSLCompiler compiler; + + // DOWNSAMPLE + vkcv::ShaderProgram dsProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/downsample.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + dsProg.addShader(shaderStage, path); + }); + for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) + { + m_DownsampleDescSets.push_back( + p_Core->createDescriptorSet(dsProg.getReflectedDescriptors()[0])); + } + m_DownsamplePipe = p_Core->createComputePipeline( + dsProg, { p_Core->getDescriptorSet(m_DownsampleDescSets[0]).layout }); + + // UPSAMPLE + vkcv::ShaderProgram usProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/upsample.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + usProg.addShader(shaderStage, path); + }); + for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) + { + m_UpsampleDescSets.push_back( + p_Core->createDescriptorSet(usProg.getReflectedDescriptors()[0])); + } + m_UpsamplePipe = p_Core->createComputePipeline( + usProg, { p_Core->getDescriptorSet(m_UpsampleDescSets[0]).layout }); + + // LENS FEATURES + vkcv::ShaderProgram lensProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/lensFlares.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + lensProg.addShader(shaderStage, path); + }); + m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors()[0]); + m_LensFlarePipe = p_Core->createComputePipeline( + lensProg, { p_Core->getDescriptorSet(m_LensFlareDescSet).layout }); + + // COMPOSITE + vkcv::ShaderProgram compProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/composite.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + compProg.addShader(shaderStage, path); + }); + m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors()[0]); + m_CompositePipe = p_Core->createComputePipeline( + compProg, { p_Core->getDescriptorSet(m_CompositeDescSet).layout }); +} + +void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; + auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; + // blur dispatch + uint32_t initialDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + + // downsample dispatch of original color attachment + p_Core->prepareImageForSampling(cmdStream, colorAttachment); + p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); + + vkcv::DescriptorWrites initialDownsampleWrites; + initialDownsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorAttachment)}; + initialDownsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + initialDownsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), 0) }; + p_Core->writeDescriptorSet(m_DownsampleDescSets[0], initialDownsampleWrites); + + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_DownsamplePipe, + initialDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); + + // downsample dispatches of blur buffer's mip maps + float mipDispatchCountX = dispatchCountX; + float mipDispatchCountY = dispatchCountY; + for(uint32_t mipLevel = 1; mipLevel < std::min((uint32_t)m_DownsampleDescSets.size(), m_Blur.getMipCount()); mipLevel++) + { + // mip descriptor writes + vkcv::DescriptorWrites mipDescriptorWrites; + mipDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel - 1, true)}; + mipDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + mipDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel) }; + p_Core->writeDescriptorSet(m_DownsampleDescSets[mipLevel], mipDescriptorWrites); + + // mip dispatch calculation + mipDispatchCountX /= 2.0f; + mipDispatchCountY /= 2.0f; + + uint32_t mipDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(mipDispatchCountX)), + static_cast<uint32_t>(glm::ceil(mipDispatchCountY)), + 1 + }; + + if(mipDispatchCount[0] == 0) + mipDispatchCount[0] = 1; + if(mipDispatchCount[1] == 0) + mipDispatchCount[1] = 1; + + // mip blur dispatch + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_DownsamplePipe, + mipDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); + + // image barrier between mips + p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); + } +} + +void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) +{ + // upsample dispatch + p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); + + const uint32_t upsampleMipLevels = std::min( + static_cast<uint32_t>(m_UpsampleDescSets.size() - 1), + static_cast<uint32_t>(3) + ); + + // upsample dispatch for each mip map + for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--) + { + // mip descriptor writes + vkcv::DescriptorWrites mipUpsampleWrites; + mipUpsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel, true)}; + mipUpsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + mipUpsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel - 1) }; + p_Core->writeDescriptorSet(m_UpsampleDescSets[mipLevel], mipUpsampleWrites); + + auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f); + + auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor; + auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor; + upsampleDispatchX /= 8.0f; + upsampleDispatchY /= 8.0f; + + const uint32_t upsampleDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(upsampleDispatchX)), + static_cast<uint32_t>(glm::ceil(upsampleDispatchY)), + 1 + }; + + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_UpsamplePipe, + upsampleDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0) + ); + // image barrier between mips + p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); + } +} + +void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) +{ + // lens feature generation descriptor writes + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); + p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); + + vkcv::DescriptorWrites lensFeatureWrites; + lensFeatureWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), 0)}; + lensFeatureWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + lensFeatureWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), 0)}; + p_Core->writeDescriptorSet(m_LensFlareDescSet, lensFeatureWrites); + + auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; + auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; + // lens feature generation dispatch + uint32_t lensFeatureDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_LensFlarePipe, + lensFeatureDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); +} + +void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); + p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); + p_Core->prepareImageForStorage(cmdStream, colorAttachment); + + // bloom composite descriptor write + vkcv::DescriptorWrites compositeWrites; + compositeWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle()), + vkcv::SampledImageDescriptorWrite(1, m_LensFeatures.getHandle())}; + compositeWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(2, m_LinearSampler)}; + compositeWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(3, colorAttachment)}; + p_Core->writeDescriptorSet(m_CompositeDescSet, compositeWrites); + + float dispatchCountX = static_cast<float>(m_Width) / 8.0f; + float dispatchCountY = static_cast<float>(m_Height) / 8.0f; + + uint32_t compositeDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + + // bloom composite dispatch + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_CompositePipe, + compositeDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); +} + +void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + execDownsamplePipe(cmdStream, colorAttachment); + execUpsamplePipe(cmdStream); + execLensFeaturePipe(cmdStream); + execCompositePipe(cmdStream, colorAttachment); +} + +void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height) +{ + m_Width = width; + m_Height = height; + + p_Core->getContext().getDevice().waitIdle(); + m_Blur = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false); + m_LensFeatures = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, false, true, false); +} + + diff --git a/projects/particle_simulation/src/BloomAndFlares.hpp b/projects/particle_simulation/src/BloomAndFlares.hpp new file mode 100644 index 0000000000000000000000000000000000000000..756b1ca154ea5232df04eb09a88bb743c5bd28aa --- /dev/null +++ b/projects/particle_simulation/src/BloomAndFlares.hpp @@ -0,0 +1,47 @@ +#pragma once +#include <vkcv/Core.hpp> +#include <glm/glm.hpp> + +class BloomAndFlares{ +public: + BloomAndFlares(vkcv::Core *p_Core, + vk::Format colorBufferFormat, + uint32_t width, + uint32_t height); + + void execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); + + void updateImageDimensions(uint32_t width, uint32_t height); + +private: + vkcv::Core *p_Core; + + vk::Format m_ColorBufferFormat; + uint32_t m_Width; + uint32_t m_Height; + + vkcv::SamplerHandle m_LinearSampler; + vkcv::Image m_Blur; + vkcv::Image m_LensFeatures; + + + vkcv::PipelineHandle m_DownsamplePipe; + std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set + + vkcv::PipelineHandle m_UpsamplePipe; + std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set + + vkcv::PipelineHandle m_LensFlarePipe; + vkcv::DescriptorSetHandle m_LensFlareDescSet; + + vkcv::PipelineHandle m_CompositePipe; + vkcv::DescriptorSetHandle m_CompositeDescSet; + + void execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); + void execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream); + void execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream); + void execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); +}; + + + diff --git a/projects/particle_simulation/src/Particle.cpp b/projects/particle_simulation/src/Particle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..387728eb366430e4373282da785bbff47de17e7a --- /dev/null +++ b/projects/particle_simulation/src/Particle.cpp @@ -0,0 +1,41 @@ + +#include "Particle.hpp" + +Particle::Particle(glm::vec3 position, glm::vec3 velocity, float lifeTime) +: m_position(position), +m_velocity(velocity), +m_lifeTime(lifeTime), +m_reset_velocity(velocity) +{} + +const glm::vec3& Particle::getPosition()const{ + return m_position; +} + +const bool Particle::isAlive()const{ + return m_lifeTime > 0.f; +} + +void Particle::setPosition( const glm::vec3 pos ){ + m_position = pos; +} + +const glm::vec3& Particle::getVelocity()const{ + return m_velocity; +} + +void Particle::setVelocity( const glm::vec3 vel ){ + m_velocity = vel; +} + +void Particle::update( const float delta ){ + m_position += m_velocity * delta; +} + +void Particle::setLifeTime( const float lifeTime ){ + m_lifeTime = lifeTime; +} + +const float& Particle::getLifeTime()const{ + return m_lifeTime; +} \ No newline at end of file diff --git a/projects/particle_simulation/src/Particle.hpp b/projects/particle_simulation/src/Particle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f374218fd8a08f1e1bf367bdc899a71c55ea1b78 --- /dev/null +++ b/projects/particle_simulation/src/Particle.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <glm/glm.hpp> + +class Particle { + +public: + Particle(glm::vec3 position, glm::vec3 velocity, float lifeTime = 1.f); + + const glm::vec3& getPosition()const; + + void setPosition( const glm::vec3 pos ); + + const glm::vec3& getVelocity()const; + + void setVelocity( const glm::vec3 vel ); + + void update( const float delta ); + + const bool isAlive()const; + + void setLifeTime( const float lifeTime ); + + const float& getLifeTime()const; + +private: + // all properties of the Particle + glm::vec3 m_position; + float m_lifeTime; + glm::vec3 m_velocity; + float mass = 1.f; + glm::vec3 m_reset_velocity; + float padding_3 = 0.f; +}; diff --git a/projects/particle_simulation/src/ParticleSystem.cpp b/projects/particle_simulation/src/ParticleSystem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3162d6bea685640d3949577271affc8b2080407 --- /dev/null +++ b/projects/particle_simulation/src/ParticleSystem.cpp @@ -0,0 +1,60 @@ +#include "ParticleSystem.hpp" + +ParticleSystem::ParticleSystem(uint32_t particleCount ,glm::vec3 minVelocity , glm::vec3 maxVelocity , glm::vec2 lifeTime ) +{ + m_rdmVel.resize(3); + m_rdmVel[0] = std::uniform_real_distribution<float>(minVelocity.x, maxVelocity.x); + m_rdmVel[1] = std::uniform_real_distribution<float>(minVelocity.y, maxVelocity.y); + m_rdmVel[2] = std::uniform_real_distribution<float>(minVelocity.z, maxVelocity.z); + m_rdmLifeTime = std::uniform_real_distribution<float>(lifeTime.x, lifeTime.y); + + for(uint32_t i = 0; i < particleCount ;i++ ){ + addParticle(Particle(m_respawnPos, getRandomVelocity(), getRandomLifeTime())); + } +} + +const std::vector<Particle>& ParticleSystem::getParticles() const{ + return m_particles; +} + +void ParticleSystem::addParticle( const Particle particle ){ + m_particles.push_back(particle); +} +void ParticleSystem::addParticles( const std::vector<Particle> particles ){ + m_particles.insert(m_particles.end(), particles.begin(), particles.end()); +} + +void ParticleSystem::updateParticles( const float deltaTime ){ + for(Particle& particle :m_particles){ + bool alive = particle.isAlive(); + particle.setPosition( particle.getPosition() * static_cast<float>(alive) + static_cast<float>(!alive) * m_respawnPos ); + particle.setVelocity( particle.getVelocity() * static_cast<float>(alive) + static_cast<float>(!alive) * getRandomVelocity()); + particle.setLifeTime( (particle.getLifeTime() * alive + !alive * getRandomLifeTime() ) - deltaTime ); + particle.update(deltaTime); + } +} + +glm::vec3 ParticleSystem::getRandomVelocity(){ + return glm::vec3(m_rdmVel[0](m_rdmEngine), m_rdmVel[1](m_rdmEngine),m_rdmVel[2](m_rdmEngine)); +} + +float ParticleSystem::getRandomLifeTime(){ + return m_rdmLifeTime(m_rdmEngine); +} + +void ParticleSystem::setRespawnPos( const glm::vec3 respawnPos){ + m_respawnPos = respawnPos; +} +void ParticleSystem::setRdmLifeTime( const glm::vec2 lifeTime ){ + m_rdmLifeTime = std::uniform_real_distribution<float> (lifeTime.x,lifeTime.y); +} + +void ParticleSystem::setRdmVelocity( glm::vec3 minVelocity, glm::vec3 maxVelocity ){ + m_rdmVel[0] = std::uniform_real_distribution<float> (minVelocity.x,maxVelocity.x); + m_rdmVel[1] = std::uniform_real_distribution<float> (minVelocity.y,maxVelocity.y); + m_rdmVel[2] = std::uniform_real_distribution<float> (minVelocity.z,maxVelocity.z); +} + +const glm::vec3 ParticleSystem::getRespawnPos() const{ + return m_respawnPos; +} diff --git a/projects/particle_simulation/src/ParticleSystem.hpp b/projects/particle_simulation/src/ParticleSystem.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fe5c99f9b407b9dbdfd414e265e7cd91bbe790b9 --- /dev/null +++ b/projects/particle_simulation/src/ParticleSystem.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include <vector> +#include "Particle.hpp" +#include <random> +#include "vkcv/Buffer.hpp" + +class ParticleSystem { + +public: + ParticleSystem(uint32_t particleCount , glm::vec3 minVelocity = glm::vec3(0.f,0.f,0.f), glm::vec3 maxVelocity = glm::vec3(1.f,1.f,0.f), glm::vec2 lifeTime = glm::vec2(2.f,3.f)); + const std::vector<Particle> &getParticles() const; + void updateParticles( const float deltaTime ); + void setRespawnPos( const glm::vec3 respawnPos ); + void setRdmLifeTime( const glm::vec2 lifeTime ); + void setRdmVelocity( glm::vec3 minVelocity, glm::vec3 maxVelocity ); + const glm::vec3 getRespawnPos() const; + +private: + + void addParticle( const Particle particle ); + void addParticles( const std::vector<Particle> particles ); + glm::vec3 getRandomVelocity(); + float getRandomLifeTime(); + + std::vector<Particle> m_particles; + glm::vec3 m_respawnPos = glm::vec3(0.f); + + std::vector<std::uniform_real_distribution<float>> m_rdmVel; + std::uniform_real_distribution<float> m_rdmLifeTime; + std::default_random_engine m_rdmEngine; +}; \ No newline at end of file diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a22044f0d2588a43a5e7a0f6cba25d9c7460be9f --- /dev/null +++ b/projects/particle_simulation/src/main.cpp @@ -0,0 +1,320 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include "ParticleSystem.hpp" +#include <random> +#include <glm/gtc/matrix_access.hpp> +#include <time.h> +#include <vkcv/shader/GLSLCompiler.hpp> +#include "BloomAndFlares.hpp" + +int main(int argc, const char **argv) { + const char *applicationName = "Particlesystem"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + true + ); + + vkcv::camera::CameraManager cameraManager(window); + + vkcv::Core core = vkcv::Core::create( + window, + applicationName, + VK_MAKE_VERSION(0, 0, 1), + {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, + {}, + {"VK_KHR_swapchain"} + ); + + auto particleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, + vkcv::BufferMemoryType::DEVICE_LOCAL); + uint16_t indices[3] = {0, 1, 2}; + particleIndexBuffer.fill(&indices[0], sizeof(indices)); + + vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + colorFormat); + + + vkcv::PassConfig particlePassDefinition({present_color_attachment}); + vkcv::PassHandle particlePass = core.createPass(particlePassDefinition); + + vkcv::PassConfig computePassDefinition({}); + vkcv::PassHandle computePass = core.createPass(computePassDefinition); + + if (!particlePass || !computePass) + { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + // use space or use water + bool useSpace = true; + + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram computeShaderProgram{}; + compiler.compile(vkcv::ShaderStage::COMPUTE, useSpace ? "shaders/shader_space.comp" : "shaders/shader_water.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + computeShaderProgram.addShader(shaderStage, path); + }); + + vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeShaderProgram.getReflectedDescriptors()[0]); + + const std::vector<vkcv::VertexAttachment> computeVertexAttachments = computeShaderProgram.getVertexAttachments(); + + std::vector<vkcv::VertexBinding> computeBindings; + for (size_t i = 0; i < computeVertexAttachments.size(); i++) { + computeBindings.push_back(vkcv::VertexBinding(i, { computeVertexAttachments[i] })); + } + const vkcv::VertexLayout computeLayout(computeBindings); + + vkcv::ShaderProgram particleShaderProgram{}; + compiler.compile(vkcv::ShaderStage::VERTEX, "shaders/shader.vert", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + particleShaderProgram.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, useSpace ? "shaders/shader_space.frag" : "shaders/shader_water.frag", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + particleShaderProgram.addShader(shaderStage, path); + }); + + vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet( + particleShaderProgram.getReflectedDescriptors()[0]); + + vkcv::Buffer<glm::vec3> vertexBuffer = core.createBuffer<glm::vec3>( + vkcv::BufferType::VERTEX, + 3 + ); + const std::vector<vkcv::VertexAttachment> vertexAttachments = particleShaderProgram.getVertexAttachments(); + + const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { + vkcv::VertexBufferBinding(0, vertexBuffer.getVulkanHandle())}; + + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, {vertexAttachments[i]})); + } + + const vkcv::VertexLayout particleLayout(bindings); + + vkcv::PipelineConfig particlePipelineDefinition{ + particleShaderProgram, + UINT32_MAX, + UINT32_MAX, + particlePass, + {particleLayout}, + {core.getDescriptorSet(descriptorSet).layout}, + true}; + particlePipelineDefinition.m_blendMode = vkcv::BlendMode::Additive; + + const std::vector<glm::vec3> vertices = {glm::vec3(-0.012, 0.012, 0), + glm::vec3(0.012, 0.012, 0), + glm::vec3(0, -0.012, 0)}; + + vertexBuffer.fill(vertices); + + vkcv::PipelineHandle particlePipeline = core.createGraphicsPipeline(particlePipelineDefinition); + + vkcv::PipelineHandle computePipeline = core.createComputePipeline(computeShaderProgram, {core.getDescriptorSet(computeDescriptorSet).layout} ); + + vkcv::Buffer<glm::vec4> color = core.createBuffer<glm::vec4>( + vkcv::BufferType::UNIFORM, + 1 + ); + + vkcv::Buffer<glm::vec2> position = core.createBuffer<glm::vec2>( + vkcv::BufferType::UNIFORM, + 1 + ); + + glm::vec3 minVelocity = glm::vec3(-0.1f,-0.1f,-0.1f); + glm::vec3 maxVelocity = glm::vec3(0.1f,0.1f,0.1f); + glm::vec2 lifeTime = glm::vec2(-1.f,8.f); + ParticleSystem particleSystem = ParticleSystem( 100000 , minVelocity, maxVelocity, lifeTime); + + vkcv::Buffer<Particle> particleBuffer = core.createBuffer<Particle>( + vkcv::BufferType::STORAGE, + particleSystem.getParticles().size() + ); + + particleBuffer.fill(particleSystem.getParticles()); + + vkcv::DescriptorWrites setWrites; + setWrites.uniformBufferWrites = {vkcv::UniformBufferDescriptorWrite(0,color.getHandle()), + vkcv::UniformBufferDescriptorWrite(1,position.getHandle())}; + setWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(2,particleBuffer.getHandle())}; + core.writeDescriptorSet(descriptorSet, setWrites); + + vkcv::DescriptorWrites computeWrites; + computeWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0,particleBuffer.getHandle())}; + core.writeDescriptorSet(computeDescriptorSet, computeWrites); + + if (!particlePipeline || !computePipeline) + { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(), + particleIndexBuffer.getCount()); + vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); + //vkcv::DrawcallInfo drawcalls(renderMesh, {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle)}); + + glm::vec2 pos = glm::vec2(0.f); + glm::vec3 spawnPosition = glm::vec3(0.f); + glm::vec4 tempPosition = glm::vec4(0.f); + + window.e_mouseMove.add([&](double offsetX, double offsetY) { + pos = glm::vec2(static_cast<float>(offsetX), static_cast<float>(offsetY)); +// std::cout << offsetX << " , " << offsetY << std::endl; + // borders are assumed to be 0.5 + //pos = glm::vec2((pos.x -0.5f * static_cast<float>(window.getWidth()))/static_cast<float>(window.getWidth()), (pos.y -0.5f * static_cast<float>(window.getHeight()))/static_cast<float>(window.getHeight())); + //borders are assumed to be 1 + pos.x = (-2 * pos.x + static_cast<float>(window.getWidth())) / static_cast<float>(window.getWidth()); + pos.y = (-2 * pos.y + static_cast<float>(window.getHeight())) / static_cast<float>(window.getHeight()); + glm::vec4 row1 = glm::row(cameraManager.getCamera(0).getView(), 0); + glm::vec4 row2 = glm::row(cameraManager.getCamera(0).getView(), 1); + glm::vec4 row3 = glm::row(cameraManager.getCamera(0).getView(), 2); + glm::vec4 camera_pos = glm::column(cameraManager.getCamera(0).getView(), 3); +// std::cout << "row1: " << row1.x << ", " << row1.y << ", " << row1.z << std::endl; +// std::cout << "row2: " << row2.x << ", " << row2.y << ", " << row2.z << std::endl; +// std::cout << "row3: " << row3.x << ", " << row3.y << ", " << row3.z << std::endl; +// std::cout << "camerapos: " << camera_pos.x << ", " << camera_pos.y << ", " << camera_pos.z << std::endl; +// std::cout << "camerapos: " << camera_pos.x << ", " << camera_pos.y << ", " << camera_pos.z << std::endl; + //glm::vec4 view_axis = glm::row(cameraManager.getCamera().getView(), 2); + // std::cout << "view_axis: " << view_axis.x << ", " << view_axis.y << ", " << view_axis.z << std::endl; + //std::cout << "Front: " << cameraManager.getCamera().getFront().x << ", " << cameraManager.getCamera().getFront().z << ", " << cameraManager.getCamera().getFront().z << std::endl; + glm::mat4 viewmat = cameraManager.getCamera(0).getView(); + spawnPosition = glm::vec3(pos.x, pos.y, 0.f); + tempPosition = glm::vec4(spawnPosition, 1.0f); + spawnPosition = glm::vec3(tempPosition.x, tempPosition.y, tempPosition.z); + particleSystem.setRespawnPos(glm::vec3(-spawnPosition.x, spawnPosition.y, spawnPosition.z)); +// std::cout << "respawn pos: " << spawnPosition.x << ", " << spawnPosition.y << ", " << spawnPosition.z << std::endl; + }); + + std::vector<glm::mat4> modelMatrices; + std::vector<vkcv::DrawcallInfo> drawcalls; + drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage}, particleSystem.getParticles().size())); + + auto start = std::chrono::system_clock::now(); + + glm::vec4 colorData = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setNearFar(0.1, 30); + cameraManager.getCamera(camIndex1).setNearFar(0.1, 30); + + cameraManager.setActiveCamera(1); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2)); + cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.0f)); + cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f)); + + vkcv::ImageHandle colorBuffer = core.createImage(colorFormat, windowWidth, windowHeight, 1, false, true, true).getHandle(); + BloomAndFlares bloomAndFlares(&core, colorFormat, windowWidth, windowHeight); + window.e_resize.add([&](int width, int height) { + windowWidth = width; + windowHeight = height; + colorBuffer = core.createImage(colorFormat, windowWidth, windowHeight, 1, false, true, true).getHandle(); + bloomAndFlares.updateImageDimensions(width, height); + }); + + vkcv::ShaderProgram tonemappingShader; + compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/tonemapping.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + tonemappingShader.addShader(shaderStage, path); + }); + + vkcv::DescriptorSetHandle tonemappingDescriptor = core.createDescriptorSet(tonemappingShader.getReflectedDescriptors()[0]); + vkcv::PipelineHandle tonemappingPipe = core.createComputePipeline( + tonemappingShader, + { core.getDescriptorSet(tonemappingDescriptor).layout }); + + std::uniform_real_distribution<float> rdm = std::uniform_real_distribution<float>(0.95f, 1.05f); + std::default_random_engine rdmEngine; + while (window.isWindowOpen()) { + window.pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight)) { + continue; + } + + color.fill(&colorData); + position.fill(&pos); + + auto end = std::chrono::system_clock::now(); + float deltatime = 0.000001 * static_cast<float>( std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() ); + start = end; +// particleSystem.updateParticles(deltatime); + + cameraManager.update(deltatime); + + // split view and projection to allow for easy billboarding in shader + glm::mat4 renderingMatrices[2]; + renderingMatrices[0] = cameraManager.getActiveCamera().getView(); + renderingMatrices[1] = cameraManager.getActiveCamera().getProjection(); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + float random = rdm(rdmEngine); + glm::vec2 pushData = glm::vec2(deltatime, random); + + vkcv::PushConstantData pushConstantDataCompute( &pushData, sizeof(glm::vec2)); + uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(particleSystem.getParticles().size()/256.f)),1,1}; + core.recordComputeDispatchToCmdStream(cmdStream, + computePipeline, + computeDispatchCount, + {vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet).vulkanHandle)}, + pushConstantDataCompute); + + core.recordBufferMemoryBarrier(cmdStream, particleBuffer.getHandle()); + + vkcv::PushConstantData pushConstantDataDraw((void *) &renderingMatrices[0], 2 * sizeof(glm::mat4)); + core.recordDrawcallsToCmdStream( + cmdStream, + particlePass, + particlePipeline, + pushConstantDataDraw, + {drawcalls}, + { colorBuffer }); + + bloomAndFlares.execWholePipeline(cmdStream, colorBuffer); + + core.prepareImageForStorage(cmdStream, colorBuffer); + core.prepareImageForStorage(cmdStream, swapchainInput); + + vkcv::DescriptorWrites tonemappingDescriptorWrites; + tonemappingDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, colorBuffer), + vkcv::StorageImageDescriptorWrite(1, swapchainInput) + }; + core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); + + uint32_t tonemappingDispatchCount[3]; + tonemappingDispatchCount[0] = std::ceil(windowWidth / 8.f); + tonemappingDispatchCount[1] = std::ceil(windowHeight / 8.f); + tonemappingDispatchCount[2] = 1; + + core.recordComputeDispatchToCmdStream( + cmdStream, + tonemappingPipe, + tonemappingDispatchCount, + {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptor).vulkanHandle) }, + vkcv::PushConstantData(nullptr, 0)); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + core.endFrame(); + } + + return 0; +} diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp index a5105bd26cc171d884075ebf5dc0e8f3d511e949..c117b4b9e6b896fbf51aae83343f30281061be9f 100644 --- a/projects/voxelization/src/Voxelization.cpp +++ b/projects/voxelization/src/Voxelization.cpp @@ -263,7 +263,7 @@ void Voxelization::voxelizeMeshes( { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelizationDescriptorSet).vulkanHandle), vkcv::DescriptorSetUsage(1, m_corePtr->getDescriptorSet(perMeshDescriptorSets[i]).vulkanHandle) - })); + },1)); } m_corePtr->prepareImageForStorage(cmdStream, m_voxelImageIntermediate.getHandle()); @@ -335,7 +335,7 @@ void Voxelization::renderVoxelVisualisation( const auto drawcall = vkcv::DrawcallInfo( vkcv::Mesh({}, nullptr, drawVoxelCount), - { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).vulkanHandle) }); + { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).vulkanHandle) },1); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); m_corePtr->recordDrawcallsToCmdStream( diff --git a/src/vkcv/DrawcallRecording.cpp b/src/vkcv/DrawcallRecording.cpp index d28ea36c6108306fe603185e9848a72af6455606..e6ea18588c251b5e49f454618a5ac9962cc8a264 100644 --- a/src/vkcv/DrawcallRecording.cpp +++ b/src/vkcv/DrawcallRecording.cpp @@ -38,10 +38,10 @@ namespace vkcv { if (drawcall.mesh.indexBuffer) { cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size - cmdBuffer.drawIndexed(drawcall.mesh.indexCount, 1, 0, 0, {}); + cmdBuffer.drawIndexed(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {}); } else { cmdBuffer.draw(drawcall.mesh.indexCount, 1, 0, 0, {}); } } -} \ No newline at end of file +} diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 5ee8d38764f81b3b24046837734ea45017bc0faa..ae554e6babdd2b2f42c352515c02a34e45182fec 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -278,7 +278,7 @@ namespace vkcv { const auto& image = m_images[id]; - if (mipLevel >= m_images.size()) { + if (mipLevel >= image.m_viewPerMip.size()) { vkcv_log(LogLevel::ERROR, "Image does not have requested mipLevel"); return nullptr; } diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index 762078befe456de438349612155f3624de4e5d6e..8b1f0b68be3a72f60103ca0dd8136f2c923513a5 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -202,8 +202,11 @@ namespace vkcv VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); + + // currently set to additive, if not disabled + // BlendFactors must be set as soon as additional BlendModes are added vk::PipelineColorBlendAttachmentState colorBlendAttachmentState( - false, + config.m_blendMode != BlendMode::None, vk::BlendFactor::eOne, vk::BlendFactor::eOne, vk::BlendOp::eAdd,