diff --git a/README.md b/README.md index bec6ca4..29365a2 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,31 @@ Vulkan Flocking: compute and shading in one pipeline! **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 6** -* (TODO) YOUR NAME HERE - Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Xiang Deng +* Tested on: Windows 10-Home, i7-6700U @ 2.6GHz 16GB, GTX 1060 6GB (Personal Computer) - ### (TODO: Your README) +![](img/e.gif) - Include screenshots, analysis, etc. (Remember, this is public, so don't put - anything here that you don't want to share with the world.) +* Analysis +* Q: Why do you think Vulkan expects explicit descriptors for things like +generating pipelines and commands? HINT: this may relate to something in the +comments about some components using pre-allocated GPU memory. +* A: For efficiency, Vulkan uses pre-allocated command pool on GPU. Explicit descriptors is thus needed +for preallocation prior to the run time (to avoid the overhead). + +* Q: Describe a situation besides flip-flop buffers in which you may need multiple +descriptor sets to fit one descriptor layout. +* A: When you need more descriptor set than two for the shader bindings, like normals, colors, etc. +* Q: What are some problems to keep in mind when using multiple Vulkan queues? + * take into consideration that different queues may be backed by different hardware + * take into consideration that the same buffer may be used across multiple queues +* A: When diffrent queues are backed by different hardware, is some queue is only used by some hardware, it might sacrifice the performance of the hardware that + does not need it. + WHen multiple queues share the same buffer, we might run into racing problem. +* Q: What is one advantage of using compute commands that can share data with a +rendering pipeline? +* A: "no need to do state tracking", no need to transfer data between computing and rendering over and over again. ### Credits * [Vulkan examples and demos](https://github.com/SaschaWillems/Vulkan) by [@SaschaWillems](https://github.com/SaschaWillems) diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index a30387e..2c59e84 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -50,7 +50,7 @@ class VulkanExampleBase bool enableVSync = false; // Device features enabled by the example // If not set, no additional features are enabled (may result in validation layer errors) - VkPhysicalDeviceFeatures enabledFeatures = {}; + VkPhysicalDeviceFeatures enabledFeatures ; // fps timer (one second interval) float fpsTimer = 0.0f; // Create application wide Vulkan instance diff --git a/data/shaders/computeparticles/particle.comp b/data/shaders/computeparticles/particle.comp index b7dc2f7..9230a17 100644 --- a/data/shaders/computeparticles/particle.comp +++ b/data/shaders/computeparticles/particle.comp @@ -58,6 +58,48 @@ void main() vec2 vPos = particlesA[index].pos.xy; vec2 vVel = particlesA[index].vel.xy; + + + vec2 pvj = vec2(0.0, 0.0); //perceived center of mass v + vec2 pcj = vec2 (0.0, 0.0); //perceived center of mass + vec2 v2 = vec2(0.0, 0.0); + vec2 v3 =vec2 (0.0, 0.0); + + + vec2 pos; + vec2 vel; + float cnt1=0; float cnt2=0; float cnt3=0; + for (int i=0; i< ubo.particleCount; i++){ + if (i!= index) + { + pos = particlesA[i].pos.xy; + vel = particlesA[i].vel.xy; + + float d = distance(pos, vPos); + // Rule 1: boids fly towards their local perceived center of mass, which excludes themselves + if (d < ubo.rule1Distance){ + pcj = pcj + pos; + cnt1 ++; + } + // Rule 2: boids try to stay a distance d away from each other + if (d < ubo.rule2Distance){ + v2 = v2 - (pos-vPos); + } + // Rule 3: boids try to match the speed of surrounding boids + if (d < ubo.rule3Distance ){ + pvj = pvj + vel; + cnt3 ++; + } + } + } + v3=pvj; + vec2 val = vec2(0.0,0.0); + if (cnt1!=0){ + val+=(pcj/cnt1 - vPos) * ubo.rule1Scale; + } + vVel +=v3 * ubo.rule3Scale+v2* ubo.rule2Scale; + + // clamp velocity for a more pleasing simulation. vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1); diff --git a/data/shaders/computeparticles/particle.comp.spv b/data/shaders/computeparticles/particle.comp.spv index 059ab59..0a9d022 100644 Binary files a/data/shaders/computeparticles/particle.comp.spv and b/data/shaders/computeparticles/particle.comp.spv differ diff --git a/img/e.gif b/img/e.gif new file mode 100644 index 0000000..19ebbbf Binary files /dev/null and b/img/e.gif differ diff --git a/vulkanBoids/vulkanBoids.cpp b/vulkanBoids/vulkanBoids.cpp index 9b2f122..54620a8 100644 --- a/vulkanBoids/vulkanBoids.cpp +++ b/vulkanBoids/vulkanBoids.cpp @@ -28,16 +28,16 @@ #define VERTEX_BUFFER_BIND_ID 0 #define ENABLE_VALIDATION true // LOOK: toggle Vulkan validation layers. These make debugging much easier! -#define PARTICLE_COUNT 4 * 1024 // LOOK: change particle count here +#define PARTICLE_COUNT 2 * 1024 // LOOK: change particle count here // LOOK: constants for the boids algorithm. These will be passed to the GPU compute part of the assignment // using a Uniform Buffer. These parameters should yield a stable and pleasing simulation for an // implementation based off the code here: http://studio.sketchpad.cc/sp/pad/view/ro.9cbgCRcgbPOI6/rev.23 -#define RULE1DISTANCE 0.1f // cohesion -#define RULE2DISTANCE 0.05f // separation -#define RULE3DISTANCE 0.05f // alignment -#define RULE1SCALE 0.02f -#define RULE2SCALE 0.05f +#define RULE1DISTANCE 0.025f // cohesion +#define RULE2DISTANCE 0.013f // separation +#define RULE3DISTANCE 0.025f // alignment +#define RULE1SCALE 0.001f +#define RULE2SCALE 0.01f #define RULE3SCALE 0.01f class VulkanExample : public VulkanExampleBase @@ -158,6 +158,7 @@ class VulkanExample : public VulkanExampleBase { particle.pos = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator)); // TODO: add randomized velocities with a slight scale here, something like 0.1f. + particle.vel = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator)); } VkDeviceSize storageBufferSize = particleBuffer.size() * sizeof(Particle); @@ -244,7 +245,7 @@ class VulkanExample : public VulkanExampleBase VERTEX_BUFFER_BIND_ID, 1, VK_FORMAT_R32G32_SFLOAT, - offsetof(Particle, pos)); // TODO: change this so that we can color the particles based on velocity. + offsetof(Particle, vel)); // TODO +: change this so that we can color the particles based on velocity. // vertices.inputState encapsulates everything we need for these particular buffers to // interface with the graphics pipeline. @@ -540,13 +541,36 @@ class VulkanExample : public VulkanExampleBase compute.descriptorSets[0], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, - &compute.uniformBuffer.descriptor) + &compute.uniformBuffer.descriptor), // TODO: write the second descriptorSet, using the top for reference. // We want the descriptorSets to be used for flip-flopping: // on one frame, we use one descriptorSet with the compute pass, // on the next frame, we use the other. // What has to be different about how the second descriptorSet is written here? + + //+ + // Binding 0 : Particle position storage buffer + vkTools::initializers::writeDescriptorSet( + compute.descriptorSets[1], // LOOK: which descriptor set to write to? + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + 0, // LOOK: which binding in the descriptor set Layout? + &compute.storageBufferB.descriptor), // LOOK: which SSBO? + + // Binding 1 : Particle position storage buffer + vkTools::initializers::writeDescriptorSet( + compute.descriptorSets[1], + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + 1, + &compute.storageBufferA.descriptor), + + // Binding 2 : Uniform buffer + vkTools::initializers::writeDescriptorSet( + compute.descriptorSets[1], + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 2, + &compute.uniformBuffer.descriptor) + }; vkUpdateDescriptorSets(device, static_cast(computeWriteDescriptorSets.size()), computeWriteDescriptorSets.data(), 0, NULL); @@ -590,6 +614,9 @@ class VulkanExample : public VulkanExampleBase // We also want to flip what SSBO we draw with in the next // pass through the graphics pipeline. // Feel free to use std::swap here. You should need it twice. + + //+ + std::swap(compute.descriptorSets[0], compute.descriptorSets[1]); } // Record command buffers for drawing using the graphics pipeline @@ -639,7 +666,10 @@ class VulkanExample : public VulkanExampleBase // How does this influence flip-flopping in draw()? // Try drawing with storageBufferA instead of storageBufferB. What happens? Why? VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &compute.storageBufferB.buffer, offsets); + //+ + vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &compute.storageBufferA.buffer, offsets); + + //vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &compute.storageBufferB.buffer, offsets); vkCmdDraw(drawCmdBuffers[i], PARTICLE_COUNT, 1, 0, 0); vkCmdEndRenderPass(drawCmdBuffers[i]);