-
Tobias Frisch authored
Signed-off-by:
Tobias Frisch <tfrisch@uni-koblenz.de>
Tobias Frisch authoredSigned-off-by:
Tobias Frisch <tfrisch@uni-koblenz.de>
main.cpp 24.78 KiB
#include <vkcv/Core.hpp>
#include <vkcv/camera/CameraManager.hpp>
#include <vkcv/gui/GUI.hpp>
#include <vkcv/shader/GLSLCompiler.hpp>
#include <random>
struct Particle {
glm::vec3 position;
float size;
glm::vec3 velocity;
float mass;
glm::vec3 pad;
float weight_sum;
glm::mat4 deformation;
glm::mat4 mls;
};
#define SIM_FORM_SPHERE 0
#define SIM_FORM_CUBE 1
#define SIM_TYPE_HYPERELASTIC 0
#define SIM_TYPE_FLUID 1
#define SIM_MODE_RANDOM 0
#define SIM_MODE_ORDERED 1
struct Simulation {
float density;
float size;
float lame1;
float lame2;
int form;
int type;
float K;
float E;
float gamma;
int mode;
float gravity;
int count;
};
struct Physics {
float t;
float dt;
float speedfactor;
};
float sphere_volume(float radius) {
return 4.0f * (radius * radius * radius) * M_PI / 3.0f;
}
float sphere_radius(float volume) {
return std::pow(volume * 3.0f / 4.0f / M_PI, 1.0f / 3.0f);
}
float cube_volume(float radius) {
return 8.0f * (radius * radius * radius);
}
float cube_radius(float volume) {
return std::pow(volume / 8.0f, 1.0f / 3.0f);
}
std::random_device random_dev;
std::uniform_int_distribution<int> dist(0, RAND_MAX);
float randomFloat(float min, float max) {
return min + (max - min) * dist(random_dev) / static_cast<float>(RAND_MAX);
}
float mod(float x, float y) {
return x - std::floor(x / y) * y;
}
void distributeParticlesCube(Particle *particles, size_t count, const glm::vec3& center, float radius,
float mass, const glm::vec3& velocity, bool random) {
const float side = cube_radius(static_cast<float>(count)) * 2.0f;
float volume = 0.0f;
for (size_t i = 0; i < count; i++) {
glm::vec3 offset;
if (random) {
offset.x = randomFloat(-1.0f, +1.0f);
offset.y = randomFloat(-1.0f, +1.0f);
offset.z = randomFloat(-1.0f, +1.0f);
} else {
const float s = static_cast<float>(i) + 0.5f;
offset.x = 2.0f * mod(s, side) / side - 1.0f;
offset.y = 2.0f * mod(s / side, side) / side - 1.0f;
offset.z = 2.0f * mod(s / side / side, side) / side - 1.0f;
}
offset *= radius;
float size = 0.0f;
if (random) {
const float ax = std::abs(offset.x);
const float ay = std::abs(offset.y);
const float az = std::abs(offset.z);
const float a = std::max(std::max(ax, ay), az);
size = (radius - a);
} else {
size = 2.0f * radius / side;
}
particles[i].position = center + offset;
particles[i].size = size;
particles[i].velocity = velocity;
volume += cube_volume(size);
}
for (size_t i = 0; i < count; i++) {
particles[i].mass = (mass * cube_volume(particles[i].size) / volume);
particles[i].deformation = glm::mat4(1.0f);
particles[i].pad = glm::vec3(0.0f);
particles[i].weight_sum = 1.0f;
particles[i].mls = glm::mat4(0.0f);
}
}
void distributeParticlesSphere(Particle *particles, size_t count, const glm::vec3& center, float radius,
float mass, const glm::vec3& velocity, bool random) {
const float side = sphere_radius(static_cast<float>(count)) * 2.0f;
float volume = 0.0f;
for (size_t i = 0; i < count; i++) {
glm::vec3 offset;
if (random) {
offset.x = randomFloat(-1.0f, +1.0f);
offset.y = randomFloat(-1.0f, +1.0f);
offset.z = randomFloat(-1.0f, +1.0f);
if (glm::length(offset) > 0.0f)
offset = glm::normalize(offset);
offset *= randomFloat(0.0f, 1.0f);
} else {
const float range = 0.5f * side;
const float s = static_cast<float>(i) + 0.5f;
float a = mod(s, range) / range;
float b = mod(s / range, M_PI * range);
float c = mod(s / range / M_PI / range, M_PI * range * 2.0f);
offset.x = a * std::sin(c) * std::sin(b);
offset.y = a * std::cos(b);
offset.z = a * std::cos(c) * std::sin(b);
}
offset *= radius;
float size = 0.0f;
if (random) {
size = (radius - glm::length(offset));
} else {
size = 2.0f * radius / side;
}
particles[i].position = center + offset;
particles[i].size = size;
particles[i].velocity = velocity;
volume += sphere_volume(size);
}
// Keep the same densitiy as planned!
mass *= (volume / sphere_volume(radius));
for (size_t i = 0; i < count; i++) {
particles[i].mass = (mass * sphere_volume(particles[i].size) / volume);
particles[i].deformation = glm::mat4(1.0f);
particles[i].pad = glm::vec3(0.0f);
particles[i].weight_sum = 1.0f;
particles[i].mls = glm::mat4(0.0f);
}
}
vkcv::ComputePipelineHandle createComputePipeline(vkcv::Core& core, vkcv::shader::GLSLCompiler& compiler,
const std::string& path,
std::vector<vkcv::DescriptorSetHandle>& descriptorSets) {
vkcv::ShaderProgram shaderProgram;
compiler.compile(
vkcv::ShaderStage::COMPUTE,
path,
[&shaderProgram](vkcv::ShaderStage stage, const std::filesystem::path& path) {
shaderProgram.addShader(stage, path);
}
);
const auto& descriptors = shaderProgram.getReflectedDescriptors();
size_t count = 0;
for (const auto& descriptor : descriptors) {
if (descriptor.first >= count) {
count = (descriptor.first + 1);
}
}
std::vector<vkcv::DescriptorSetLayoutHandle> descriptorSetLayouts;
descriptorSetLayouts.resize(count);
descriptorSets.resize(count);
for (const auto& descriptor : descriptors) {
descriptorSetLayouts[descriptor.first] = core.createDescriptorSetLayout(descriptor.second);
descriptorSets[descriptor.first] = core.createDescriptorSet(descriptorSetLayouts[descriptor.first]);
}
vkcv::ComputePipelineConfig config {
shaderProgram,
descriptorSetLayouts
};
return core.createComputePipeline(config);
}
vkcv::BufferHandle resetParticles(vkcv::Core& core, size_t count, const glm::vec3& velocity,
float density, float size, int form, int mode) {
vkcv::Buffer<Particle> particles = core.createBuffer<Particle>(
vkcv::BufferType::STORAGE,
count
);
std::vector<Particle> particles_vec (particles.getCount());
switch (form) {
case SIM_FORM_SPHERE:
distributeParticlesSphere(
particles_vec.data(),
particles_vec.size(),
glm::vec3(0.5f),
size,
density * sphere_volume(size),
velocity,
(mode == 0)
);
break;
case SIM_FORM_CUBE:
distributeParticlesCube(
particles_vec.data(),
particles_vec.size(),
glm::vec3(0.5f),
size,
density * sphere_volume(size),
velocity,
(mode == 0)
);
break;
default:
break;
}
particles.fill(particles_vec);
return particles.getHandle();
}
int main(int argc, const char **argv) {
const char* applicationName = "Wobble Bobble";
uint32_t windowWidth = 800;
uint32_t windowHeight = 600;
vkcv::Features features;
features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
vkcv::Core core = vkcv::Core::create(
applicationName,
VK_MAKE_VERSION(0, 0, 1),
{vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute},
features
);
vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true);
vkcv::Window& window = core.getWindow(windowHandle);
vkcv::camera::CameraManager cameraManager(window);
vkcv::gui::GUI gui (core, windowHandle);
uint32_t trackballIdx = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
cameraManager.getCamera(trackballIdx).setCenter(glm::vec3(0.5f, 0.5f, 0.5f)); // set camera to look at the center of the particle volume
cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
auto swapchainExtent = core.getSwapchain(windowHandle).getExtent();
vkcv::ImageHandle depthBuffer = core.createImage(
vk::Format::eD32Sfloat,
swapchainExtent.width,
swapchainExtent.height
).getHandle();
vkcv::Image grid = core.createImage(
vk::Format::eR16G16B16A16Sfloat,
32,
32,
32,
false,
true
);
vkcv::SamplerHandle gridSampler = core.createSampler(
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::NEAREST,
vkcv::SamplerAddressMode::CLAMP_TO_BORDER,
0.0f,
vkcv::SamplerBorderColor::FLOAT_ZERO_TRANSPARENT
);
vkcv::Buffer<Simulation> simulation = core.createBuffer<Simulation>(
vkcv::BufferType::UNIFORM, 1, vkcv::BufferMemoryType::HOST_VISIBLE
);
Simulation* sim = simulation.map();
glm::vec3 initialVelocity (0.0f, 0.1f, 0.0f);
sim->density = 2500.0f;
sim->size = 0.1f;
sim->lame1 = 10.0f;
sim->lame2 = 20.0f;
sim->form = SIM_FORM_SPHERE;
sim->type = SIM_TYPE_HYPERELASTIC;
sim->K = 2.2f;
sim->E = 35.0f;
sim->gamma = 1.330f;
sim->mode = SIM_MODE_RANDOM;
sim->gravity = 9.81f;
sim->count = 1024;
vkcv::BufferHandle particlesHandle = resetParticles(
core,
sim->count,
initialVelocity,
sim->density,
sim->size,
sim->form,
sim->mode
);
vkcv::shader::GLSLCompiler compiler;
std::vector<vkcv::DescriptorSetHandle> initParticleWeightsSets;
vkcv::ComputePipelineHandle initParticleWeightsPipeline = createComputePipeline(
core, compiler,
"shaders/init_particle_weights.comp",
initParticleWeightsSets
);
{
vkcv::DescriptorWrites writes;
writes.writeStorageBuffer(0, particlesHandle);
core.writeDescriptorSet(initParticleWeightsSets[0], writes);
}
{
vkcv::DescriptorWrites writes;
writes.writeSampledImage(0, grid.getHandle());
writes.writeSampler(1, gridSampler);
core.writeDescriptorSet(initParticleWeightsSets[1], writes);
}
std::vector<vkcv::DescriptorSetHandle> transformParticlesToGridSets;
vkcv::ComputePipelineHandle transformParticlesToGridPipeline = createComputePipeline(
core, compiler,
"shaders/transform_particles_to_grid.comp",
transformParticlesToGridSets
);
{
vkcv::DescriptorWrites writes;
writes.writeStorageBuffer(0, particlesHandle);
core.writeDescriptorSet(transformParticlesToGridSets[0], writes);
}
{
vkcv::DescriptorWrites writes;
writes.writeUniformBuffer(0, simulation.getHandle());
core.writeDescriptorSet(transformParticlesToGridSets[1], writes);
}
{
vkcv::DescriptorWrites writes;
writes.writeStorageImage(0, grid.getHandle());
core.writeDescriptorSet(transformParticlesToGridSets[2], writes);
}
std::vector<vkcv::DescriptorSetHandle> updateParticleVelocitiesSets;
vkcv::ComputePipelineHandle updateParticleVelocitiesPipeline = createComputePipeline(
core, compiler,
"shaders/update_particle_velocities.comp",
updateParticleVelocitiesSets
);
{
vkcv::DescriptorWrites writes;
writes.writeStorageBuffer(0, particlesHandle);
core.writeDescriptorSet(updateParticleVelocitiesSets[0], writes);
}
{
vkcv::DescriptorWrites writes;
writes.writeUniformBuffer(0, simulation.getHandle());
core.writeDescriptorSet(updateParticleVelocitiesSets[1], writes);
}
{
vkcv::DescriptorWrites writes;
writes.writeSampledImage(0, grid.getHandle());
writes.writeSampler(1, gridSampler);
core.writeDescriptorSet(updateParticleVelocitiesSets[2], writes);
}
vkcv::ShaderProgram gfxProgramGrid;
compiler.compileProgram(gfxProgramGrid, {
{ vkcv::ShaderStage::VERTEX, "shaders/grid.vert" },
{ vkcv::ShaderStage::FRAGMENT, "shaders/grid.frag" }
}, nullptr);
vkcv::ShaderProgram gfxProgramParticles;
compiler.compileProgram(gfxProgramParticles, {
{ vkcv::ShaderStage::VERTEX, "shaders/particle.vert" },
{ vkcv::ShaderStage::FRAGMENT, "shaders/particle.frag" }
}, nullptr);
vkcv::ShaderProgram gfxProgramLines;
compiler.compileProgram(gfxProgramLines, {
{ vkcv::ShaderStage::VERTEX, "shaders/lines.vert" },
{ vkcv::ShaderStage::FRAGMENT, "shaders/lines.frag" }
}, nullptr);
vkcv::PassConfig passConfigGrid {{
vkcv::AttachmentDescription(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
core.getSwapchain(windowHandle).getFormat()
),
vkcv::AttachmentDescription(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
vk::Format::eD32Sfloat
)
}, vkcv::Multisampling::None };
vkcv::PassConfig passConfigParticles {{
vkcv::AttachmentDescription(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
core.getSwapchain(windowHandle).getFormat()
),
vkcv::AttachmentDescription(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
vk::Format::eD32Sfloat
)
}, vkcv::Multisampling::None };
vkcv::PassConfig passConfigLines {{
vkcv::AttachmentDescription(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::LOAD,
core.getSwapchain(windowHandle).getFormat()
),
vkcv::AttachmentDescription(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::LOAD,
vk::Format::eD32Sfloat
)
}, vkcv::Multisampling::None };
vkcv::DescriptorSetLayoutHandle gfxSetLayoutGrid = core.createDescriptorSetLayout(
gfxProgramGrid.getReflectedDescriptors().at(0)
);
vkcv::DescriptorSetHandle gfxSetGrid = core.createDescriptorSet(gfxSetLayoutGrid);
{
vkcv::DescriptorWrites writes;
writes.writeSampledImage(0, grid.getHandle());
writes.writeSampler(1, gridSampler);
writes.writeUniformBuffer(2, simulation.getHandle());
core.writeDescriptorSet(gfxSetGrid, writes);
}
vkcv::DescriptorSetLayoutHandle gfxSetLayoutParticles = core.createDescriptorSetLayout(
gfxProgramParticles.getReflectedDescriptors().at(0)
);
vkcv::DescriptorSetHandle gfxSetParticles = core.createDescriptorSet(gfxSetLayoutParticles);
{
vkcv::DescriptorWrites writes;
writes.writeStorageBuffer(0, particlesHandle);
core.writeDescriptorSet(gfxSetParticles, writes);
}
vkcv::PassHandle gfxPassGrid = core.createPass(passConfigGrid);
vkcv::PassHandle gfxPassParticles = core.createPass(passConfigParticles);
vkcv::PassHandle gfxPassLines = core.createPass(passConfigLines);
vkcv::VertexLayout vertexLayoutGrid ({
vkcv::createVertexBinding(0, gfxProgramGrid.getVertexAttachments())
});
vkcv::GraphicsPipelineConfig gfxPipelineConfigGrid;
gfxPipelineConfigGrid.m_ShaderProgram = gfxProgramGrid;
gfxPipelineConfigGrid.m_Width = windowWidth;
gfxPipelineConfigGrid.m_Height = windowHeight;
gfxPipelineConfigGrid.m_PassHandle = gfxPassGrid;
gfxPipelineConfigGrid.m_VertexLayout = vertexLayoutGrid;
gfxPipelineConfigGrid.m_DescriptorLayouts = { gfxSetLayoutGrid };
gfxPipelineConfigGrid.m_UseDynamicViewport = true;
vkcv::VertexLayout vertexLayoutParticles ({
vkcv::createVertexBinding(0, gfxProgramParticles.getVertexAttachments())
});
vkcv::GraphicsPipelineConfig gfxPipelineConfigParticles;
gfxPipelineConfigParticles.m_ShaderProgram = gfxProgramParticles;
gfxPipelineConfigParticles.m_Width = windowWidth;
gfxPipelineConfigParticles.m_Height = windowHeight;
gfxPipelineConfigParticles.m_PassHandle = gfxPassParticles;
gfxPipelineConfigParticles.m_VertexLayout = vertexLayoutParticles;
gfxPipelineConfigParticles.m_DescriptorLayouts = { gfxSetLayoutParticles };
gfxPipelineConfigParticles.m_UseDynamicViewport = true;
vkcv::VertexLayout vertexLayoutLines ({
vkcv::createVertexBinding(0, gfxProgramLines.getVertexAttachments())
});
vkcv::GraphicsPipelineConfig gfxPipelineConfigLines;
gfxPipelineConfigLines.m_ShaderProgram = gfxProgramLines;
gfxPipelineConfigLines.m_Width = windowWidth;
gfxPipelineConfigLines.m_Height = windowHeight;
gfxPipelineConfigLines.m_PassHandle = gfxPassLines;
gfxPipelineConfigLines.m_VertexLayout = vertexLayoutLines;
gfxPipelineConfigLines.m_DescriptorLayouts = {};
gfxPipelineConfigLines.m_UseDynamicViewport = true;
gfxPipelineConfigLines.m_PrimitiveTopology = vkcv::PrimitiveTopology::LineList;
vkcv::GraphicsPipelineHandle gfxPipelineGrid = core.createGraphicsPipeline(gfxPipelineConfigGrid);
vkcv::GraphicsPipelineHandle gfxPipelineParticles = core.createGraphicsPipeline(gfxPipelineConfigParticles);
vkcv::GraphicsPipelineHandle gfxPipelineLines = core.createGraphicsPipeline(gfxPipelineConfigLines);
vkcv::Buffer<glm::vec2> trianglePositions = core.createBuffer<glm::vec2>(vkcv::BufferType::VERTEX, 3);
trianglePositions.fill({
glm::vec2(-1.0f, -1.0f),
glm::vec2(+0.0f, +1.5f),
glm::vec2(+1.0f, -1.0f)
});
vkcv::Buffer<uint16_t> triangleIndices = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3);
triangleIndices.fill({
0, 1, 2
});
vkcv::Mesh triangleMesh (
{ vkcv::VertexBufferBinding(0, trianglePositions.getVulkanHandle()) },
triangleIndices.getVulkanHandle(),
triangleIndices.getCount()
);
vkcv::Buffer<glm::vec3> linesPositions = core.createBuffer<glm::vec3>(vkcv::BufferType::VERTEX, 8);
linesPositions.fill({
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(1.0f, 1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f),
glm::vec3(1.0f, 0.0f, +1.0f),
glm::vec3(0.0f, 1.0f, 1.0f),
glm::vec3(1.0f, 1.0f, 1.0f)
});
vkcv::Buffer<uint16_t> linesIndices = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 24);
linesIndices.fill({
0, 1,
1, 3,
3, 2,
2, 0,
4, 5,
5, 7,
7, 6,
6, 4,
0, 4,
1, 5,
2, 6,
3, 7
});
vkcv::Mesh linesMesh (
{ vkcv::VertexBufferBinding(0, linesPositions.getVulkanHandle()) },
linesIndices.getVulkanHandle(),
linesIndices.getCount()
);
std::vector<vkcv::DrawcallInfo> drawcallsGrid;
drawcallsGrid.push_back(vkcv::DrawcallInfo(
triangleMesh,
{ vkcv::DescriptorSetUsage(0, gfxSetGrid) },
grid.getWidth() * grid.getHeight() * grid.getDepth()
));
std::vector<vkcv::DrawcallInfo> drawcallsParticles;
drawcallsParticles.push_back(vkcv::DrawcallInfo(
triangleMesh,
{ vkcv::DescriptorSetUsage(0, gfxSetParticles) },
sim->count
));
std::vector<vkcv::DrawcallInfo> drawcallsLines;
drawcallsLines.push_back(vkcv::DrawcallInfo(
linesMesh,
{},
1
));
bool renderGrid = true;
float speed_factor = 1.0f;
auto start = std::chrono::system_clock::now();
auto current = start;
while (vkcv::Window::hasOpenWindow()) {
vkcv::Window::pollEvents();
if (window.getHeight() == 0 || window.getWidth() == 0)
continue;
uint32_t swapchainWidth, swapchainHeight;
if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) {
continue;
}
if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) {
depthBuffer = core.createImage(
vk::Format::eD32Sfloat,
swapchainWidth,
swapchainHeight
).getHandle();
swapchainExtent.width = swapchainWidth;
swapchainExtent.height = swapchainHeight;
}
auto next = std::chrono::system_clock::now();
auto time = std::chrono::duration_cast<std::chrono::microseconds>(next - start);
auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(next - current);
current = next;
Physics physics;
physics.t = static_cast<float>(0.000001 * static_cast<double>(time.count()));
physics.dt = static_cast<float>(0.000001 * static_cast<double>(deltatime.count()));
physics.speedfactor = speed_factor;
vkcv::PushConstants physicsPushConstants(sizeof(physics));
physicsPushConstants.appendDrawcall(physics);
cameraManager.update(physics.dt);
glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
vkcv::PushConstants cameraPushConstants(sizeof(glm::mat4));
cameraPushConstants.appendDrawcall(mvp);
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
const uint32_t dispatchSizeGrid[3] = {grid.getWidth() / 4, grid.getHeight() / 4, grid.getDepth() / 4};
const uint32_t dispatchSizeParticles[3] = {static_cast<uint32_t>(sim->count + 63) / 64, 1, 1};
for (int step = 0; step < 1; step++) {
core.recordBeginDebugLabel(cmdStream, "INIT PARTICLE WEIGHTS", {0.78f, 0.89f, 0.94f, 1.0f});
core.recordBufferMemoryBarrier(cmdStream, particlesHandle);
core.prepareImageForSampling(cmdStream, grid.getHandle());
core.recordComputeDispatchToCmdStream(
cmdStream,
initParticleWeightsPipeline,
dispatchSizeParticles,
{
vkcv::DescriptorSetUsage(
0, initParticleWeightsSets[0]
),
vkcv::DescriptorSetUsage(
1, initParticleWeightsSets[1]
)
},
vkcv::PushConstants(0)
);
core.recordBufferMemoryBarrier(cmdStream, particlesHandle);
core.recordEndDebugLabel(cmdStream);
core.recordBeginDebugLabel(cmdStream, "TRANSFORM PARTICLES TO GRID", {0.47f, 0.77f, 0.85f, 1.0f});
core.recordBufferMemoryBarrier(cmdStream, particlesHandle);
core.prepareImageForStorage(cmdStream, grid.getHandle());
core.recordComputeDispatchToCmdStream(
cmdStream,
transformParticlesToGridPipeline,
dispatchSizeGrid,
{
vkcv::DescriptorSetUsage(
0, transformParticlesToGridSets[0]
),
vkcv::DescriptorSetUsage(
1, transformParticlesToGridSets[1]
),
vkcv::DescriptorSetUsage(
2, transformParticlesToGridSets[2]
)
},
physicsPushConstants
);
core.recordImageMemoryBarrier(cmdStream, grid.getHandle());
core.recordEndDebugLabel(cmdStream);
core.recordBeginDebugLabel(cmdStream, "UPDATE PARTICLE VELOCITIES", {0.78f, 0.89f, 0.94f, 1.0f});
core.recordBufferMemoryBarrier(cmdStream, particlesHandle);
core.recordBufferMemoryBarrier(cmdStream, simulation.getHandle());
core.prepareImageForSampling(cmdStream, grid.getHandle());
core.recordComputeDispatchToCmdStream(
cmdStream,
updateParticleVelocitiesPipeline,
dispatchSizeParticles,
{
vkcv::DescriptorSetUsage(
0, updateParticleVelocitiesSets[0]
),
vkcv::DescriptorSetUsage(
1, updateParticleVelocitiesSets[1]
),
vkcv::DescriptorSetUsage(
2, updateParticleVelocitiesSets[2]
)
},
physicsPushConstants
);
core.recordBufferMemoryBarrier(cmdStream, particlesHandle);
core.recordEndDebugLabel(cmdStream);
}
std::vector<vkcv::ImageHandle> renderTargets {
vkcv::ImageHandle::createSwapchainImageHandle(),
depthBuffer
};
if (renderGrid) {
core.recordBeginDebugLabel(cmdStream, "RENDER GRID", { 0.13f, 0.20f, 0.22f, 1.0f });
core.recordBufferMemoryBarrier(cmdStream, simulation.getHandle());
core.prepareImageForSampling(cmdStream, grid.getHandle());
core.recordDrawcallsToCmdStream(
cmdStream,
gfxPassGrid,
gfxPipelineGrid,
cameraPushConstants,
drawcallsGrid,
renderTargets,
windowHandle
);
core.recordEndDebugLabel(cmdStream);
} else {
core.recordBeginDebugLabel(cmdStream, "RENDER PARTICLES", { 0.13f, 0.20f, 0.22f, 1.0f });
core.recordBufferMemoryBarrier(cmdStream, particlesHandle);
core.recordDrawcallsToCmdStream(
cmdStream,
gfxPassParticles,
gfxPipelineParticles,
cameraPushConstants,
drawcallsParticles,
renderTargets,
windowHandle
);
core.recordEndDebugLabel(cmdStream);
}
core.recordBeginDebugLabel(cmdStream, "RENDER LINES", { 0.13f, 0.20f, 0.22f, 1.0f });
core.recordDrawcallsToCmdStream(
cmdStream,
gfxPassLines,
gfxPipelineLines,
cameraPushConstants,
drawcallsLines,
renderTargets,
windowHandle
);
core.recordEndDebugLabel(cmdStream);
core.prepareSwapchainImageForPresent(cmdStream);
core.submitCommandStream(cmdStream);
gui.beginGUI();
ImGui::Begin("Settings");
ImGui::BeginGroup();
ImGui::Combo("Mode", &(sim->mode), "Random\0Ordered", 2);
ImGui::Combo("Form", &(sim->form), "Sphere\0Cube", 2);
ImGui::Combo("Type", &(sim->type), "Hyperelastic\0Fluid", 2);
ImGui::EndGroup();
ImGui::Spacing();
ImGui::SliderInt("Particle Count", &(sim->count), 1, 100000);
ImGui::SliderFloat("Density", &(sim->density), std::numeric_limits<float>::epsilon(), 5000.0f);
ImGui::SameLine(0.0f, 10.0f);
if (ImGui::SmallButton("Reset##density")) {
sim->density = 2500.0f;
}
ImGui::SliderFloat("Radius", &(sim->size), 0.0f, 0.5f);
ImGui::SameLine(0.0f, 10.0f);
if (ImGui::SmallButton("Reset##radius")) {
sim->size = 0.1f;
}
ImGui::Spacing();
ImGui::BeginGroup();
ImGui::SliderFloat("Bulk Modulus", &(sim->K), 0.0f, 1000.0f);
ImGui::SliderFloat("Young's Modulus", &(sim->E), 0.0f, 1000.0f);
ImGui::SliderFloat("Heat Capacity Ratio", &(sim->gamma), 1.0f, 2.0f);
ImGui::SliderFloat("Lame1", &(sim->lame1), 0.0f, 1000.0f);
ImGui::SliderFloat("Lame2", &(sim->lame2), 0.0f, 1000.0f);
ImGui::EndGroup();
ImGui::Spacing();
ImGui::SliderFloat("Simulation Speed", &speed_factor, 0.0f, 2.0f);
ImGui::Spacing();
ImGui::Checkbox("Render Grid", &renderGrid);
ImGui::DragFloat3("Initial Velocity", reinterpret_cast<float*>(&initialVelocity), 0.001f);
ImGui::SameLine(0.0f, 10.0f);
if (ImGui::Button("Reset##particle_velocity")) {
particlesHandle = resetParticles(
core,
sim->count,
initialVelocity,
sim->density,
sim->size,
sim->form,
sim->mode
);
vkcv::DescriptorWrites writes;
writes.writeStorageBuffer(0, particlesHandle);
core.writeDescriptorSet(initParticleWeightsSets[0], writes);
core.writeDescriptorSet(transformParticlesToGridSets[0], writes);
core.writeDescriptorSet(updateParticleVelocitiesSets[0], writes);
core.writeDescriptorSet(gfxSetParticles, writes);
}
ImGui::SliderFloat("Gravity", &(sim->gravity), 0.0f, 10.0f);
ImGui::End();
gui.endGUI();
core.endFrame(windowHandle);
}
simulation.unmap();
return 0;
}