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:
parent
eb428db92d
commit
5d7014b221
9 changed files with 203 additions and 209 deletions
|
|
@ -283,6 +283,97 @@ VkPipelineShaderStageCreateInfo VulkanExampleBase::loadShader(std::string fileNa
|
|||
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,
|
||||
©Region);
|
||||
|
||||
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)
|
||||
{
|
||||
VkMemoryRequirements memReqs;
|
||||
|
|
|
|||
|
|
@ -271,6 +271,20 @@ public:
|
|||
// Load a SPIR-V shader
|
||||
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
|
||||
VkBool32 createBuffer(
|
||||
VkBufferUsageFlags usageFlags,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
|
|
@ -22,15 +23,15 @@
|
|||
|
||||
#define VERTEX_BUFFER_BIND_ID 0
|
||||
#define ENABLE_VALIDATION false
|
||||
#define PARTICLE_COUNT 8 * 1024
|
||||
#define PARTICLE_COUNT 3000 * 1024
|
||||
|
||||
class VulkanExample : public VulkanExampleBase
|
||||
{
|
||||
private:
|
||||
vkTools::VulkanTexture textureColorMap;
|
||||
public:
|
||||
float timer = 0.0f;
|
||||
float animStart = 50.0f;
|
||||
float timer = 0.f;
|
||||
float animStart = 20.0f;
|
||||
bool animate = true;
|
||||
|
||||
struct {
|
||||
|
|
@ -68,13 +69,11 @@ public:
|
|||
} uniformData;
|
||||
|
||||
struct Particle {
|
||||
glm::vec4 pos;
|
||||
glm::vec4 col;
|
||||
glm::vec4 vel;
|
||||
glm::vec2 pos;
|
||||
glm::vec2 vel;
|
||||
};
|
||||
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkDescriptorSet descriptorSetPostCompute;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
|
||||
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||
|
|
@ -103,17 +102,6 @@ public:
|
|||
vkDestroyPipelineLayout(device, computePipelineLayout, nullptr);
|
||||
vkDestroyDescriptorSetLayout(device, computeDescriptorSetLayout, 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()
|
||||
|
|
@ -191,7 +179,6 @@ public:
|
|||
);
|
||||
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);
|
||||
|
||||
VkDeviceSize offsets[1] = { 0 };
|
||||
|
|
@ -243,9 +230,6 @@ public:
|
|||
err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete);
|
||||
assert(!err);
|
||||
|
||||
err = vkQueueWaitIdle(queue);
|
||||
assert(!err);
|
||||
|
||||
// Compute
|
||||
VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo();
|
||||
computeSubmitInfo.commandBufferCount = 1;
|
||||
|
|
@ -254,6 +238,9 @@ public:
|
|||
err = vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE);
|
||||
assert(!err);
|
||||
|
||||
err = vkQueueWaitIdle(queue);
|
||||
assert(!err);
|
||||
|
||||
err = vkQueueWaitIdle(computeQueue);
|
||||
assert(!err);
|
||||
}
|
||||
|
|
@ -262,93 +249,25 @@ public:
|
|||
// vertex positions and velocities
|
||||
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
|
||||
std::vector<Particle> particleBuffer;
|
||||
for (int i = 0; i < PARTICLE_COUNT; ++i)
|
||||
std::vector<Particle> particleBuffer(PARTICLE_COUNT);
|
||||
for (auto& element : particleBuffer)
|
||||
{
|
||||
// Position
|
||||
float aspectRatio = (float)height / (float)width;
|
||||
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);
|
||||
element.pos = glm::vec2(rDistribution(rGenerator), rDistribution(rGenerator));
|
||||
element.vel = glm::vec2(0.f);
|
||||
}
|
||||
|
||||
// Buffer size is the same for all storage buffers
|
||||
uint32_t storageBufferSize = particleBuffer.size() * sizeof(Particle);
|
||||
|
||||
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
||||
VkMemoryRequirements memReqs;
|
||||
createDeviceBuffer(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, storageBufferSize, computeStorageBuffer.buffer,
|
||||
computeStorageBuffer.memory, computeStorageBuffer.descriptor);
|
||||
|
||||
VkResult err;
|
||||
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,
|
||||
©Region);
|
||||
|
||||
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;
|
||||
updateDeviceBuffer(storageBufferSize, computeStorageBuffer.buffer, particleBuffer.data());
|
||||
|
||||
// Binding description
|
||||
vertices.bindingDescriptions.resize(1);
|
||||
|
|
@ -360,7 +279,7 @@ public:
|
|||
|
||||
// Attribute descriptions
|
||||
// Describes memory layout and shader positions
|
||||
vertices.attributeDescriptions.resize(2);
|
||||
vertices.attributeDescriptions.resize(1);
|
||||
// Location 0 : Position
|
||||
vertices.attributeDescriptions[0] =
|
||||
vkTools::initializers::vertexInputAttributeDescription(
|
||||
|
|
@ -368,13 +287,6 @@ public:
|
|||
0,
|
||||
VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
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
|
||||
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
|
||||
|
|
@ -389,15 +301,14 @@ public:
|
|||
std::vector<VkDescriptorPoolSize> poolSizes =
|
||||
{
|
||||
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
||||
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1),
|
||||
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)
|
||||
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1)
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo descriptorPoolInfo =
|
||||
vkTools::initializers::descriptorPoolCreateInfo(
|
||||
poolSizes.size(),
|
||||
poolSizes.data(),
|
||||
3);
|
||||
2);
|
||||
|
||||
VkResult vkRes = vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool);
|
||||
assert(!vkRes);
|
||||
|
|
@ -405,63 +316,26 @@ public:
|
|||
|
||||
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 =
|
||||
vkTools::initializers::descriptorSetLayoutCreateInfo(
|
||||
setLayoutBindings.data(),
|
||||
setLayoutBindings.size());
|
||||
VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo;
|
||||
descriptorLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
descriptorLayoutInfo.pNext = NULL;
|
||||
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);
|
||||
|
||||
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
|
||||
vkTools::initializers::pipelineLayoutCreateInfo(
|
||||
&descriptorSetLayout,
|
||||
1);
|
||||
0);
|
||||
|
||||
err = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout);
|
||||
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
|
||||
void createComputeCommandBuffer()
|
||||
{
|
||||
|
|
@ -504,16 +378,16 @@ public:
|
|||
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilState =
|
||||
vkTools::initializers::pipelineDepthStencilStateCreateInfo(
|
||||
VK_TRUE,
|
||||
VK_TRUE,
|
||||
VK_COMPARE_OP_LESS_OR_EQUAL);
|
||||
VK_FALSE,
|
||||
VK_FALSE,
|
||||
VK_COMPARE_OP_ALWAYS);
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState =
|
||||
vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampleState =
|
||||
vkTools::initializers::pipelineMultisampleStateCreateInfo(
|
||||
VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_SAMPLE_COUNT_4_BIT,
|
||||
0);
|
||||
|
||||
std::vector<VkDynamicState> dynamicStateEnables = {
|
||||
|
|
@ -650,27 +524,34 @@ public:
|
|||
void prepareUniformBuffers()
|
||||
{
|
||||
// Compute shader uniform buffer block
|
||||
createBuffer(
|
||||
createDeviceBuffer(
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
sizeof(computeUbo),
|
||||
&computeUbo,
|
||||
&uniformData.computeShader.ubo.buffer,
|
||||
&uniformData.computeShader.ubo.memory,
|
||||
&uniformData.computeShader.ubo.descriptor);
|
||||
uniformData.computeShader.ubo.buffer,
|
||||
uniformData.computeShader.ubo.memory,
|
||||
uniformData.computeShader.ubo.descriptor);
|
||||
updateDeviceBuffer(sizeof(computeUbo), uniformData.computeShader.ubo.buffer, &computeUbo);
|
||||
|
||||
updateUniformBuffers();
|
||||
}
|
||||
|
||||
void updateUniformBuffers()
|
||||
{
|
||||
computeUbo.deltaT = frameTimer * 5.0f;
|
||||
computeUbo.deltaT = frameTimer * 4.0f;
|
||||
if (animate) // tmp
|
||||
{
|
||||
computeUbo.destX = sin(glm::radians(timer*360.0)) * 0.75f;
|
||||
computeUbo.destY = 0;
|
||||
uint8_t *pData;
|
||||
VkResult err = vkMapMemory(device, uniformData.computeShader.ubo.memory, 0, sizeof(computeUbo), 0, (void **)&pData);
|
||||
assert(!err);
|
||||
memcpy(pData, &computeUbo, sizeof(computeUbo));
|
||||
vkUnmapMemory(device, uniformData.computeShader.ubo.memory);
|
||||
computeUbo.destY = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
|
|
@ -693,6 +574,8 @@ public:
|
|||
assert(queueIndex < queueCount);
|
||||
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueCreateInfo.pNext = NULL;
|
||||
queueCreateInfo.queueFamilyIndex = queueIndex;
|
||||
queueCreateInfo.queueCount = 1;
|
||||
vkGetDeviceQueue(device, queueIndex, 0, &computeQueue);
|
||||
|
|
@ -701,7 +584,6 @@ public:
|
|||
void prepare()
|
||||
{
|
||||
VulkanExampleBase::prepare();
|
||||
loadTextures();
|
||||
getComputeQueue();
|
||||
createComputeCommandBuffer();
|
||||
prepareStorageBuffers();
|
||||
|
|
@ -709,7 +591,6 @@ public:
|
|||
setupDescriptorSetLayout();
|
||||
preparePipelines();
|
||||
setupDescriptorPool();
|
||||
setupDescriptorSet();
|
||||
prepareCompute();
|
||||
buildCommandBuffers();
|
||||
buildComputeCommandBuffer();
|
||||
|
|
@ -723,16 +604,18 @@ public:
|
|||
vkDeviceWaitIdle(device);
|
||||
draw();
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
if (animate)
|
||||
{
|
||||
if (animStart > 0.0f)
|
||||
{
|
||||
animStart -= frameTimer * 5.0f;
|
||||
}
|
||||
if ((animate) & (animStart <= 0.0f))
|
||||
else if (animStart <= 0.0f)
|
||||
{
|
||||
timer += frameTimer * 0.1f;
|
||||
if (timer > 1.0)
|
||||
{
|
||||
timer -= 1.0f;
|
||||
timer += frameTimer * 0.04f;
|
||||
if (timer > 1.f)
|
||||
timer = 0.f;
|
||||
}
|
||||
}
|
||||
updateUniformBuffers();
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
|
||||
struct Particle
|
||||
{
|
||||
vec4 pos;
|
||||
vec4 col;
|
||||
vec4 vel;
|
||||
vec2 pos;
|
||||
vec2 vel;
|
||||
};
|
||||
|
||||
// Binding 0 : Position storage buffer
|
||||
|
|
@ -26,14 +25,21 @@ layout (binding = 1) uniform UBO
|
|||
int particleCount;
|
||||
} 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;
|
||||
float dDampedDot = dot(delta, delta) + damp;
|
||||
float invDist = 1.0f / sqrt(dDampedDot);
|
||||
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()
|
||||
|
|
@ -45,22 +51,25 @@ void main()
|
|||
return;
|
||||
|
||||
// Read position and velocity
|
||||
vec3 vPos = particles[index].pos.xyz;
|
||||
vec3 vVel = particles[index].vel.xyz;
|
||||
vec2 vVel = particles[index].vel.xy;
|
||||
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
|
||||
vVel += attraction(vPos, destPos.xyz);
|
||||
vec2 delta = destPos - vPos;
|
||||
float targetDistance = sqrt(dot(delta, delta));
|
||||
vVel += repulsion(vPos, destPos.xy) * 0.05;
|
||||
|
||||
// Move by velocity
|
||||
vPos += vVel * ubo.deltaT;
|
||||
|
||||
if ((vPos.x < -1.0) || (vPos.x > 1.0))
|
||||
vVel.x -= vVel.x;
|
||||
// collide with boundary
|
||||
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
|
||||
particles[index].pos.xyz = vPos;
|
||||
particles[index].vel.xyz = vVel;
|
||||
particles[index].vel.xy = vVel;
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -3,13 +3,11 @@
|
|||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
|
||||
layout (binding = 0) uniform sampler2D sColorMap;
|
||||
|
||||
layout (location = 0) in vec4 inColor;
|
||||
|
||||
layout (location = 0) out vec4 outFragColor;
|
||||
|
||||
void main ()
|
||||
{
|
||||
outFragColor = texture(sColorMap, gl_PointCoord) * inColor;
|
||||
outFragColor = inColor;
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -4,13 +4,12 @@
|
|||
#extension GL_ARB_shading_language_420pack : enable
|
||||
|
||||
layout (location = 0) in vec4 inPos;
|
||||
layout (location = 1) in vec4 inColor;
|
||||
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
void main ()
|
||||
{
|
||||
gl_PointSize = 32.0;
|
||||
outColor = inColor;
|
||||
gl_Position = vec4(inPos.xyz, 1.0);
|
||||
gl_PointSize = 1.0;
|
||||
outColor = vec4(0.035);
|
||||
gl_Position = vec4(inPos.xy, 1.0, 1.0);
|
||||
}
|
||||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue