diff --git a/README.md b/README.md index bec6ca4..f8b09cc 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,32 @@ 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) +* Kaixiang Miao +* Tested on: Windows 7, i7-3630QM @ 2.40GHz 8GB, GTX 660M 2GB (Lenovo Y580 laptop, personal computer) - ### (TODO: Your README) +### ScreenShots + +![](img/72.gif) + + +### Analysis + +* Why do you think Vulkan expects explicit descriptors for things like generating pipelines and commands? + +Vulkan is a explicit low-level graphics API. It uses command buffer pool, which stores the pre-allocated command buffers. Thus, in order to use these buffers correctly, descriptors are needed to be bound to them so that GPU knows which buffer to use and what the memory layout is. + +* Describe a situation besides flip-flop buffers in which you may need multiple descriptor sets to fit one descriptor layout. + +For example, we can use different descriptor sets to describe different texture buffers. Thus we can bind the texture we want into the pipeline. + +* What are some problems to keep in mind when using multiple Vulkan queues? + +When using multiple Vulkan queues, synchronization is important. Race-condition occurs when different queues are requesting the same memory. In this situation, one queue must wait for the other one until it stop occupying the buffers. Programmers has to deal with these issues correctly and it's the thing we should keep in mind. + +* What is one advantage of using compute commands that can share data with a rendering pipeline? + +Save time spent on I/O since you can reuse the data. - Include screenshots, analysis, etc. (Remember, this is public, so don't put - anything here that you don't want to share with the world.) ### Credits diff --git a/data/shaders/computeparticles/generate-spirv.bat b/data/shaders/computeparticles/generate-spirv.bat index be03b7c..aacf7f1 100644 --- a/data/shaders/computeparticles/generate-spirv.bat +++ b/data/shaders/computeparticles/generate-spirv.bat @@ -1,5 +1,6 @@ glslangvalidator -V particle.frag -o particle.frag.spv glslangvalidator -V particle.vert -o particle.vert.spv glslangvalidator -V particle.comp -o particle.comp.spv +pause diff --git a/data/shaders/computeparticles/particle.comp b/data/shaders/computeparticles/particle.comp index b7dc2f7..b520488 100644 --- a/data/shaders/computeparticles/particle.comp +++ b/data/shaders/computeparticles/particle.comp @@ -58,8 +58,58 @@ void main() vec2 vPos = particlesA[index].pos.xy; vec2 vVel = particlesA[index].vel.xy; +vec2 v1 = vec2(0.0, 0.0); +vec2 v2 = vec2(0.0, 0.0); +vec2 v3 = vec2(0.0, 0.0); +int counter1 = 0; +int counter3 = 0; +float test = 0.0; +float ttt; +for (int i = 0; i < ubo.particleCount; i++) +{ + if (i != index) + { + float distance = length(particlesA[i].pos.xy - vPos.xy); + if (distance < ubo.rule1Distance) + { + v1 += particlesA[i].pos.xy; + test += 1.0; + counter1++; + } + + if (distance < ubo.rule2Distance) + { + v2 -= particlesA[i].pos.xy - vPos.xy; + } + + if (distance < ubo.rule3Distance) + { + v3 += particlesA[i].vel.xy; + counter3++; + } + ttt = distance; + } +} +if (counter1 != 0) +{ + v1 /= counter1; + v1 = (v1 - vPos) * ubo.rule1Scale; +} + +v2 *= ubo.rule2Scale; + +if (counter3 != 0) +{ + v3 /= counter3; + v3 = (v3 - vVel) * ubo.rule3Scale; +} + +vVel = v1 + v2 + v3; +//vVel = vec2(test/ 1000.0, 0.0); +//vVel = v3; + // clamp velocity for a more pleasing simulation. - vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1); + vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.5); // kinematic update vPos += vVel * ubo.deltaT; diff --git a/data/shaders/computeparticles/particle.comp.spv b/data/shaders/computeparticles/particle.comp.spv index 059ab59..bef8d74 100644 Binary files a/data/shaders/computeparticles/particle.comp.spv and b/data/shaders/computeparticles/particle.comp.spv differ diff --git a/img/72.gif b/img/72.gif new file mode 100644 index 0000000..b0a3bf9 Binary files /dev/null and b/img/72.gif differ diff --git a/vulkanBoids/vulkanBoids.cpp b/vulkanBoids/vulkanBoids.cpp index 9b2f122..c0c3ee7 100644 --- a/vulkanBoids/vulkanBoids.cpp +++ b/vulkanBoids/vulkanBoids.cpp @@ -36,9 +36,9 @@ #define RULE1DISTANCE 0.1f // cohesion #define RULE2DISTANCE 0.05f // separation #define RULE3DISTANCE 0.05f // alignment -#define RULE1SCALE 0.02f -#define RULE2SCALE 0.05f -#define RULE3SCALE 0.01f +#define RULE1SCALE 2.0f +#define RULE2SCALE 0.1f +#define RULE3SCALE 0.9f class VulkanExample : public VulkanExampleBase { @@ -157,6 +157,7 @@ class VulkanExample : public VulkanExampleBase for (auto& particle : particleBuffer) { particle.pos = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator)); + particle.vel = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator)); // TODO: add randomized velocities with a slight scale here, something like 0.1f. } @@ -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. @@ -254,7 +255,7 @@ class VulkanExample : public VulkanExampleBase vertices.inputState.vertexAttributeDescriptionCount = static_cast(vertices.attributeDescriptions.size()); vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); } - + // Prepare and initialize uniform buffer containing shader uniforms for compute void prepareUniformBuffers() { @@ -517,7 +518,7 @@ class VulkanExample : public VulkanExampleBase { // LOOK // WriteDescriptorSet writes each of these descriptors into the specified descriptorSet. - // THese first few are written into compute.descriptorSet[0]. + // These first few are written into compute.descriptorSet[0]. // Each of these corresponds to a layout binding in the descriptor set layout, // which in turn corresponds with something like `layout(std140, binding = 0)` in `particle.comp`. @@ -540,8 +541,27 @@ class VulkanExample : public VulkanExampleBase compute.descriptorSets[0], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, - &compute.uniformBuffer.descriptor) + &compute.uniformBuffer.descriptor), + + 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) // 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, @@ -590,6 +610,7 @@ 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 +660,7 @@ 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); vkCmdDraw(drawCmdBuffers[i], PARTICLE_COUNT, 1, 0, 0); vkCmdEndRenderPass(drawCmdBuffers[i]);