Vortex2D

2D real-time fluid engine

Introduction

This is a 2D engine with the goal of being used in real-time scenarios, e.g. video games, in the same manner as a Box2D.

It is a hybrid engine that uses particles for the advection part (moving the particles given their velocities) and a grid to resolve the incompressible constrains. However, the particles are not visible to the user and you only work with the grid directly.

The engine runs directly on the GPU using Vulkan compute shaders. The rendering is then also done with Vulkan. The grids are represented by textures and operations by the user are all done by drawing shapes on the textures. The engine itself is written in C++ and it provides a simple wrapper around Vulkan and the basic rendering functionalities: shapes, textures, sprites, blending, render textures, etc.

Table of content

Setup

Vortex2D is multi-platform and currently supports the following:

  • Windows
  • Linux
  • macOS
  • iOS

CMake is used to generate the appropriate build scripts for each platform. The dependencies, which are fetched when calling cmake, are glm and SPIRV-cross. The tests use gtest and the examples use glfw.

The only dependency required is python. There a several variables that can be used to configure:

CMake Builds
VORTEX2D_ENABLE_TESTS builds the tests
VORTEX2D_ENABLE_EXAMPLES builds the examples
VORTEX2D_ENABLE_DOCS builds the documentation

The main library is built as a dll on windows, shared library on linux and (dynamic) framework on macOS/iOS.

Prerequisite

Following are necessary:

  • Python
  • glslangValidator (comes with Vulkan SDK)
Windows

To build on windows, cmake-gui is the easiest to use. Only the variables specified above should be changed.

Linux

Again, regular cmake commands should be use to configure cmake:

cmake ..
macOS

In addition to the normal variables, we need to specify the location of MoltenVK:

cmake .. -DMOLTENVK_DIR=../../MoltenVK/Package/Latest/MoltenVK/ -DVORTEX2D_ENABLE_EXAMPLES=On
iOS

The framework needs to signed on iOS, so the following variables need to be defined:

Variable Value
CODE_SIGN_IDENTITY “iPhone Developer”
DEVELOPMENT_TEAM_ID set to the team id, can be found on the apple developer portal

In addition, the MoltenVK location has to be specified, and the toolchain:

cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/ios.toolchain.cmake -DIOS_PLATFORM=OS -DIOS_ARCH=arm64 -DENABLE_VISIBILITY=true -DMOLTENVK_DIR=../../MoltenVK/Package/Latest/MoltenVK/ -DCODE_SIGN_IDENTITY="iPhone Developer" -DDEVELOPMENT_TEAM_ID=XXXXXX
Documentation

To build the documentation the following is required:

  • doxygen
  • sphinx
  • sphinx_rtd_theme
  • sphinx breathe

Rendering

Initialization

The rendering API is very basic and supports only the most basic functionality.

Create an instance of Vortex2D::Renderer::Instance which is then used to create an instance of Vortex2D::Renderer::Device.

The device is then used to create any other object. The main one is the Vortex2D::Renderer::RenderWindow which is a window where to render sprites and polygons. The function Vortex2D::Fluid::RenderWindow::Display() is then used to present the result to the screen.

Vortex2D::Renderer::Instance instance("Application name", extensions); // pass list of required extensions
Vortex2D::Renderer::Device device(instance.GetPhysicalDevice(), surface);

Vortex2D::Renderer::RenderWindow window(device, surface, width, height);

Note that the instance requires a list of extensions necessary to create a window. With GLFW they can be retrived as:

std::vector<const char*> GetGLFWExtensions()
{
    std::vector<const char*> extensions;
    unsigned int glfwExtensionCount = 0;
    const char** glfwExtensions;

    // get the required extensions from GLFW
    glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
    for (unsigned int i = 0; i < glfwExtensionCount; i++)
    {
        extensions.push_back(glfwExtensions[i]);
    }

    return extensions;
}

In addition, you also need to create a surface which can be also done with the help of GLFW:

vk::UniqueSurfaceKHR GetGLFWSurface(GLFWwindow* window, vk::Instance instance)
{
    // create surface
    VkSurfaceKHR surface;
    if (glfwCreateWindowSurface(static_cast<VkInstance>(instance), window, nullptr, &surface) != VK_SUCCESS)
    {
        throw std::runtime_error("failed to create window surface!");
    }

    return vk::UniqueSurfaceKHR(surface, vk::SurfaceKHRDeleter{instance});
}
Render Targets

To be able to render, we need to record Vortex2D::Renderer::RenderCommand on a Vortex2D::Renderer::RenderTarget. There are two implementations of it:

You can render implementations of the abstract class Vortex2D::Renderer::Drawable, which get recorder in the render command. To actually render it on the render target, the submit function needs to be called. Note, it can be called repeatedly (e.g. over several frames).

In addition, the blend state needs to be passed in, see Vortex2D::Renderer::ColorBlendState.

Shapes

We are now ready to draw things on the screen. Let’s start with some shapes like rectangles and circles:

Vortex2D::Renderer::Rectangle rectangle(device, {100.0f, 100.0f});
Vortex2D::Renderer::Ellipse circle(device, {50.0f, 50.0f});

auto blendMode = vk::PipelineColorBlendAttachmentState()
    .setBlendEnable(true)
    .setAlphaBlendOp(vk::BlendOp::eAdd)
    .setColorBlendOp(vk::BlendOp::eAdd)
    .setSrcColorBlendFactor(vk::BlendFactor::eSrcAlpha)
    .setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
    .setDstColorBlendFactor(vk::BlendFactor::eOneMinusSrcAlpha)
    .setDstAlphaBlendFactor(vk::BlendFactor::eZero);

// note that rectangle, circle and render need to be alive for the duration of the rendering
auto render = renderTarget.Record({rectangle, circle}, blendMode);
render.Submit();
Textures

Of course we can also render textures, using sprites.

Vortex2D::Renderer::Texture texture(device, 100, 100, vk::Format::eR8G8B8A8Unorm);
Vortex2D::Renderer::Sprite sprite(device, texture);
Transformations

The shapes and textures can be positioned, i.e. are transformable. You can set the following properties on them:

  • Position
  • Scale
  • Rotation
  • Anchor

As an example:

Vortex2D::Renderer::Ellipse circle(device, {50.0f, 50.0f});
circle.Colour = {0.0f, 0.0f, 1.0f, 1.0f};
circle.Position = {500.0f, 400.0f};

Level sets

A level set is a signed distance field. It’s a field containing positive or negative value, where the values are 0 represent a contour, or border. This is used to represent shapes, the numbers give you the distance to the shape border. It’s the fundamental way that we represent the area of a fluid and the area of the obstacles, i.e. the boundaries.

The level set is represented simply as a float texture. To set the level set, we simply render on that texture. This means that the class Vortex2D::Fluid::LevelSet inherits Vortex2D::Renderer::RenderTexture.

Basic shapes

There is a list of basic shapes that can be used to render on a level set:

They are used the same way as regular drawable shapes, i.e.

Vortex2D::Fluid::Rectangle rectangle(device, {100.0f, 100.0f});
rectangle.Position = {40.0f, 60.0f};

Vortex2D::Fluid::LevelSet levelSet(device, {400, 400});
auto renderCmd = levelSet.Record({rectangle});
renderCmd.Submit(); // note that renderCmd and rectangle have to be alive untill the rendering is done
Combining shapes

Multiple shapes can be combined together to build the level set. You can either take the union or the intersection when rendering. This happens by using certain blend states which are:

  • Vortex2D::Renderer::IntersectionBlend
  • Vortex2D::Renderer::UnionBlend

After combining several shapes, the resulting float texture is not a signed distance field. It needs to be reinitialised which is simply done by calling Vortex2D::Fluid::LevelSet::Reinitialise().

World

The world classes are the centre of the engine, where the fluid gets animated. They contain essentially three fields:

  • The velocity field
  • The liquid phi field
  • The solid phi field

The first one contain the velocity of the fluid at every point, the second one defines where the fluid is. This is a signed distance field where a negative value indicates this is a fluid location. Finally the last one contains the location of solid obstacles, again as a signed distance field where the negative values indicate the solid’s location.

Each can be visualised as a texture with the getters:

Renderer::RenderTexture& GetVelocity();
DistanceField LiquidDistanceField();
DistanceField SolidDistanceField();

Of course, to get interesting fluid simulations, we need to set values on them. Setting the signed distance fields is straightword (see Level sets):

    Renderer::RenderCommand RecordLiquidPhi(Renderer::RenderTarget::DrawableList drawables);
Renderer::RenderCommand RecordStaticSolidPhi(Renderer::RenderTarget::DrawableList drawables);

Note that this only has to be done once.

For velocities however, the simulation needs to set the velocities at a specific time during the simulation, so instead of ourselves calling Vortex2D::Renderer::RenderCommand::Submit() we pass the Vortex2D::Renderer::RenderCommand() to the World::Fluid::World() class:

    Renderer::RenderCommand RecordVelocity(Renderer::RenderTarget::DrawableList drawables);
void SubmitVelocity(Renderer::RenderCommand& renderCommand);
Smoke World

This is a type of fluid simulation where the fluid area doesn’t move.

Water World

This is a classical water type of fluid simulation.

Rigid body

Rigid bodies are the way to have dynamic interations with the fluid (other then changing the velocity field directly). Vortex2D only provides a way to get current forces applied to the rigidbodies, and applying velocities from the rigidbody to the fluid. Updating the rigidbody’s forces, velocities and position needs to be done by a seperate engine, such as Box2D.

Rigidbodies have three types:

  • Static
  • Weak
  • Strong
Static bodies

Static bodies act on the fluid, but the fluid doesn’t act on the fluid. They have a velocity that is imparted on the fluid. Think of motorized objects pushing through the fluid.

Weak/Strong bodies

Weak rigidbodies are affected by the fluid. They can also in turn, affect the fluid, which is called a strong coupling with the fluid.

Renderer API reference

API Reference
namespace Renderer

Typedefs

using Vortex2D::Renderer::DescriptorTypeBindings = typedef std::map<uint32_t, vk::DescriptorType>
typedef std::vector<glm::vec2> Path

Functions

VORTEX2D_API void Vortex2D::Renderer::BufferBarrier(vk::Buffer buffer, vk::CommandBuffer commandBuffer, vk::AccessFlags oldAccess, vk::AccessFlags newAccess)

Inserts a barrier for the given buffer, command buffer and access.

Parameters
  • buffer: the vulkan buffer handle
  • commandBuffer: the command buffer to inserts the barrier
  • oldAccess: old access
  • newAccess: new access

template <template< typename > class BufferType, typename T>
void CopyTo(BufferType<T> &buffer, T &t)

Copy the content of a buffer in an object.

template <template< typename > class BufferType, typename T>
void CopyTo(BufferType<T> &buffer, std::vector<T> &t)

Copy the content of a buffer to a vector. Vector needs to have the correct size already.

template <template< typename > class BufferType, typename T>
void CopyFrom(BufferType<T> &buffer, const T &t)

Copy the content of an object to the buffer.

template <template< typename > class BufferType, typename T>
void CopyFrom(BufferType<T> &buffer, const std::vector<T> &t)

Copy the content of a vector to the buffer.

void VORTEX2D_API Vortex2D::Renderer::ExecuteCommand(const Device & device, CommandBuffer::CommandFn commandFn)

Runs immediately a set of commands and waits for them to finish.

Parameters
  • device: vulkan device
  • commandFn: lambda that runs the commands.

bool operator==(const ShaderLayout &left, const ShaderLayout &right)
bool operator==(const PipelineLayout &left, const PipelineLayout &right)
vk::DescriptorType GetDescriptorType(uint32_t bind, const PipelineLayout &layout)
VORTEX2D_API void Vortex2D::Renderer::Bind(const Device & device, vk::DescriptorSet dstSet, const PipelineLayout & layout, const std::vector< BindingInput > & bindingInputs)

Bind the resources (buffer or texture/sampler) to a DescriptorSet.

Parameters
  • device: vulkan device
  • dstSet: vulkan descriptor set
  • layout: pipeline layout
  • bindingInputs: list of resources (buffer or texture/sampler)

bool HasLayer(const char *extension, const std::vector<vk::LayerProperties> &availableExtensions)
bool HasExtension(const char *extension, const std::vector<vk::ExtensionProperties> &availableExtensions)
VORTEX2D_API vk::UniquePipeline Vortex2D::Renderer::MakeComputePipeline(vk::Device device, vk::ShaderModule shader, vk::PipelineLayout layout, SpecConstInfo specConstInfo = {})

Create a compute pipeline.

Return
compute pipeline
Parameters
  • device: vulkan device
  • shader: shader module
  • layout: layout of shader
  • specConstInfo: any specialisation constants

template <typename Type>
SpecConstInfo::Value<Type> SpecConstValue(uint32_t id, Type &&value)

Constructs a specialization constant value.

template <typename... Args>
SpecConstInfo SpecConst(Args&&... args)

Constructs a SpecConstInfo with given values of specialisation constants.

bool operator==(const RenderState &left, const RenderState right)
VORTEX2D_API ComputeSize Vortex2D::Renderer::MakeStencilComputeSize(const glm::ivec2 & size, int radius)

Create a ComputeSize for a stencil type shader.

Return
calculate ComputeSize
Parameters
  • size: the domain size
  • radius: the stencil size

VORTEX2D_API ComputeSize Vortex2D::Renderer::MakeCheckerboardComputeSize(const glm::ivec2 & size)

Create a ComputeSize for a checkerboard type shader.

Return
calculate ComputeSize
Parameters
  • size: the domain size

class AbstractShape : public Vortex2D::Renderer::Drawable, public Vortex2D::Renderer::Transformable
#include <Shapes.h>

An polygonal shape where the fragment shader can be specified for customisation.

Subclassed by Vortex2D::Renderer::IntRectangle, Vortex2D::Renderer::Rectangle

Public Functions

AbstractShape(const Device &device, const SpirvBinary &fragShader, const std::vector<glm::vec2> &vertices)
AbstractShape(AbstractShape &&other)
virtual VORTEX2D_API ~AbstractShape()
void Initialize(const RenderState &renderState)

Initialize the drawable for a particular state. This might include creating the correct pipeline. If it was already initialized, it will do nothing.

Parameters
  • renderState: the state to initialize with.

void Update(const glm::mat4 &projection, const glm::mat4 &view)

Update the MVP matrix of the drawable.

Parameters
  • projection: the projection matrix
  • view: the view matrix

void Draw(vk::CommandBuffer commandBuffer, const RenderState &renderState)

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

Public Members

glm::vec4 Colour
class AbstractSprite : public Vortex2D::Renderer::Drawable, public Vortex2D::Renderer::Transformable
#include <Sprite.h>

a Sprite, i.e. a drawable that can render a texture. The fragment shader can be specified for customisation.

Subclassed by Vortex2D::Fluid::DistanceField, Vortex2D::Renderer::Sprite

Public Functions

AbstractSprite(const Device &device, const SpirvBinary &fragShaderName, Texture &texture)
AbstractSprite(AbstractSprite &&other)
virtual VORTEX2D_API ~AbstractSprite()
void Initialize(const RenderState &renderState)

Initialize the drawable for a particular state. This might include creating the correct pipeline. If it was already initialized, it will do nothing.

Parameters
  • renderState: the state to initialize with.

void Update(const glm::mat4 &projection, const glm::mat4 &view)

Update the MVP matrix of the drawable.

Parameters
  • projection: the projection matrix
  • view: the view matrix

void Draw(vk::CommandBuffer commandBuffer, const RenderState &renderState)

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

template <typename T>
void PushConstant(vk::CommandBuffer commandBuffer, uint32_t offset, const T &data)

Public Members

glm::vec4 Colour = {1.0f, 1.0f, 1.0f, 1.0f}
struct BindingInput
#include <DescriptorSet.h>

The texture/sampler or buffer that can be binded to a shader.

Public Functions

BindingInput(Renderer::GenericBuffer &buffer, uint32_t bind = DefaultBind)
BindingInput(Renderer::Texture &texture, uint32_t bind = DefaultBind)
BindingInput(vk::Sampler sampler, Renderer::Texture &texture, uint32_t bind = DefaultBind)

Public Members

uint32_t Bind
mapbox::util::variant<Renderer::GenericBuffer *, DescriptorImage> Input

Public Static Attributes

constexpr uint32_t DefaultBind = static_cast<uint32_t>(-1)
template <typename T>
class Buffer : public Vortex2D::Renderer::GenericBuffer
#include <Buffer.h>

a storage buffer type of buffer

Public Functions

Buffer(const Device &device, std::size_t size = 1, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY)
class Clear : public Vortex2D::Renderer::Drawable
#include <Shapes.h>

A drawable that simply clears the target.

Public Functions

Clear(const glm::vec4 &colour)
void Initialize(const RenderState &renderState)

Initialize the drawable for a particular state. This might include creating the correct pipeline. If it was already initialized, it will do nothing.

Parameters
  • renderState: the state to initialize with.

void Update(const glm::mat4 &projection, const glm::mat4 &view)

Update the MVP matrix of the drawable.

Parameters
  • projection: the projection matrix
  • view: the view matrix

void Draw(vk::CommandBuffer commandBuffer, const RenderState &renderState)

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

struct ColorBlendState
#include <RenderState.h>

The blend state and blend constant.

Public Functions

ColorBlendState()

Public Members

vk::PipelineColorBlendAttachmentState ColorBlend
std::array<float, 4> BlendConstants
class CommandBuffer
#include <CommandBuffer.h>

Can record commands, then submit them (multiple times). A fence can used to wait on the completion of the commands.

Public Types

using CommandFn = std::function<void(vk::CommandBuffer)>

Public Functions

CommandBuffer(const Device &device, bool synchronise = true)

Creates a command buffer which can be synchronized.

Parameters
  • device: vulkan device
  • synchronise: flag to determine if the command buffer can be waited on.

~CommandBuffer()
CommandBuffer(CommandBuffer &&other)
CommandBuffer &operator=(CommandBuffer &&other)
void Record(CommandFn commandFn)

Record some commands. The commads are recorded in the lambda which is immediately executed.

Parameters
  • commandFn: a functor, or simply a lambda, where commands are recorded.

void Record(const RenderTarget &renderTarget, vk::Framebuffer framebuffer, CommandFn commandFn)

Record some commands inside a render pass. The commads are recorded in the lambda which is immediately executed.

Parameters
  • renderTarget: the render target which contains the render pass to record into
  • framebuffer: the frame buffer where the render pass will render.
  • commandFn: a functor, or simply a lambda, where commands are recorded.

void Wait()

Wait for the command submit to finish. Does nothing if the synchronise flag was false.

void Reset()

Reset the command buffer so it can be recorded again.

void Submit(const std::initializer_list<vk::Semaphore> &waitSemaphores = {}, const std::initializer_list<vk::Semaphore> &signalSemaphores = {})

submit the command buffer

operator bool() const

explicit conversion operator to bool, indicates if the command was properly recorded and can be sumitted.

struct ComputeSize
#include <Work.h>

Used for a compute shader, and defines the group size, local size and domain size.

Public Functions

ComputeSize(const glm::ivec2 &size, const glm::ivec2 &localSize = GetLocalSize2D())

Creates a ComputeSize using a 2D domain size and the default 2D local size.

Parameters
  • size: the domain size
  • localSize: the local size of the shader

ComputeSize(int size, int localSize = GetLocalSize1D())

Creates a ComputeSize using a 1D domain size and the default 1D local size.

Parameters
  • size: the domain size
  • localSize: the local size of the shader

Public Members

glm::ivec2 DomainSize
glm::ivec2 WorkSize
glm::ivec2 LocalSize

Public Static Functions

glm::ivec2 GetLocalSize2D()

The default local size for 2D compute shaders.

Return
a 2d vector

int GetLocalSize1D()

The default local size for 1D compute shaders.

Return
a integer value

glm::ivec2 GetWorkSize(const glm::ivec2 &size, const glm::ivec2 &localSize = GetLocalSize2D())

Computes the 2D group size given a domain size.

Return
the group size
Parameters
  • size: the domain size of the shader
  • localSize: the local size of the shader

glm::ivec2 GetWorkSize(int size, int localSize = GetLocalSize1D())

Computes the 1D group size given a domain size.

Return
the group size
Parameters
  • size: the domain size of the shader
  • localSize: the local size of the shader

ComputeSize Default2D()

A default ComputeSize using the default 2D local size. The domain size is (1,1)

Return
a default compute size

ComputeSize Default1D()

A default ComputeSize using the default 1D local size. The domain size is (1,1)

Return
a default compute size

struct DescriptorImage
#include <DescriptorSet.h>

The texture or sampler that can be binded to a shader.

Public Functions

DescriptorImage(vk::Sampler sampler, Renderer::Texture &texture)
DescriptorImage(Renderer::Texture &texture)

Public Members

vk::Sampler Sampler
Renderer::Texture *Texture
struct DescriptorSet
#include <DescriptorSet.h>

The binding of an object for a shader.

Public Members

vk::UniqueDescriptorSet descriptorSet
vk::PipelineLayout pipelineLayout
vk::DescriptorSetLayout descriptorSetLayout
class Device
#include <Device.h>

Encapsulation around the vulkan device. Allows to create command buffers, layout, bindings, memory and shaders.

Public Functions

Device(vk::PhysicalDevice physicalDevice, bool validation = true)
Device(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, bool validation = true)
Device(vk::PhysicalDevice physicalDevice, int familyIndex, bool validation = true)
~Device()
Device(Device&&)
Device &operator=(Device&&)
vk::Device Handle() const
vk::Queue Queue() const
vk::PhysicalDevice GetPhysicalDevice() const
int GetFamilyIndex() const
std::vector<vk::CommandBuffer> CreateCommandBuffers(uint32_t size) const
void FreeCommandBuffers(vk::ArrayProxy<const vk::CommandBuffer> commandBuffers) const
VmaAllocator Allocator() const
LayoutManager &GetLayoutManager() const
vk::ShaderModule GetShaderModule(const SpirvBinary &spirv) const
struct DispatchParams
#include <Work.h>

Parameters for indirect compute: group size, local size, etc.

Public Functions

DispatchParams(int count)

Public Members

vk::DispatchIndirectCommand workSize
uint32_t count
struct Drawable
#include <Drawable.h>

Interface of a drawable object.

Subclassed by Vortex2D::Fluid::Circle, Vortex2D::Fluid::Polygon, Vortex2D::Renderer::AbstractShape, Vortex2D::Renderer::AbstractSprite, Vortex2D::Renderer::Clear, Vortex2D::Renderer::Ellipse

Public Functions

virtual ~Drawable()
virtual void Initialize(const RenderState &renderState) = 0

Initialize the drawable for a particular state. This might include creating the correct pipeline. If it was already initialized, it will do nothing.

Parameters
  • renderState: the state to initialize with.

virtual void Update(const glm::mat4 &projection, const glm::mat4 &view) = 0

Update the MVP matrix of the drawable.

Parameters
  • projection: the projection matrix
  • view: the view matrix

virtual void Draw(vk::CommandBuffer commandBuffer, const RenderState &renderState) = 0

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

class Ellipse : public Vortex2D::Renderer::Drawable, public Vortex2D::Renderer::Transformable
#include <Shapes.h>

A solid colour ellipse. Implements the Drawable interface and Transformable interface.

Public Functions

Ellipse(const Device &device, const glm::vec2 &radius)
void Initialize(const RenderState &renderState)

Initialize the drawable for a particular state. This might include creating the correct pipeline. If it was already initialized, it will do nothing.

Parameters
  • renderState: the state to initialize with.

void Update(const glm::mat4 &projection, const glm::mat4 &view)

Update the MVP matrix of the drawable.

Parameters
  • projection: the projection matrix
  • view: the view matrix

void Draw(vk::CommandBuffer commandBuffer, const RenderState &renderState)

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

Public Members

glm::vec4 Colour
class GenericBuffer
#include <Buffer.h>

A vulkan buffer which can be on the host or the device.

Subclassed by Vortex2D::Renderer::Buffer< float >, Vortex2D::Renderer::Buffer< glm::ivec2 >, Vortex2D::Renderer::Buffer< glm::vec2 >, Vortex2D::Renderer::Buffer< int >, Vortex2D::Renderer::Buffer< Vortex2D::Fluid::Particle >, Vortex2D::Renderer::Buffer< Vortex2D::Fluid::RigidBody::Velocity >, Vortex2D::Renderer::Buffer< Vortex2D::Renderer::DispatchParams >, Vortex2D::Renderer::IndirectBuffer< Vortex2D::Renderer::DispatchParams >, Vortex2D::Renderer::UniformBuffer< glm::mat4 >, Vortex2D::Renderer::UniformBuffer< glm::vec2 >, Vortex2D::Renderer::UniformBuffer< glm::vec4 >, Vortex2D::Renderer::UniformBuffer< Size >, Vortex2D::Renderer::UniformBuffer< Vortex2D::Fluid::RigidBody::Velocity >, Vortex2D::Renderer::VertexBuffer< glm::vec2 >, Vortex2D::Renderer::VertexBuffer< Vortex2D::Renderer::AbstractSprite::Vertex >, Vortex2D::Renderer::Buffer< T >, Vortex2D::Renderer::IndirectBuffer< T >, Vortex2D::Renderer::UniformBuffer< T >, Vortex2D::Renderer::VertexBuffer< T >

Public Functions

GenericBuffer(const Device &device, vk::BufferUsageFlags usageFlags, VmaMemoryUsage memoryUsage, vk::DeviceSize deviceSize)
~GenericBuffer()
GenericBuffer(GenericBuffer &&other)
void CopyFrom(vk::CommandBuffer commandBuffer, GenericBuffer &srcBuffer)

Copy a buffer to this buffer.

Parameters
  • commandBuffer: command buffer to run the copy on.
  • srcBuffer: the source buffer.

void CopyFrom(vk::CommandBuffer commandBuffer, Texture &srcTexture)

Copy a texture to this buffer.

Parameters
  • commandBuffer: command buffer to run the copy on.
  • srcTexture: the source texture

vk::Buffer Handle() const

The vulkan handle.

vk::DeviceSize Size() const

The size in bytes of the buffer.

void Barrier(vk::CommandBuffer commandBuffer, vk::AccessFlags oldAccess, vk::AccessFlags newAccess)

Inserts a barrier for this buffer.

Parameters
  • commandBuffer: the command buffer to run the barrier
  • oldAccess: old access
  • newAccess: new access

void Clear(vk::CommandBuffer commandBuffer)

Clear the buffer with 0.

Parameters
  • commandBuffer: the command buffer to clear on

Friends

template <template< typename > class BufferType, typename T>
void CopyFrom(BufferType<T> &buffer, const T &t)

Copy the content of an object to the buffer.

template <template< typename > class BufferType, typename T>
void CopyTo(BufferType<T> &buffer, T &t)

Copy the content of a buffer in an object.

template <template< typename > class BufferType, typename T>
void CopyTo(BufferType<T> &buffer, std::vector<T> &t)

Copy the content of a buffer to a vector. Vector needs to have the correct size already.

template <template< typename > class BufferType, typename T>
void CopyFrom(BufferType<T> &buffer, const std::vector<T> &t)

Copy the content of a vector to the buffer.

class GraphicsPipeline
#include <Pipeline.h>

graphics pipeline which caches the pipeline per render states.

Public Functions

GraphicsPipeline()
GraphicsPipeline(Builder builder)
void Create(vk::Device device, const RenderState &renderState)
void Bind(vk::CommandBuffer commandBuffer, const RenderState &renderState)
class Builder
#include <Pipeline.h>

Builder for graphics pipeline.

Public Functions

Builder()
GraphicsPipeline::Builder &Shader(vk::ShaderModule shader, vk::ShaderStageFlagBits shaderStage)

Set the shader.

Return
*this
Parameters
  • shader: the loaded shader
  • shaderStage: shader state (vertex, fragment or compute)

GraphicsPipeline::Builder &VertexAttribute(uint32_t location, uint32_t binding, vk::Format format, uint32_t offset)

Sets the vertex attributes.

Return
*this
Parameters
  • location: location in the shader
  • binding: binding in the shader
  • format: vertex format
  • offset: offset in the vertex

GraphicsPipeline::Builder &VertexBinding(uint32_t binding, uint32_t stride, vk::VertexInputRate inputRate = vk::VertexInputRate::eVertex)

Sets the vertex binding.

Return
*this
Parameters
  • binding: binding in the shader
  • stride: stride in bytes
  • inputRate: inpute rate

GraphicsPipeline::Builder &Topology(vk::PrimitiveTopology topology)
GraphicsPipeline::Builder &Layout(vk::PipelineLayout pipelineLayout)
vk::UniquePipeline Create(vk::Device device, const RenderState &renderState)
template <typename T>
class IndirectBuffer : public Vortex2D::Renderer::GenericBuffer
#include <Buffer.h>

an indirect buffer type of buffer, used for compute indirect dispatch

Public Functions

IndirectBuffer(const Device &device, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY)
class Instance
#include <Instance.h>

Vulkan instance, which extensions enabled.

Public Functions

Instance(const std::string &name, std::vector<const char *> extensions, bool validation)
~Instance()
vk::PhysicalDevice GetPhysicalDevice() const
vk::Instance GetInstance() const
class IntRectangle : public Vortex2D::Renderer::AbstractShape
#include <Shapes.h>

A solid colour rectangle as Rectangle, however uses integer colors and is meant to be drawn to a framebuffer wiht integer colours.

Public Functions

IntRectangle(const Device &device, const glm::vec2 &size)
class LayoutManager
#include <DescriptorSet.h>

Caches and creates layouts and bindings.

Public Functions

LayoutManager(const Device &device)
void CreateDescriptorPool()

Create or re-create the descriptor pool, will render invalid existing descriptor sets.

DescriptorSet MakeDescriptorSet(const PipelineLayout &layout)

Create the descriptor set given the layout.

Return
built descriptor set
Parameters
  • layout: pipeline/shader layout

vk::DescriptorSetLayout GetDescriptorSetLayout(const PipelineLayout &layout)

Create, cache and return a descriptor layout given the pipeline layout.

Return
cached descriptor set layout
Parameters
  • layout: pipeline layout

vk::PipelineLayout GetPipelineLayout(const PipelineLayout &layout)

create, cache and return a vulkan pipeline layout given the layout

Return
vulkan pipeline layout
Parameters
  • layout: pipeline layout

struct PipelineLayout
#include <DescriptorSet.h>

Represents the layout of a pipeline: vertex + fragment or compute.

Public Members

std::vector<ShaderLayout> layouts
template <typename T>
class property
#include <Transformable.h>

Simple class to simulate properties like in C#.

Public Functions

property(Transformable &t)
T &operator=(const T &i)
operator T const&() const
class Rectangle : public Vortex2D::Renderer::AbstractShape
#include <Shapes.h>

A solid colour rectangle defined by two triangles. Implements the Drawable interface and Transformable interface.

Public Functions

Rectangle(const Device &device, const glm::vec2 &size)
class RenderCommand
#include <CommandBuffer.h>

A special command buffer that has been recorded by a RenderTarget. It can be used to submit the rendering. The object has to stay alive untill rendering is complete.

Public Functions

RenderCommand()
~RenderCommand()
RenderCommand(RenderCommand &&other)
RenderCommand &operator=(RenderCommand &&other)
RenderCommand &Submit(const glm::mat4 &view = glm::mat4(1.0f))

Submit the render command with a transform matrix.

Return
*this
Parameters
  • view: a transform matrix

void Wait()

Wait for the render command to complete.

Friends

friend Vortex2D::Renderer::RenderTexture
friend Vortex2D::Renderer::RenderWindow
class RenderpassBuilder
#include <RenderTarget.h>

Factory for a vulkan render pass.

Public Functions

RenderpassBuilder &Attachement(vk::Format format)

Format of the render pass.

Return
Parameters
  • format:

RenderpassBuilder &AttachementLoadOp(vk::AttachmentLoadOp value)

operation to perform when loading the framebuffer (clear, load, etc)

Return
Parameters
  • value:

RenderpassBuilder &AttachementStoreOp(vk::AttachmentStoreOp value)

operation to perform when storing the framebuffer (clear, save, etc)

Return
Parameters
  • value:

RenderpassBuilder &AttachementInitialLayout(vk::ImageLayout layout)

Layout of the image to be before render pass.

Return
Parameters
  • layout:

RenderpassBuilder &AttachementFinalLayout(vk::ImageLayout layout)

Layout of the image to be after render pass.

Return
Parameters
  • layout:

RenderpassBuilder &Subpass(vk::PipelineBindPoint bindPoint)

Define subpass of the render pass.

Return
Parameters
  • bindPoint:

RenderpassBuilder &SubpassColorAttachment(vk::ImageLayout layout, uint32_t attachment)

Set the color attachment with index.

Return
Parameters
  • layout:
  • attachment: index of the attachment

RenderpassBuilder &Dependency(uint32_t srcSubpass, uint32_t dstSubpass)

Dependency of the subpasses.

Return
Parameters
  • srcSubpass:
  • dstSubpass:

RenderpassBuilder &DependencySrcStageMask(vk::PipelineStageFlags value)
RenderpassBuilder &DependencyDstStageMask(vk::PipelineStageFlags value)
RenderpassBuilder &DependencySrcAccessMask(vk::AccessFlags value)
RenderpassBuilder &DependencyDstAccessMask(vk::AccessFlags value)
vk::UniqueRenderPass Create(vk::Device device)

Create the render pass.

Return
Parameters
  • device:

struct RenderState
#include <RenderState.h>

the various state to render to a target: size, render pass and blend.

Public Functions

RenderState(const RenderTarget &renderTarget)

Initialize for a render target with default blend.

Parameters
  • renderTarget:

RenderState(const RenderTarget &renderTarget, ColorBlendState blendState)

Initialize for a render target with a given blend.

Parameters
  • renderTarget:
  • colorBlend:

Public Members

uint32_t Width
uint32_t Height
vk::RenderPass RenderPass
ColorBlendState BlendState
struct RenderTarget
#include <RenderTarget.h>

A target that can be rendered to. This is implemented by the RenderWindow and the RenderTexture.

Subclassed by Vortex2D::Renderer::RenderTexture, Vortex2D::Renderer::RenderWindow

Public Types

using DrawableList = std::initializer_list<std::reference_wrapper<Drawable>>

Public Functions

RenderTarget(uint32_t width, uint32_t height)
RenderTarget(RenderTarget &&other)
~RenderTarget()
virtual VORTEX2D_API RenderCommand Vortex2D::Renderer::RenderTarget::Record(DrawableList drawables, ColorBlendState blendState = {}) = 0
virtual VORTEX2D_API void Vortex2D::Renderer::RenderTarget::Submit(RenderCommand & renderCommand) = 0

Public Members

uint32_t Width
uint32_t Height
glm::mat4 Orth
glm::mat4 View
vk::UniqueRenderPass RenderPass
class RenderTexture : public Vortex2D::Renderer::RenderTarget, public Vortex2D::Renderer::Texture
#include <RenderTexture.h>

A render target that renders into a texture.

Subclassed by Vortex2D::Fluid::Density, Vortex2D::Fluid::LevelSet, Vortex2D::Fluid::ParticleCount, Vortex2D::Fluid::Velocity

Public Functions

RenderTexture(const Device &device, uint32_t width, uint32_t height, vk::Format format)
RenderCommand Record(DrawableList drawables, ColorBlendState blendState = {})
void Submit(RenderCommand &renderCommand)
class RenderWindow : public Vortex2D::Renderer::RenderTarget
#include <RenderWindow.h>

Render to a swapchain, i.e. to the window/surface.

Public Functions

RenderWindow(const Device &device, vk::SurfaceKHR surface, uint32_t width, uint32_t height)

Initialize with a given surface and size.

Parameters
  • device: vulkan device
  • surface: vulkan surface
  • width:
  • height:

RenderCommand Record(DrawableList drawables, ColorBlendState blendState = {})
void Submit(RenderCommand &renderCommand)
void Display()

Submits all the render command and present the surface for display.

class SamplerBuilder
#include <Texture.h>

Factory for a vullkan sampler.

Public Functions

SamplerBuilder()
SamplerBuilder &AddressMode(vk::SamplerAddressMode mode)

Mode of the sampler: repeat, clamp, etc.

Return
*this
Parameters
  • mode: vulkan mode

SamplerBuilder &Filter(vk::Filter filter)

Filter of the sampler: linear, nearest, etc.

Return
*this
Parameters
  • filter: vulkan filter

vk::UniqueSampler Create(vk::Device device)

Create the vulkan sampler.

Return
unique sampler
Parameters
  • device: vulkan device

struct ShaderLayout
#include <DescriptorSet.h>

Represents the layout of a shader (vertex, fragment or compute)

Public Functions

ShaderLayout(const SPIRV::Reflection &reflection)

Public Members

vk::ShaderStageFlags shaderStage
DescriptorTypeBindings bindings
unsigned pushConstantSize
struct SpecConstInfo
#include <Pipeline.h>

Defines and holds value of the specification constants for shaders.

Public Functions

SpecConstInfo()

Public Members

vk::SpecializationInfo info
std::vector<vk::SpecializationMapEntry> mapEntries
std::vector<char> data
template <typename Type>
struct Value

Public Members

uint32_t id
Type value
class SpirvBinary
#include <Device.h>

A binary SPIRV shader, to be feed to vulkan.

Public Functions

template <std::size_t N>
SpirvBinary(const uint32_t (&spirv)[N])
const uint32_t *data() const
std::size_t size() const
std::size_t words() const
class Sprite : public Vortex2D::Renderer::AbstractSprite
#include <Sprite.h>

A sprite that renders a texture with a simple pass-through fragment shader.

Subclassed by Vortex2D::Fluid::Density

Public Functions

Sprite(const Device &device, Texture &texture)
struct SwapChainSupportDetails

Public Functions

SwapChainSupportDetails(vk::PhysicalDevice device, vk::SurfaceKHR surface)
bool IsValid() const

Public Members

vk::SurfaceCapabilitiesKHR capabilities
std::vector<vk::SurfaceFormatKHR> formats
std::vector<vk::PresentModeKHR> presentModes
class Texture
#include <Texture.h>

A texture, or in vulkan terms, an image.

Subclassed by Vortex2D::Renderer::RenderTexture

Public Functions

Texture(const Device &device, uint32_t width, uint32_t height, vk::Format format, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY)
~Texture()
Texture(Texture &&other)
template <typename T>
void CopyFrom(const std::vector<T> &data)
template <typename T>
void CopyTo(std::vector<T> &data)
void CopyFrom(vk::CommandBuffer commandBuffer, Texture &srcImage)
void Barrier(vk::CommandBuffer commandBuffer, vk::ImageLayout oldLayout, vk::AccessFlags oldAccess, vk::ImageLayout newLayout, vk::AccessFlags newAccess)
vk::ImageView GetView() const
uint32_t GetWidth() const
uint32_t GetHeight() const
vk::Format GetFormat() const
void Clear(vk::CommandBuffer commandBuffer, const std::array<int, 4> &colour)
void Clear(vk::CommandBuffer commandBuffer, const std::array<float, 4> &colour)

Friends

friend Vortex2D::Renderer::GenericBuffer
class Timer
#include <Timer.h>

Calculates the ellapsed time on the GPU.

Public Functions

Timer(const Device &device)
void Start(vk::CommandBuffer commandBuffer)

Start the timer after the current last command buffer.

Parameters
  • commandBuffer: command buffer to write timestamp

void Stop(vk::CommandBuffer commandBuffer)

Start the timer after the current last command buffer.

Parameters
  • commandBuffer: command buffer to write timestamp

void Start()

Start the timer after the current last command buffer.

void Stop()

Stop the timer after the current last command buffer.

void Wait()

Wait for Start and Stop to finish before retrieving the results.

uint64_t GetElapsedNs()

Get the elapsed time between the Start and Stop calls. Blocking function which will download the timestamps from the GPU.

Return
timestamp in nanoseconds.

struct Transformable
#include <Transformable.h>

Class to represent the transformation of an object: position, scale, rotation and anchor.

Subclassed by Vortex2D::Fluid::Circle, Vortex2D::Fluid::Polygon, Vortex2D::Fluid::RigidBody, Vortex2D::Renderer::AbstractShape, Vortex2D::Renderer::AbstractSprite, Vortex2D::Renderer::Ellipse

Public Functions

Transformable()
virtual ~Transformable()
const glm::mat4 &GetTransform() const

Returns the transform matrix.

void Update()

Update the transform matrix with the position, scale, rotation and anchor.

Public Members

property<glm::vec2> Position

absolute position

property<glm::vec2> Scale

scale for the x and y components

property<float> Rotation

Rotation in radians.

property<glm::vec2> Anchor

An offset to the position (used for centering a shape)

template <typename T>
class UniformBuffer : public Vortex2D::Renderer::GenericBuffer
#include <Buffer.h>

a uniform buffer type of buffer

Public Functions

UniformBuffer(const Device &device, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY)
template <typename T>
class VertexBuffer : public Vortex2D::Renderer::GenericBuffer
#include <Buffer.h>

a vertex buffer type of buffer

Public Functions

VertexBuffer(const Device &device, std::size_t size, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY)
class Work
#include <Work.h>

Represents a compute shader. It simplifies the process of binding, setting push constants and recording.

Public Functions

Work(const Device &device, const ComputeSize &computeSize, const SpirvBinary &spirv, const SpecConstInfo &additionalSpecConstInfo = {})

Constructs an object using a SPIRV binary. It is not bound to any buffers or textures.

Parameters
  • device: vulkan device
  • computeSize: the compute size. Can be a default one with size (1,1) or one with an actual size.
  • spirv: binary spirv
  • additionalSpecConstInfo: additional specialization constants

Work::Bound Bind(const std::vector<BindingInput> &inputs)

Bind the buffers and/or textures.

Return
a bound object, ready to be recorded in a command buffer.
Parameters
  • inputs: a list of buffers and/or textures

VORTEX2D_API Bound Vortex2D::Renderer::Work::Bind(ComputeSize computeSize, const std::vector< BindingInput > & inputs)

Bind the buffers and/or textures. This overrides the provided compute size in Work.

Return
a bound object, ready to be recorded in a command buffer.
Parameters
  • computeSize: the compute shader compute size.
  • inputs: a list of buffers and/or textures

class Bound
#include <Work.h>

Is a bound version of Work. This means a buffer or texture was bound and this can be recorded in a command buffer.

Public Functions

Bound()
template <typename ... Args>
void PushConstant(vk::CommandBuffer commandBuffer, Args&&... args)

Adds a constant value, i.e. a push constant.

Parameters
  • commandBuffer: the command buffer where the compute work will also be recorded.
  • data: the data to push. A total of 128 bytes can be used.

void Record(vk::CommandBuffer commandBuffer)

Record the compute work in this command buffer. This will also set two additional push constants: the 2D domain size.

Parameters
  • commandBuffer: the command buffer to record into.

void RecordIndirect(vk::CommandBuffer commandBuffer, IndirectBuffer<DispatchParams> &dispatchParams)

Record the compute work in this command buffer. Use the provided parameters to run the compute shader.

Parameters
  • commandBuffer: the command buffer to record into.
  • dispatchParams: the indirect buffer containing the parameters.

Friends

friend Vortex2D::Renderer::Work
namespace Detail

Functions

void InsertSpecConst(SpecConstInfo &specConstInfo)
template <typename Arg, typename... Args>
void InsertSpecConst(SpecConstInfo &specConstInfo, Arg &&arg, Args&&... args)

Fluid API reference

API Reference
namespace Fluid

Enums

enum VelocityOp

Operator when applying velocity to velocity field: add or set.

Values:

Add
Set

Functions

Renderer::ComputeSize MakeLocalSize(const glm::ivec2 &size)
VORTEX2D_API LinearSolver::Parameters Vortex2D::Fluid::FixedParams(unsigned iterations)

Create a linear solver parameters object with fixed solver type.

Return
parameters
Parameters
  • iterations: number of iterations to do

VORTEX2D_API LinearSolver::Parameters Vortex2D::Fluid::IterativeParams(float errorTolerance)

Create a linear solver parameters object, solver will continue until error tolerance is reached.

Return
parameters
Parameters
  • errorTolerance: tolerance to reach before exiting

template <typename Class>
void Vortex2D::Fluid::ForAll(std::vector< Class *> & elements, void(Class::*)() f)

Variables

VORTEX2D_API Renderer::ColorBlendState Vortex2D::Fluid::IntersectionBlend

= []

{

Renderer::ColorBlendState

blendState;

blendState.ColorBlend

.setBlendEnable(true)

.setColorBlendOp(vk::BlendOp::eMax)

.setSrcColorBlendFactor(vk::BlendFactor::eOne)

.setDstColorBlendFactor(vk::BlendFactor::eOne)

.setColorWriteMask(vk::ColorComponentFlagBits::eR);

return blendState;

}()

VORTEX2D_API Renderer::ColorBlendState Vortex2D::Fluid::UnionBlend

= []

{

Renderer::ColorBlendState

blendState;

blendState.ColorBlend

.setBlendEnable(true)

.setColorBlendOp(vk::BlendOp::eMin)

.setSrcColorBlendFactor(vk::BlendFactor::eOne)

.setDstColorBlendFactor(vk::BlendFactor::eOne)

.setColorWriteMask(vk::ColorComponentFlagBits::eR);

return blendState;

}()

VORTEX2D_API Renderer::Clear Vortex2D::Fluid::BoundariesClear = Vortex2D::Renderer::Clear({10000.0f, 0.0f, 0.0f, 0.0f})
class Advection
#include <Advection.h>

Advects particles, velocity field or any field using a velocity field.

Public Functions

Advection(const Renderer::Device &device, const glm::ivec2 &size, float dt, Velocity &velocity)

Initialize advection kernels and related object.

Parameters
  • device: vulkan device
  • size: size of velocity field
  • dt: delta time for integration
  • velocity: velocity field

void AdvectVelocity()

Self advect velocity.

void AdvectBind(Density &density)

Binds a density field to be advected.

Parameters
  • density: density field

void Advect()

Performs an advection of the density field. Asynchronous operation.

void AdvectParticleBind(Renderer::GenericBuffer &particles, Renderer::Texture &levelSet, Renderer::IndirectBuffer<Renderer::DispatchParams> &dispatchParams)

Binds praticles to be advected. Also use a level set to project out the particles if they enter it.

Parameters
  • particles: particles to be advected
  • levelSet: level set to project out particles
  • dispatchParams: contains number of particles

void AdvectParticles()

Advect particles. Asynchrounous operation.

class Cfl
#include <Cfl.h>

Calculates the CFL number of the velocity field. It’s an indication on how to choose your time step size. Ideally, the time step should be smaller than the CFL number.

Public Functions

Cfl(const Renderer::Device &device, const glm::ivec2 &size, Velocity &velocity)
void Compute()

Compute the CFL number. Non-blocking.

float Get()

Returns the CFL number. Blocking.

Return
cfl number

class Circle : public Vortex2D::Renderer::Transformable, public Vortex2D::Renderer::Drawable
#include <Boundaries.h>

Signed distance field of circle.

Public Functions

Circle(const Renderer::Device &device, float radius, float extent = 10.0f)

Initialize the circle with radius and extend of signed distance.

Parameters
  • device: vulkan device.
  • radius: radius of circle.
  • extent: extend how far from the circle the signed distance field is calculated.

void Initialize(const Renderer::RenderState &renderState)

Initialize the drawable for a particular state. This might include creating the correct pipeline. If it was already initialized, it will do nothing.

Parameters
  • renderState: the state to initialize with.

void Update(const glm::mat4 &projection, const glm::mat4 &view)

Update the MVP matrix of the drawable.

Parameters
  • projection: the projection matrix
  • view: the view matrix

void Draw(vk::CommandBuffer commandBuffer, const Renderer::RenderState &renderState)

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

class ConjugateGradient : public Vortex2D::Fluid::LinearSolver
#include <ConjugateGradient.h>

An iterative preconditioned conjugate linear solver. The preconditioner can be specified.

Public Functions

ConjugateGradient(const Renderer::Device &device, const glm::ivec2 &size, Preconditioner &preconditioner)

Initialize the solver with a size and preconditioner.

Parameters
  • device: vulkan device
  • size:
  • preconditioner:

void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x)

Bind the buffers for the linear solver.

Parameters
  • d: the diagonal of the matrxi
  • l: the lower matrix
  • b: the right hand side
  • x: the unknowns

void BindRigidbody(float delta, Renderer::GenericBuffer &d, RigidBody &rigidBody)

Bind rigidbody with the linear solver’s matrix.

Parameters
  • delta: solver delta
  • d: diagonal matrix
  • rigidBody: rigidbody to bind to

void Solve(Parameters &params, const std::vector<RigidBody *> &rigidbodies = {})

Solve iteratively solve the linear equations in data.

class Density : public Vortex2D::Renderer::RenderTexture, public Vortex2D::Renderer::Sprite
#include <Density.h>

Density field, used to represent smoke swirling.

Public Functions

Density(const Renderer::Device &device, const glm::ivec2 &size, vk::Format format)

Friends

friend Vortex2D::Fluid::Advection
class Depth
#include <Multigrid.h>

Contains the sizes of the multigrid hierarchy.

Public Functions

Depth(const glm::ivec2 &size)

Initialize with the finest size.

Parameters
  • size: the base size.

int GetMaxDepth() const

The calculated depth of the multigrid.

Return
the depth.

glm::ivec2 GetDepthSize(std::size_t i) const

Gets the depth for a given level.

Return
the size
Parameters
  • i: the level

class Diagonal : public Vortex2D::Fluid::Preconditioner
#include <Diagonal.h>

Diagonal preconditioner. Simplest of preconditioner, useful to verify if the preconditioned conjugate gradient works.

Public Functions

Diagonal(const Renderer::Device &device, const glm::ivec2 &size)
void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x)

Bind the linear equation buffers.

Parameters
  • d: the diagonal of the matrix
  • l: the lower matrix
  • b: the right hand side
  • x: the unknown buffer

void Record(vk::CommandBuffer commandBuffer)

Record the preconditioner.

Parameters
  • commandBuffer: the command buffer to record into.

class DistanceField : public Vortex2D::Renderer::AbstractSprite
#include <Boundaries.h>

Sprite of a distance field.

Public Functions

DistanceField(const Renderer::Device &device, Renderer::RenderTexture &levelSet, float scale = 1.0f)

Initialize the price with the level set and scale.

Parameters
  • device: vulkan device
  • levelSet: level set to use as sprite
  • scale: scale of the level set

void Draw(vk::CommandBuffer commandBuffer, const Renderer::RenderState &renderState)

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

class Extrapolation
#include <Extrapolation.h>

Class to extrapolate values into the neumann and/or dirichlet boundaries.

Public Functions

Extrapolation(const Renderer::Device &device, const glm::ivec2 &size, Renderer::GenericBuffer &valid, Velocity &velocity, int iterations = 10)
void Extrapolate()

Will extrapolate values from buffer into the dirichlet and neumann boundaries.

void ConstrainBind(Renderer::Texture &solidPhi)

Binds a solid level set to use later and constrain the velocity against.

Parameters
  • solidPhi: solid level set

void ConstrainVelocity()

Constrain the velocity, i.e. ensure that the velocity normal to the solid level set is 0.

class GaussSeidel : public Vortex2D::Fluid::LinearSolver, public Vortex2D::Fluid::Preconditioner
#include <GaussSeidel.h>

An iterative black and red successive over relaxation linear solver.

Public Functions

GaussSeidel(const Renderer::Device &device, const glm::ivec2 &size)
void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x)

Bind the buffers for the linear solver.

Parameters
  • d: the diagonal of the matrxi
  • l: the lower matrix
  • b: the right hand side
  • x: the unknowns

void BindRigidbody(float delta, Renderer::GenericBuffer &d, RigidBody &rigidBody)

Bind rigidbody with the linear solver’s matrix.

Parameters
  • delta: solver delta
  • d: diagonal matrix
  • rigidBody: rigidbody to bind to

void Solve(Parameters &params, const std::vector<RigidBody *> &rigidbodies = {})

Iterative solving of the linear equations in data.

void Record(vk::CommandBuffer commandBuffer)

Record the preconditioner.

Parameters
  • commandBuffer: the command buffer to record into.

void Record(vk::CommandBuffer commandBuffer, int iterations)

Record a determined number of iterations.

Parameters
  • commandBuffer:
  • iterations:

void SetW(float w)

Set the w factor of the GS iterations : x_new = w * x_new + (1-w) * x_old.

Parameters
  • w:

void SetPreconditionerIterations(int iterations)

set number of iterations to be used when GS is a preconditioner

Parameters
  • iterations:

class IncompletePoisson : public Vortex2D::Fluid::Preconditioner
#include <IncompletePoisson.h>

Incomplete poisson preconditioner. Slightly better than a simple diagonal preconditioner.

Public Functions

IncompletePoisson(const Renderer::Device &device, const glm::ivec2 &size)
void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x)

Bind the linear equation buffers.

Parameters
  • d: the diagonal of the matrix
  • l: the lower matrix
  • b: the right hand side
  • x: the unknown buffer

void Record(vk::CommandBuffer commandBuffer)

Record the preconditioner.

Parameters
  • commandBuffer: the command buffer to record into.

struct J

Public Members

glm::vec2 linear
float angular
class Jacobi : public Vortex2D::Fluid::Preconditioner
#include <Jacobi.h>

An iterative jacobi linear solver.

Public Functions

Jacobi(const Renderer::Device &device, const glm::ivec2 &size)
void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x)

Bind the linear equation buffers.

Parameters
  • d: the diagonal of the matrix
  • l: the lower matrix
  • b: the right hand side
  • x: the unknown buffer

void Record(vk::CommandBuffer commandBuffer)

Record the preconditioner.

Parameters
  • commandBuffer: the command buffer to record into.

void Record(vk::CommandBuffer commandBuffer, int iterations)
void SetW(float w)

Set the w factor of the GS iterations : x_new = w * x_new + (1-w) * x_old.

Parameters
  • w:

void SetPreconditionerIterations(int iterations)

set number of iterations to be used when GS is a preconditioner

Parameters
  • iterations:

class LevelSet : public Vortex2D::Renderer::RenderTexture
#include <LevelSet.h>

A signed distance field, which can be re-initialized. In other words, a level set.

Public Functions

LevelSet(const Renderer::Device &device, const glm::ivec2 &size, int reinitializeIterations = 100)
void Reinitialise()

Reinitialise the level set, i.e. ensure it is a correct signed distance field.

void ExtrapolateBind(Renderer::Texture &solidPhi)

Bind a solid level set, which will be used to extrapolate into this level set.

Parameters
  • solidPhi:

void Extrapolate()

Extrapolate this level set into the solid level set it was attached to. This only performs a single cell extrapolation.

struct LinearSolver
#include <LinearSolver.h>

An interface to represent a linear solver.

Subclassed by Vortex2D::Fluid::ConjugateGradient, Vortex2D::Fluid::GaussSeidel

Public Functions

virtual ~LinearSolver()
virtual void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x) = 0

Bind the buffers for the linear solver.

Parameters
  • d: the diagonal of the matrxi
  • l: the lower matrix
  • b: the right hand side
  • x: the unknowns

virtual void BindRigidbody(float delta, Renderer::GenericBuffer &d, RigidBody &rigidBody) = 0

Bind rigidbody with the linear solver’s matrix.

Parameters
  • delta: solver delta
  • d: diagonal matrix
  • rigidBody: rigidbody to bind to

virtual void Solve(Parameters &params, const std::vector<RigidBody *> &rigidbodies = {}) = 0

Solves the linear equations.

Parameters
  • params: solver iteration/error parameters
  • rigidBodies: rigidbody to include in solver’s matrix

struct Data
#include <LinearSolver.h>

The various parts of linear equations.

Public Functions

Data(const Renderer::Device &device, const glm::ivec2 &size, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY)

Public Members

Renderer::Buffer<float> Diagonal
Renderer::Buffer<glm::vec2> Lower
Renderer::Buffer<float> B
Renderer::Buffer<float> X
struct Parameters
#include <LinearSolver.h>

Parameters for an iterative linear solvers.

Public Types

enum SolverType

Run the solver a fixed number of step or until we reached a minimum error.

Values:

Fixed
Iterative

Public Functions

Parameters(SolverType type, unsigned iterations, float errorTolerance = 0.0f)

Construct parameters with max iterations and max error.

Parameters
  • type: fixed or iterative type of solver
  • iterations: max number of iterations to perform
  • errorTolerance: solver stops when the error is smaller than this.

bool IsFinished(float initialError) const

Checks if we’ve reacched the parameters.

Return
if we can stop the linear solver.
Parameters
  • initialError: the initial error

void Reset()

Sets the out error and out iterations to 0.

Public Members

SolverType Type
unsigned Iterations
float ErrorTolerance
unsigned OutIterations
float OutError
class LocalGaussSeidel : public Vortex2D::Fluid::Preconditioner
#include <GaussSeidel.h>

A version of the gauss seidel that can only be applied on sizes (16,16) or smaller.

Public Functions

LocalGaussSeidel(const Renderer::Device &device, const glm::ivec2 &size)
void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x)

Bind the linear equation buffers.

Parameters
  • d: the diagonal of the matrix
  • l: the lower matrix
  • b: the right hand side
  • x: the unknown buffer

void Record(vk::CommandBuffer commandBuffer)

Record the preconditioner.

Parameters
  • commandBuffer: the command buffer to record into.

class Multigrid : public Vortex2D::Fluid::Preconditioner
#include <Multigrid.h>

Multigrid preconditioner. It creates a hierarchy of twice as small set of linear equations. It applies a few iterations of jacobi on each level and transfers the error on the level above. It then copies the error down, adds to the current solution and apply a few more iterations of jacobi.

Public Functions

Multigrid(const Renderer::Device &device, const glm::ivec2 &size, float delta)

Initialize multigrid for given size and delta.

Parameters
  • device: vulkan device
  • size: of the linear equations
  • delta: timestep delta

void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x)

Bind the linear equation buffers.

Parameters
  • d: the diagonal of the matrix
  • l: the lower matrix
  • b: the right hand side
  • x: the unknown buffer

void BuildHierarchiesBind(Pressure &pressure, Renderer::Texture &solidPhi, Renderer::Texture &liquidPhi)

Bind the level sets from which the hierarchy is built.

Parameters
  • pressure: The current linear equations
  • solidPhi: the solid level set
  • liquidPhi: the liquid level set

void BuildHierarchies()

Computes the hierarchy to be used by the multigrid. Asynchronous operation.

void Record(vk::CommandBuffer commandBuffer)

Record the preconditioner.

Parameters
  • commandBuffer: the command buffer to record into.

struct Particle

Public Members

glm::vec2 Position
glm::vec2 Velocity
class ParticleCount : public Vortex2D::Renderer::RenderTexture
#include <Particles.h>

Container for particles used in the advection of the fluid simulation. Also a level set that is built from the particles.

Public Functions

ParticleCount(const Renderer::Device &device, const glm::ivec2 &size, Renderer::GenericBuffer &particles, const Renderer::DispatchParams &params = {0}, float alpha = 1.0f)
void Scan()

Count the number of particles and update the internal data structures.

int GetTotalCount()

Calculate the total number of particles and return it.

Return

Renderer::IndirectBuffer<Renderer::DispatchParams> &GetDispatchParams()

Calculate the dispatch parameters to use on the particle buffer.

Return

void LevelSetBind(LevelSet &levelSet)

Bind a solid level set, which will be used to interpolate the particles out of.

Parameters
  • levelSet:

void Phi()

Calculate the level set from the particles.

void VelocitiesBind(Velocity &velocity, Renderer::GenericBuffer &valid)

Bind the velocities, used for advection of the particles.

Parameters
  • velocity:
  • valid:

void TransferToGrid()

Interpolate the velocities of the particles to the velocities field.

void TransferFromGrid()

Interpolate the velocities field in to the particles’ velocity.

class Polygon : public Vortex2D::Renderer::Transformable, public Vortex2D::Renderer::Drawable
#include <Boundaries.h>

Signed distance field of a poylgon.

Subclassed by Vortex2D::Fluid::Rectangle

Public Functions

Polygon(const Renderer::Device &device, std::vector<glm::vec2> points, bool inverse = false, float extent = 10.0f)

Initialize polygon with set of points and extent of signed distance.

Parameters
  • device: vulkan device
  • points: clockwise oriented set of points (mininum 3).
  • inverse: flag if the distance field should be inversed.
  • extent: extend how far from the poylon the signed distance field is calculated.

void Initialize(const Renderer::RenderState &renderState)

Initialize the drawable for a particular state. This might include creating the correct pipeline. If it was already initialized, it will do nothing.

Parameters
  • renderState: the state to initialize with.

void Update(const glm::mat4 &projection, const glm::mat4 &view)

Update the MVP matrix of the drawable.

Parameters
  • projection: the projection matrix
  • view: the view matrix

void Draw(vk::CommandBuffer commandBuffer, const Renderer::RenderState &renderState)

Draw for the given render state. This has to be initialized before.

Parameters
  • commandBuffer: the command buffer to record into.
  • renderState: the render state to use.

struct Preconditioner
#include <Preconditioner.h>

An interface to represent a linear solver preconditioner.

Subclassed by Vortex2D::Fluid::Diagonal, Vortex2D::Fluid::GaussSeidel, Vortex2D::Fluid::IncompletePoisson, Vortex2D::Fluid::Jacobi, Vortex2D::Fluid::LocalGaussSeidel, Vortex2D::Fluid::Multigrid

Public Functions

virtual ~Preconditioner()
virtual void Bind(Renderer::GenericBuffer &d, Renderer::GenericBuffer &l, Renderer::GenericBuffer &b, Renderer::GenericBuffer &x) = 0

Bind the linear equation buffers.

Parameters
  • d: the diagonal of the matrix
  • l: the lower matrix
  • b: the right hand side
  • x: the unknown buffer

virtual void Record(vk::CommandBuffer commandBuffer) = 0

Record the preconditioner.

Parameters
  • commandBuffer: the command buffer to record into.

class PrefixScan
#include <PrefixScan.h>

The prefix sum operator.

void PrefixSym(int input[], int n, int output[])
{
    output[0] = input[0];

    for (int i = 1; i < n; i++)
        output[i] = output[i-1] + input[i];
}

Public Functions

PrefixScan(const Renderer::Device &device, const glm::ivec2 &size)
PrefixScan::Bound Bind(Renderer::GenericBuffer &input, Renderer::GenericBuffer &output, Renderer::GenericBuffer &dispatchParams)
class Bound
#include <PrefixScan.h>

A prefix scan object bound with input/output buffers, ready to be dispatched.

Public Functions

void Record(vk::CommandBuffer commandBuffer)

Friends

friend Vortex2D::Fluid::PrefixScan
class Pressure
#include <Pressure.h>

build the linear equation and compute the divergence from the resulting solution.

Public Functions

Pressure(const Renderer::Device &device, float dt, const glm::ivec2 &size, LinearSolver::Data &data, Velocity &velocity, Renderer::Texture &solidPhi, Renderer::Texture &liquidPhi, Renderer::GenericBuffer &valid)
Renderer::Work::Bound BindMatrixBuild(const glm::ivec2 &size, Renderer::GenericBuffer &diagonal, Renderer::GenericBuffer &lower, Renderer::Texture &liquidPhi, Renderer::Texture &solidPhi)

Bind the various buffes for the linear system Ax = b.

Return
Parameters
  • size: size of the linear system
  • diagonal: diagonal of A
  • lower: lower matrix of A
  • liquidPhi: liquid level set
  • solidPhi: solid level set

void BuildLinearEquation()

Build the matrix A and right hand side b.

void ApplyPressure()

Apply the solution of the equation Ax = b, i.e. the pressure to the velocity to make it non-divergent.

class Rectangle : public Vortex2D::Fluid::Polygon
#include <Boundaries.h>

Signed distance field of a rectangle.

Public Functions

Rectangle(const Renderer::Device &device, const glm::vec2 &size, bool inverse = false, float extent = 10.0f)

Initialize rectangle with size and extend of signed distance.

Parameters
  • device: vulkan device.
  • size: rectangle size
  • inverse: flag if the distance field should be inverted.
  • extent: extent how far from the rectangle the signed distance field is calculated.

class Reduce
#include <Reduce.h>

Parallel reduction of a buffer into one value. The operator and type of data is specified by inheriting the class.

Subclassed by Vortex2D::Fluid::ReduceJ, Vortex2D::Fluid::ReduceMax, Vortex2D::Fluid::ReduceSum

Public Functions

virtual ~Reduce()
Reduce::Bound Bind(Renderer::GenericBuffer &input, Renderer::GenericBuffer &output)

Bind the reduce operation.

Return
a bound object that can be recorded in a command buffer.
Parameters
  • input: input buffer
  • output: output buffer

class Bound
#include <Reduce.h>

Bound input and output buffer for a reduce operation.

Public Functions

Bound()
void Record(vk::CommandBuffer commandBuffer)

Record the reduce operation.

Parameters
  • commandBuffer: the command buffer to record into.

Friends

friend Vortex2D::Fluid::Reduce
class ReduceJ : public Vortex2D::Fluid::Reduce
#include <Reduce.h>

Reduce operation on a struct with a 2d vector and 1 float (i.e. 3 floats) with addition.

Public Functions

ReduceJ(const Renderer::Device &device, const glm::ivec2 &size)

Initialize reduce with device and 2d size.

Parameters
  • device:
  • size:

class ReduceMax : public Vortex2D::Fluid::Reduce
#include <Reduce.h>

Reduce operation on float with max of absolute.

Public Functions

ReduceMax(const Renderer::Device &device, const glm::ivec2 &size)

Initialize reduce with device and 2d size.

Parameters
  • device:
  • size:

class ReduceSum : public Vortex2D::Fluid::Reduce
#include <Reduce.h>

Reduce operation on float with addition.

Public Functions

ReduceSum(const Renderer::Device &device, const glm::ivec2 &size)

Initialize reduce with device and 2d size.

Parameters
  • device:
  • size:

class RigidBody : public Vortex2D::Renderer::Transformable
#include <Rigidbody.h>

Rigidbody that can interact with the fluid: either be push by it, or influence it, or both.

Public Types

enum Type

Values:

eStatic = 0x01
eWeak = 0x02
eStrong = 0x3

Public Functions

RigidBody(const Renderer::Device &device, const glm::ivec2 &size, Renderer::Drawable &drawable, vk::Flags<Type> type)
~RigidBody()
void ApplyForces()

function to override and apply forces from this rigidbody to the external rigidbody

void ApplyVelocities()

to override and apply velocities from the external rigidbody to the this rigidbody

void SetMassData(float mass, float inertia)

Sets the mass and inertia of the rigidbody.

Parameters
  • mass: of the body
  • inertia: of the body

void SetVelocities(const glm::vec2 &velocity, float angularVelocity)

sets the velocities and angular velocities of the body

Parameters
  • velocity:
  • angularVelocity:

void UpdatePosition()

Upload the transform matrix to the GPU.

void RenderPhi()

Render the current object orientation in an internal texture and the external one.

void BindPhi(Renderer::RenderTexture &phi)

Bind the rendertexture where this rigidbodies shape will be rendered.

Parameters
  • phi: render texture of the world

void BindDiv(Renderer::GenericBuffer &div, Renderer::GenericBuffer &diagonal)

Bind a the right hand side and diagonal of the linear system Ax = b. This is to apply the rigid body influence to the system.

Parameters
  • div: right hand side of the linear system Ax=b
  • diagonal: diagonal of matrix A
  • fluidLevelSet: fluid level set

void BindVelocityConstrain(Fluid::Velocity &velocity)

Bind velocities to constrain based on the body’s velocity.

Parameters
  • velocity:

void BindForce(Renderer::GenericBuffer &d, Renderer::GenericBuffer &pressure)

Bind pressure, to have the pressure update the body’s forces.

Parameters
  • fluidLevelSet: fluid level set, to know if the pressure is applicable
  • pressure: solved pressure buffer

void BindPressure(float delta, Renderer::GenericBuffer &d, Renderer::GenericBuffer &s, Renderer::GenericBuffer &z)

Bind pressure, to have the pressure update the body’s forces.

Parameters
  • delta:
  • d:
  • s:
  • z:

void Div()

Apply the body’s velocities to the linear equations matrix A and right hand side b.

void Force()

Apply the pressure to body, updating its forces.

void Pressure()

Reduce the force for pressure update.

void VelocityConstrain()

Constrain the velocities field based on the body’s velocity.

RigidBody::Velocity GetForces()

Download the forces from the GPU and return them.

Return

vk::Flags<RigidBody::Type> GetType()

Type of this body.

Return

Renderer::RenderTexture &Phi()

the local level set of the body

Return

struct Velocity

Public Members

glm::vec2 velocity
float angular_velocity
class RigidBodySolver
#include <Rigidbody.h>

Interface to call the external rigidbody solver.

Public Functions

virtual void Step(float delta) = 0

perfoms a single step of the solver.

Parameters
  • delta: of simulation

class SmokeWorld : public Vortex2D::Fluid::World
#include <World.h>

A concrete implementation of World to simulate ‘smoke’, or more accurately dye in a liquid. The liquid cannot change location or size.

Public Functions

SmokeWorld(const Renderer::Device &device, const glm::ivec2 &size, float dt)
void FieldBind(Density &density)

Bind a density field to be moved around with the fluid.

Parameters
  • density: the density field

class Transfer
#include <Transfer.h>

Prolongates or restrict a level set on a finer or coarser level set.

Public Functions

Transfer(const Renderer::Device &device)

Initialize prolongate and restrict compute pipelines.

Parameters
  • device:

void ProlongateBind(std::size_t level, const glm::ivec2 &fineSize, Renderer::GenericBuffer &fine, Renderer::GenericBuffer &fineDiagonal, Renderer::GenericBuffer &coarse, Renderer::GenericBuffer &coarseDiagonal)

Prolongate a level set on a finer level set. Setting the 4 cells to the value of the coarser grid. Multiple level sets can be bound and indexed.

Parameters
  • level: the index of the bound level set to prolongate
  • fineSize: size of the finer level set
  • fine: the finer level set
  • fineDiagonal: the diagonal of the linear equation matrix at size fineSize
  • coarse: the coarse level set
  • coarseDiagonal: the diagonal of the linear equation matrix at size half of fineSize

void RestrictBind(std::size_t level, const glm::ivec2 &fineSize, Renderer::GenericBuffer &fine, Renderer::GenericBuffer &fineDiagonal, Renderer::GenericBuffer &coarse, Renderer::GenericBuffer &coarseDiagonal)

Restricing the level set on a coarser level set. Averages 4 cells into one. Multiple level sets can be bound and indexed.

Parameters
  • level: the index of the bound level set to prolongate
  • fineSize: size of the finer level set
  • fine: the finer level set
  • fineDiagonal: the diagonal of the linear equation matrix at size fineSize
  • coarse: the coarse level set
  • coarseDiagonal: the diagonal of the linear equation matrix at size half of fineSize

void Prolongate(vk::CommandBuffer commandBuffer, std::size_t level)

Prolongate the level set, using the bound level sets at the specified index.

Parameters
  • commandBuffer: command buffer to record into.
  • level: index of bound level sets.

void Restrict(vk::CommandBuffer commandBuffer, std::size_t level)

Restrict the level set, using the bound level sets at the specified index.

Parameters
  • commandBuffer: command buffer to record into.
  • level: index of bound level sets.

class Velocity : public Vortex2D::Renderer::RenderTexture
#include <Velocity.h>

The Velocity field. Can be used to calculate a difference between different states. Contains three fields: intput and output, used for ping-pong algorithms, and d, the difference between two velocity fields.

Public Functions

Velocity(const Renderer::Device &device, const glm::ivec2 &size)
Renderer::Texture &Output()

An output texture used for algorithms that used the velocity as input and need to create a new velocity field.

Return

Renderer::Texture &D()

A difference velocity field, calculated with the difference between this velocity field, and the output velocity field.

Return

void CopyBack(vk::CommandBuffer commandBuffer)

Copy the output field to the main field.

Parameters
  • commandBuffer:

void Clear(vk::CommandBuffer commandBuffer)

Clear the velocity field.

Parameters
  • commandBuffer:

void SaveCopy()

Copy to the difference field.

void VelocityDiff()

Calculate the difference between the difference field and this velocity field, store it in the diference field.

class WaterWorld : public Vortex2D::Fluid::World
#include <World.h>

A concrete implementation of World to simulate water.

Public Functions

WaterWorld(const Renderer::Device &device, const glm::ivec2 &size, float dt, int numSubSteps)
Renderer::RenderCommand RecordParticleCount(Renderer::RenderTarget::DrawableList drawables)

The water simulation uses particles to define the water area. In fact, the level set is built from the particles. This means to be able to set an area, we can’t use RecordLiquidPhi. To define the particle area, simply draw a regular shape. The colour r is used to determine if we add or remove particles, use r = 4 to add and r = -4 to remove.

Return
render command
Parameters
  • drawables: list of drawables object with colour 8 or -8

class World
#include <World.h>

The main class of the framework. Each instance manages a grid and this class is used to set forces, define boundaries, solve the incompressbility equations and do the advection.

Subclassed by Vortex2D::Fluid::SmokeWorld, Vortex2D::Fluid::WaterWorld

Public Functions

World(const Renderer::Device &device, const glm::ivec2 &size, float dt, int numSubSteps = 1)

Construct an Engine with a size and time step.

Parameters
  • device: vulkan device
  • size: dimensions of the simulation
  • dt: timestamp of the simulation, e.g. 0.016 for 60FPS simulations.
  • numSubSteps: the number of sub-steps to perform per step call. Reduces loss of fluid.

virtual ~World()
void Step(LinearSolver::Parameters &params)

Perform one step of the simulation.

Renderer::RenderCommand RecordVelocity(Renderer::RenderTarget::DrawableList drawables, VelocityOp op)

Record drawables to the velocity field. The colour (r,g) will be used as the velocity (x, y)

Return
render command
Parameters
  • drawables: a list of drawable field
  • op: operation of the render: add velocity or set velocity

void SubmitVelocity(Renderer::RenderCommand &renderCommand)

submit the render command created with RecordVelocity

Parameters
  • renderCommand: the render command

Renderer::RenderCommand RecordLiquidPhi(Renderer::RenderTarget::DrawableList drawables)

Record drawables to the liquid level set, i.e. to define the fluid area. The drawables need to make a signed distance field, if not the result is undefined.

Return
render command
Parameters
  • drawables: a list of signed distance field drawables

Renderer::RenderCommand RecordStaticSolidPhi(Renderer::RenderTarget::DrawableList drawables)

Record drawables to the solid level set, i.e. to define the boundary area. The drawables need to make a signed distance field, if not the result is undefined.

Return
render command
Parameters
  • drawables: a list of signed distance field drawables

DistanceField LiquidDistanceField()

Create sprite that can be rendered to visualize the liquid level set.

Return
a sprite

DistanceField SolidDistanceField()

Create sprite that can be rendered to visualize the solid level set.

Return
a sprite

void AddRigidbody(RigidBody &rigidbody)

Add a rigibody to the solver.

Parameters
  • rigidbody:

void RemoveRigidBody(RigidBody &rigidbody)

Remove a rigidbody from the solver.

Parameters
  • rigidbody:

void AttachRigidBodySolver(RigidBodySolver &rigidbodySolver)

Attach a rigidbody solver, e.g. box2d.

Parameters
  • rigidbodySolver:

float GetCFL()

Calculate the CFL number, i.e. the width divided by the max velocity.

Return
CFL number

Renderer::Texture &GetVelocity()

Get the velocity, can be used to display it.

Return
velocity field reference