Visual Update for computeparticles

Instead of using a small amount of large textured particles, use a large
amount of small monochrome particles.
Which uses a new vulkanexamplebase functionality of creating and
updating a only device visible buffer via a temporary staging buffer.
This commit is contained in:
Voultapher 2016-04-21 11:21:48 +02:00
parent eb428db92d
commit 5d7014b221
9 changed files with 203 additions and 209 deletions

View file

@ -283,6 +283,97 @@ VkPipelineShaderStageCreateInfo VulkanExampleBase::loadShader(std::string fileNa
return shaderStage; return shaderStage;
} }
VkBool32 VulkanExampleBase::createDeviceBuffer(
const VkBufferUsageFlags usage,
const VkDeviceSize size,
VkBuffer& buffer,
VkDeviceMemory& memory,
VkDescriptorBufferInfo& descriptor)
{
VkMemoryRequirements memReqs;
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT, size);
VkResult err = vkCreateBuffer(device, &bufferCreateInfo, nullptr, &buffer);
assert(!err);
vkGetBufferMemoryRequirements(device, buffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex);
err = vkAllocateMemory(device, &memAlloc, nullptr, &memory);
assert(!err);
err = vkBindBufferMemory(device, buffer, memory, 0);
assert(!err);
descriptor.offset = 0;
descriptor.buffer = buffer;
descriptor.range = size;
return VK_TRUE;
}
VkBool32 VulkanExampleBase::updateDeviceBuffer(
const VkDeviceSize size,
VkBuffer& deviceBuffer,
void* data)
{
//todo check that size is not larger than memory size
// create staging buffer and copy data to it
VkMemoryRequirements memReqs;
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, size);
VkBuffer stagingBuffer;
VkDeviceMemory stagingMemory;
VkResult err = vkCreateBuffer(device, &bufferCreateInfo, nullptr, &stagingBuffer);
assert(!err);
vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex);
err = vkAllocateMemory(device, &memAlloc, nullptr, &stagingMemory);
assert(!err);
if (data != nullptr)
{
void* mapped;
err = vkMapMemory(device, stagingMemory, 0, size, 0, &mapped);
assert(!err);
memcpy(mapped, data, size);
vkUnmapMemory(device, stagingMemory);
}
err = vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0);
assert(!err);
// create cmdbuffer to copy staging buffer to device local buffer
createSetupCommandBuffer();
VkBufferCopy copyRegion = {};
copyRegion.size = size;
vkCmdCopyBuffer(
setupCmdBuffer,
stagingBuffer,
deviceBuffer,
1,
&copyRegion);
flushSetupCommandBuffer();
// free staging memory
vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingMemory, nullptr);
return VK_TRUE;
}
VkBool32 VulkanExampleBase::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, void * data, VkBuffer * buffer, VkDeviceMemory * memory) VkBool32 VulkanExampleBase::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, void * data, VkBuffer * buffer, VkDeviceMemory * memory)
{ {
VkMemoryRequirements memReqs; VkMemoryRequirements memReqs;

View file

@ -271,6 +271,20 @@ public:
// Load a SPIR-V shader // Load a SPIR-V shader
VkPipelineShaderStageCreateInfo loadShader(std::string fileName, VkShaderStageFlagBits stage); VkPipelineShaderStageCreateInfo loadShader(std::string fileName, VkShaderStageFlagBits stage);
// create device local buffer and use staging to access
VkBool32 createDeviceBuffer(
const VkBufferUsageFlags usage,
const VkDeviceSize size,
VkBuffer& buffer,
VkDeviceMemory& memory,
VkDescriptorBufferInfo& descriptor);
// update loacal buffer memory by creating a host visible staging buffer
VkBool32 updateDeviceBuffer(
const VkDeviceSize size,
VkBuffer& deviceBuffer,
void* data);
// Create a buffer, fill it with data (if != NULL) and bind buffer memory // Create a buffer, fill it with data (if != NULL) and bind buffer memory
VkBool32 createBuffer( VkBool32 createBuffer(
VkBufferUsageFlags usageFlags, VkBufferUsageFlags usageFlags,

View file

@ -11,6 +11,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <vector> #include <vector>
#include <random>
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
@ -22,15 +23,15 @@
#define VERTEX_BUFFER_BIND_ID 0 #define VERTEX_BUFFER_BIND_ID 0
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
#define PARTICLE_COUNT 8 * 1024 #define PARTICLE_COUNT 3000 * 1024
class VulkanExample : public VulkanExampleBase class VulkanExample : public VulkanExampleBase
{ {
private: private:
vkTools::VulkanTexture textureColorMap; vkTools::VulkanTexture textureColorMap;
public: public:
float timer = 0.0f; float timer = 0.f;
float animStart = 50.0f; float animStart = 20.0f;
bool animate = true; bool animate = true;
struct { struct {
@ -68,13 +69,11 @@ public:
} uniformData; } uniformData;
struct Particle { struct Particle {
glm::vec4 pos; glm::vec2 pos;
glm::vec4 col; glm::vec2 vel;
glm::vec4 vel;
}; };
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
VkDescriptorSet descriptorSetPostCompute;
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout;
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
@ -103,17 +102,6 @@ public:
vkDestroyPipelineLayout(device, computePipelineLayout, nullptr); vkDestroyPipelineLayout(device, computePipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, nullptr);
vkDestroyPipeline(device, pipelines.compute, nullptr); vkDestroyPipeline(device, pipelines.compute, nullptr);
textureLoader->destroyTexture(textureColorMap);
}
void loadTextures()
{
textureLoader->loadTexture(
getAssetPath() + "textures/particle01_rgba.ktx",
VK_FORMAT_R8G8B8A8_UNORM,
&textureColorMap,
false);
} }
void buildCommandBuffers() void buildCommandBuffers()
@ -191,7 +179,6 @@ public:
); );
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSetPostCompute, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.postCompute); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.postCompute);
VkDeviceSize offsets[1] = { 0 }; VkDeviceSize offsets[1] = { 0 };
@ -243,9 +230,6 @@ public:
err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete); err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete);
assert(!err); assert(!err);
err = vkQueueWaitIdle(queue);
assert(!err);
// Compute // Compute
VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo(); VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo();
computeSubmitInfo.commandBufferCount = 1; computeSubmitInfo.commandBufferCount = 1;
@ -254,6 +238,9 @@ public:
err = vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE); err = vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE);
assert(!err); assert(!err);
err = vkQueueWaitIdle(queue);
assert(!err);
err = vkQueueWaitIdle(computeQueue); err = vkQueueWaitIdle(computeQueue);
assert(!err); assert(!err);
} }
@ -262,93 +249,25 @@ public:
// vertex positions and velocities // vertex positions and velocities
void prepareStorageBuffers() void prepareStorageBuffers()
{ {
float destPosX = 0.0f;
float destPosY = 0.0f; std::mt19937 rGenerator;
std::uniform_real_distribution<float> rDistribution(-1.f, 1.f);
// Initial particle positions // Initial particle positions
std::vector<Particle> particleBuffer; std::vector<Particle> particleBuffer(PARTICLE_COUNT);
for (int i = 0; i < PARTICLE_COUNT; ++i) for (auto& element : particleBuffer)
{ {
// Position element.pos = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator));
float aspectRatio = (float)height / (float)width; element.vel = glm::vec2(0.f);
float rndVal = (float)rand() / (float)(RAND_MAX / (360.0f * 3.14f * 2.0f));
float rndRad = (float)rand() / (float)(RAND_MAX) * 0.5f;
Particle p;
p.pos = glm::vec4(
destPosX + cos(rndVal) * rndRad * aspectRatio,
destPosY + sin(rndVal) * rndRad,
0.0f,
1.0f);
p.col = glm::vec4(
(float)(rand() % 255) / 255.0f,
(float)(rand() % 255) / 255.0f,
(float)(rand() % 255) / 255.0f,
1.0f);
p.vel = glm::vec4(0.0f);
particleBuffer.push_back(p);
} }
// Buffer size is the same for all storage buffers // Buffer size is the same for all storage buffers
uint32_t storageBufferSize = particleBuffer.size() * sizeof(Particle); uint32_t storageBufferSize = particleBuffer.size() * sizeof(Particle);
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); createDeviceBuffer(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, storageBufferSize, computeStorageBuffer.buffer,
VkMemoryRequirements memReqs; computeStorageBuffer.memory, computeStorageBuffer.descriptor);
VkResult err; updateDeviceBuffer(storageBufferSize, computeStorageBuffer.buffer, particleBuffer.data());
void *data;
struct StagingBuffer {
VkDeviceMemory memory;
VkBuffer buffer;
} stagingBuffer;
// Allocate and fill host-visible staging storage buffer object
// Allocate and fill storage buffer object
VkBufferCreateInfo vBufferInfo =
vkTools::initializers::bufferCreateInfo(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
storageBufferSize);
vkTools::checkResult(vkCreateBuffer(device, &vBufferInfo, nullptr, &stagingBuffer.buffer));
vkGetBufferMemoryRequirements(device, stagingBuffer.buffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex);
vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &stagingBuffer.memory));
vkTools::checkResult(vkMapMemory(device, stagingBuffer.memory, 0, storageBufferSize, 0, &data));
memcpy(data, particleBuffer.data(), storageBufferSize);
vkUnmapMemory(device, stagingBuffer.memory);
vkTools::checkResult(vkBindBufferMemory(device, stagingBuffer.buffer, stagingBuffer.memory, 0));
// Allocate device local storage buffer ojbect
vBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
vkTools::checkResult(vkCreateBuffer(device, &vBufferInfo, nullptr, &computeStorageBuffer.buffer));
vkGetBufferMemoryRequirements(device, computeStorageBuffer.buffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex);
vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &computeStorageBuffer.memory));
vkTools::checkResult(vkBindBufferMemory(device, computeStorageBuffer.buffer, computeStorageBuffer.memory, 0));
// Copy from host to device
createSetupCommandBuffer();
VkBufferCopy copyRegion = {};
copyRegion.size = storageBufferSize;
vkCmdCopyBuffer(
setupCmdBuffer,
stagingBuffer.buffer,
computeStorageBuffer.buffer,
1,
&copyRegion);
flushSetupCommandBuffer();
// Destroy staging buffer
vkDestroyBuffer(device, stagingBuffer.buffer, nullptr);
vkFreeMemory(device, stagingBuffer.memory, nullptr);
computeStorageBuffer.descriptor.buffer = computeStorageBuffer.buffer;
computeStorageBuffer.descriptor.offset = 0;
computeStorageBuffer.descriptor.range = storageBufferSize;
// Binding description // Binding description
vertices.bindingDescriptions.resize(1); vertices.bindingDescriptions.resize(1);
@ -360,7 +279,7 @@ public:
// Attribute descriptions // Attribute descriptions
// Describes memory layout and shader positions // Describes memory layout and shader positions
vertices.attributeDescriptions.resize(2); vertices.attributeDescriptions.resize(1);
// Location 0 : Position // Location 0 : Position
vertices.attributeDescriptions[0] = vertices.attributeDescriptions[0] =
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
@ -368,13 +287,6 @@ public:
0, 0,
VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT,
0); 0);
// Location 1 : Color
vertices.attributeDescriptions[1] =
vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
1,
VK_FORMAT_R32G32B32A32_SFLOAT,
sizeof(float) * 4);
// Assign to vertex buffer // Assign to vertex buffer
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
@ -389,15 +301,14 @@ public:
std::vector<VkDescriptorPoolSize> poolSizes = std::vector<VkDescriptorPoolSize> poolSizes =
{ {
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1), vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1)
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)
}; };
VkDescriptorPoolCreateInfo descriptorPoolInfo = VkDescriptorPoolCreateInfo descriptorPoolInfo =
vkTools::initializers::descriptorPoolCreateInfo( vkTools::initializers::descriptorPoolCreateInfo(
poolSizes.size(), poolSizes.size(),
poolSizes.data(), poolSizes.data(),
3); 2);
VkResult vkRes = vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool); VkResult vkRes = vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool);
assert(!vkRes); assert(!vkRes);
@ -405,63 +316,26 @@ public:
void setupDescriptorSetLayout() void setupDescriptorSetLayout()
{ {
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
{
// Binding 0 : Fragment shader image sampler
vkTools::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
0)
};
VkDescriptorSetLayoutCreateInfo descriptorLayout = VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo;
vkTools::initializers::descriptorSetLayoutCreateInfo( descriptorLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
setLayoutBindings.data(), descriptorLayoutInfo.pNext = NULL;
setLayoutBindings.size()); descriptorLayoutInfo.flags = 0;
descriptorLayoutInfo.bindingCount = 0;
descriptorLayoutInfo.pBindings = nullptr;
VkResult err = vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout); VkResult err = vkCreateDescriptorSetLayout(device, &descriptorLayoutInfo, nullptr, &descriptorSetLayout);
assert(!err); assert(!err);
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
vkTools::initializers::pipelineLayoutCreateInfo( vkTools::initializers::pipelineLayoutCreateInfo(
&descriptorSetLayout, &descriptorSetLayout,
1); 0);
err = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout); err = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout);
assert(!err); assert(!err);
} }
void setupDescriptorSet()
{
VkDescriptorSetAllocateInfo allocInfo =
vkTools::initializers::descriptorSetAllocateInfo(
descriptorPool,
&descriptorSetLayout,
1);
VkResult vkRes = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSetPostCompute);
assert(!vkRes);
// Image descriptor for the color map texture
VkDescriptorImageInfo texDescriptor =
vkTools::initializers::descriptorImageInfo(
textureColorMap.sampler,
textureColorMap.view,
VK_IMAGE_LAYOUT_GENERAL);
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
{
// Binding 1 : Fragment shader image sampler
vkTools::initializers::writeDescriptorSet(
descriptorSetPostCompute,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
0,
&texDescriptor)
};
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
}
// Create a separate command buffer for compute commands // Create a separate command buffer for compute commands
void createComputeCommandBuffer() void createComputeCommandBuffer()
{ {
@ -504,16 +378,16 @@ public:
VkPipelineDepthStencilStateCreateInfo depthStencilState = VkPipelineDepthStencilStateCreateInfo depthStencilState =
vkTools::initializers::pipelineDepthStencilStateCreateInfo( vkTools::initializers::pipelineDepthStencilStateCreateInfo(
VK_TRUE, VK_FALSE,
VK_TRUE, VK_FALSE,
VK_COMPARE_OP_LESS_OR_EQUAL); VK_COMPARE_OP_ALWAYS);
VkPipelineViewportStateCreateInfo viewportState = VkPipelineViewportStateCreateInfo viewportState =
vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0); vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
VkPipelineMultisampleStateCreateInfo multisampleState = VkPipelineMultisampleStateCreateInfo multisampleState =
vkTools::initializers::pipelineMultisampleStateCreateInfo( vkTools::initializers::pipelineMultisampleStateCreateInfo(
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT,
0); 0);
std::vector<VkDynamicState> dynamicStateEnables = { std::vector<VkDynamicState> dynamicStateEnables = {
@ -650,27 +524,34 @@ public:
void prepareUniformBuffers() void prepareUniformBuffers()
{ {
// Compute shader uniform buffer block // Compute shader uniform buffer block
createBuffer( createDeviceBuffer(
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
sizeof(computeUbo), sizeof(computeUbo),
&computeUbo, uniformData.computeShader.ubo.buffer,
&uniformData.computeShader.ubo.buffer, uniformData.computeShader.ubo.memory,
&uniformData.computeShader.ubo.memory, uniformData.computeShader.ubo.descriptor);
&uniformData.computeShader.ubo.descriptor); updateDeviceBuffer(sizeof(computeUbo), uniformData.computeShader.ubo.buffer, &computeUbo);
updateUniformBuffers(); updateUniformBuffers();
} }
void updateUniformBuffers() void updateUniformBuffers()
{ {
computeUbo.deltaT = frameTimer * 5.0f; computeUbo.deltaT = frameTimer * 4.0f;
computeUbo.destX = sin(glm::radians(timer*360.0)) * 0.75f; if (animate) // tmp
computeUbo.destY = 0; {
uint8_t *pData; computeUbo.destX = sin(glm::radians(timer*360.0)) * 0.75f;
VkResult err = vkMapMemory(device, uniformData.computeShader.ubo.memory, 0, sizeof(computeUbo), 0, (void **)&pData); computeUbo.destY = 0.f;
assert(!err); }
memcpy(pData, &computeUbo, sizeof(computeUbo)); else
vkUnmapMemory(device, uniformData.computeShader.ubo.memory); {
float normalizedMx = (mousePos.x - static_cast<float>(width / 2)) / static_cast<float>(width / 2);
float normalizedMy = (mousePos.y - static_cast<float>(height / 2)) / static_cast<float>(height / 2);
computeUbo.destX = normalizedMx;
computeUbo.destY = normalizedMy;
}
updateDeviceBuffer(sizeof(computeUbo), uniformData.computeShader.ubo.buffer, &computeUbo);
} }
// Find and create a compute capable device queue // Find and create a compute capable device queue
@ -693,6 +574,8 @@ public:
assert(queueIndex < queueCount); assert(queueIndex < queueCount);
VkDeviceQueueCreateInfo queueCreateInfo = {}; VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.pNext = NULL;
queueCreateInfo.queueFamilyIndex = queueIndex; queueCreateInfo.queueFamilyIndex = queueIndex;
queueCreateInfo.queueCount = 1; queueCreateInfo.queueCount = 1;
vkGetDeviceQueue(device, queueIndex, 0, &computeQueue); vkGetDeviceQueue(device, queueIndex, 0, &computeQueue);
@ -701,7 +584,6 @@ public:
void prepare() void prepare()
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadTextures();
getComputeQueue(); getComputeQueue();
createComputeCommandBuffer(); createComputeCommandBuffer();
prepareStorageBuffers(); prepareStorageBuffers();
@ -709,7 +591,6 @@ public:
setupDescriptorSetLayout(); setupDescriptorSetLayout();
preparePipelines(); preparePipelines();
setupDescriptorPool(); setupDescriptorPool();
setupDescriptorSet();
prepareCompute(); prepareCompute();
buildCommandBuffers(); buildCommandBuffers();
buildComputeCommandBuffer(); buildComputeCommandBuffer();
@ -723,16 +604,18 @@ public:
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
draw(); draw();
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
if (animStart > 0.0f)
if (animate)
{ {
animStart -= frameTimer * 5.0f; if (animStart > 0.0f)
}
if ((animate) & (animStart <= 0.0f))
{
timer += frameTimer * 0.1f;
if (timer > 1.0)
{ {
timer -= 1.0f; animStart -= frameTimer * 5.0f;
}
else if (animStart <= 0.0f)
{
timer += frameTimer * 0.04f;
if (timer > 1.f)
timer = 0.f;
} }
} }
updateUniformBuffers(); updateUniformBuffers();

View file

@ -5,9 +5,8 @@
struct Particle struct Particle
{ {
vec4 pos; vec2 pos;
vec4 col; vec2 vel;
vec4 vel;
}; };
// Binding 0 : Position storage buffer // Binding 0 : Position storage buffer
@ -26,14 +25,21 @@ layout (binding = 1) uniform UBO
int particleCount; int particleCount;
} ubo; } ubo;
vec3 attraction(vec3 pos, vec3 attractPos) vec2 attraction(vec2 pos, vec2 attractPos)
{ {
vec3 delta = attractPos - pos; vec2 delta = attractPos - pos;
const float damp = 0.5; const float damp = 0.5;
float dDampedDot = dot(delta, delta) + damp; float dDampedDot = dot(delta, delta) + damp;
float invDist = 1.0f / sqrt(dDampedDot); float invDist = 1.0f / sqrt(dDampedDot);
float invDistCubed = invDist*invDist*invDist; float invDistCubed = invDist*invDist*invDist;
return delta * invDistCubed * 0.00035; return delta * invDistCubed * 0.0035;
}
vec2 repulsion(vec2 pos, vec2 attractPos)
{
vec2 delta = attractPos - pos;
float targetDistance = sqrt(dot(delta, delta));
return delta * (1.0 / (targetDistance * targetDistance * targetDistance)) * -0.000035;
} }
void main() void main()
@ -45,22 +51,25 @@ void main()
return; return;
// Read position and velocity // Read position and velocity
vec3 vPos = particles[index].pos.xyz; vec2 vVel = particles[index].vel.xy;
vec3 vVel = particles[index].vel.xyz; vec2 vPos = particles[index].pos.xy;
vec3 destPos = vec3(ubo.destX, ubo.destY, 0.0); vec2 destPos = vec2(ubo.destX, ubo.destY);
// Calculate new velocity depending on attraction point vec2 delta = destPos - vPos;
vVel += attraction(vPos, destPos.xyz); float targetDistance = sqrt(dot(delta, delta));
vVel += repulsion(vPos, destPos.xy) * 0.05;
// Move by velocity // Move by velocity
vPos += vVel * ubo.deltaT; vPos += vVel * ubo.deltaT;
if ((vPos.x < -1.0) || (vPos.x > 1.0)) // collide with boundary
vVel.x -= vVel.x; if ((vPos.x < -1.0) || (vPos.x > 1.0) || (vPos.y < -1.0) || (vPos.y > 1.0))
vVel = (-vVel * 0.1) + attraction(vPos, destPos) * 12;
else
particles[index].pos.xy = vPos;
// Write back // Write back
particles[index].pos.xyz = vPos; particles[index].vel.xy = vVel;
particles[index].vel.xyz = vVel;
} }

View file

@ -3,13 +3,11 @@
#extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable #extension GL_ARB_shading_language_420pack : enable
layout (binding = 0) uniform sampler2D sColorMap;
layout (location = 0) in vec4 inColor; layout (location = 0) in vec4 inColor;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
void main () void main ()
{ {
outFragColor = texture(sColorMap, gl_PointCoord) * inColor; outFragColor = inColor;
} }

View file

@ -4,13 +4,12 @@
#extension GL_ARB_shading_language_420pack : enable #extension GL_ARB_shading_language_420pack : enable
layout (location = 0) in vec4 inPos; layout (location = 0) in vec4 inPos;
layout (location = 1) in vec4 inColor;
layout (location = 0) out vec4 outColor; layout (location = 0) out vec4 outColor;
void main () void main ()
{ {
gl_PointSize = 32.0; gl_PointSize = 1.0;
outColor = inColor; outColor = vec4(0.035);
gl_Position = vec4(inPos.xyz, 1.0); gl_Position = vec4(inPos.xy, 1.0, 1.0);
} }