-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FLIP fluid simulation example #145
base: master
Are you sure you want to change the base?
Changes from 63 commits
dcaead3
dbf97a8
1ca6ea2
b910ce5
b4125e6
8f267c8
fbb696d
37d9ac4
f463a0b
98fee14
7001b1e
18b7cc9
29db701
eaf034a
3a4fc2d
d89692b
0a7845a
0b38b07
ea269e2
80ac1da
90c5a5a
586b70b
1a6205c
869b974
9013205
fdf9dde
e9f2489
b9353f3
6676476
0710f23
51b59f5
be4bbfe
5f11de4
a9816ac
f801ab1
b600e4a
4943b3c
2e85153
f85443b
d51970d
fe99f53
99cfee8
f125b05
4309860
b733b16
9d7f215
5a22471
869b0c8
a87c1d7
36dd333
846df9e
3fcfc30
0b623d5
e0a715a
e0914d9
ce2d305
c44f474
4aaa0b7
b57aca2
41d16bf
c95daef
55a950b
fd18c2b
ea47f35
aac75f1
f8cfe65
99b9837
e819c9d
70d73f2
4f66d96
26cbbff
e6c8526
3880f0e
5168747
09fb9f8
2d00c1e
38a3cc2
c8393de
12391e6
1ad5819
1e1360a
77561f2
af0b661
516515f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
include(common RESULT_VARIABLE RES) | ||
if(NOT RES) | ||
message(FATAL_ERROR "common.cmake not found. Should be in {repo_root}/cmake directory") | ||
endif() | ||
|
||
nbl_create_executable_project("" "" "" "" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") | ||
|
||
if(NBL_EMBED_BUILTIN_RESOURCES) | ||
set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData) | ||
set(RESOURCE_DIR "app_resources") | ||
|
||
get_filename_component(_SEARCH_DIRECTORIES_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) | ||
get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/src" ABSOLUTE) | ||
get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/include" ABSOLUTE) | ||
|
||
file(GLOB_RECURSE BUILTIN_RESOURCE_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}" CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}/*") | ||
foreach(RES_FILE ${BUILTIN_RESOURCE_FILES}) | ||
LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "${RES_FILE}") | ||
endforeach() | ||
|
||
ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_SEARCH_DIRECTORIES_}" "${RESOURCE_DIR}" "nbl::this_example::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}") | ||
|
||
LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_}) | ||
endif() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
https://github.com/user-attachments/assets/fc8bfac9-c8fb-49f1-87d6-251aae015945 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
#ifndef _FLIP_EXAMPLE_CELL_UTILS_HLSL | ||
#define _FLIP_EXAMPLE_CELL_UTILS_HLSL | ||
|
||
#ifdef __HLSL_VERSION | ||
static const uint CM_SOLID = 0; | ||
static const uint CM_FLUID = 1; | ||
static const uint CM_AIR = 2; | ||
|
||
static const uint CellMatMask = 0x00000003u; | ||
static const uint CellMatMaskShift = 0; | ||
static const uint XPrevMatMask = 0x0000000cu; | ||
static const uint XPrevMatMaskShift = 2; | ||
static const uint XNextMatMask = 0x00000030u; | ||
static const uint XNextMatMaskShift = 4; | ||
static const uint YPrevMatMask = 0x000000c0u; | ||
static const uint YPrevMatMaskShift = 6; | ||
static const uint YNextMatMask = 0x00000300u; | ||
static const uint YNextMatMaskShift = 8; | ||
static const uint ZPrevMatMask = 0x00000c00u; | ||
static const uint ZPrevMatMaskShift = 10; | ||
static const uint ZNextMatMask = 0x00003000u; | ||
static const uint ZNextMatMaskShift = 12; | ||
Comment on lines
+5
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HLSL has bitfields. struct Cell
{
uint32_t cellMaterial : 2;
...etc...
}; |
||
|
||
inline void setCellMaterial(inout uint cellMaterials, uint cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~CellMatMask) | ((cellMaterial << CellMatMaskShift) & CellMatMask); | ||
} | ||
inline uint getCellMaterial(uint cellMaterials) | ||
{ | ||
return (cellMaterials & CellMatMask) >> CellMatMaskShift; | ||
} | ||
inline void setXPrevMaterial(inout uint cellMaterials, uint cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~XPrevMatMask) | ((cellMaterial << XPrevMatMaskShift) & XPrevMatMask); | ||
} | ||
inline uint getXPrevMaterial(uint cellMaterials) | ||
{ | ||
return (cellMaterials & XPrevMatMask) >> XPrevMatMaskShift; | ||
} | ||
inline void setXNextMaterial(inout uint cellMaterials, uint cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~XNextMatMask) | ((cellMaterial << XNextMatMaskShift) & XNextMatMask); | ||
} | ||
inline uint getXNextMaterial(uint cellMaterials) | ||
{ | ||
return (cellMaterials & XNextMatMask) >> XNextMatMaskShift; | ||
} | ||
inline void setYPrevMaterial(inout uint cellMaterials, uint cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~YPrevMatMask) | ((cellMaterial << YPrevMatMaskShift) & YPrevMatMask); | ||
} | ||
inline uint getYPrevMaterial(uint cellMaterials) | ||
{ | ||
return (cellMaterials & YPrevMatMask) >> YPrevMatMaskShift; | ||
} | ||
inline void setYNextMaterial(inout uint cellMaterials, uint cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~YNextMatMask) | ((cellMaterial << YNextMatMaskShift) & YNextMatMask); | ||
} | ||
inline uint getYNextMaterial(uint cellMaterials) | ||
{ | ||
return (cellMaterials & YNextMatMask) >> YNextMatMaskShift; | ||
} | ||
inline void setZPrevMaterial(inout uint cellMaterials, uint cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~ZPrevMatMask) | ((cellMaterial << ZPrevMatMaskShift) & ZPrevMatMask); | ||
} | ||
inline uint getZPrevMaterial(uint cellMaterials) | ||
{ | ||
return (cellMaterials & ZPrevMatMask) >> ZPrevMatMaskShift; | ||
} | ||
inline void setZNextMaterial(inout uint cellMaterials, uint cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~ZNextMatMask) | ((cellMaterial << ZNextMatMaskShift) & ZNextMatMask); | ||
} | ||
inline uint getZNextMaterial(uint cellMaterials) | ||
{ | ||
return (cellMaterials & ZNextMatMask) >> ZNextMatMaskShift; | ||
} | ||
|
||
|
||
inline void setCellMaterial(inout uint3 cellMaterials, uint3 cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~CellMatMask) | ((cellMaterial << CellMatMaskShift) & CellMatMask); | ||
} | ||
inline uint3 getCellMaterial(uint3 cellMaterials) | ||
{ | ||
return (cellMaterials & CellMatMask) >> CellMatMaskShift; | ||
} | ||
inline void setXPrevMaterial(inout uint3 cellMaterials, uint3 cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~XPrevMatMask) | ((cellMaterial << XPrevMatMaskShift) & XPrevMatMask); | ||
} | ||
inline uint3 getXPrevMaterial(uint3 cellMaterials) | ||
{ | ||
return (cellMaterials & XPrevMatMask) >> XPrevMatMaskShift; | ||
} | ||
inline void setXNextMaterial(inout uint3 cellMaterials, uint3 cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~XNextMatMask) | ((cellMaterial << XNextMatMaskShift) & XNextMatMask); | ||
} | ||
inline uint3 getXNextMaterial(uint3 cellMaterials) | ||
{ | ||
return (cellMaterials & XNextMatMask) >> XNextMatMaskShift; | ||
} | ||
inline void setYPrevMaterial(inout uint3 cellMaterials, uint3 cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~YPrevMatMask) | ((cellMaterial << YPrevMatMaskShift) & YPrevMatMask); | ||
} | ||
inline uint3 getYPrevMaterial(uint3 cellMaterials) | ||
{ | ||
return (cellMaterials & YPrevMatMask) >> YPrevMatMaskShift; | ||
} | ||
inline void setYNextMaterial(inout uint3 cellMaterials, uint3 cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~YNextMatMask) | ((cellMaterial << YNextMatMaskShift) & YNextMatMask); | ||
} | ||
inline uint3 getYNextMaterial(uint3 cellMaterials) | ||
{ | ||
return (cellMaterials & YNextMatMask) >> YNextMatMaskShift; | ||
} | ||
inline void setZPrevMaterial(inout uint3 cellMaterials, uint3 cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~ZPrevMatMask) | ((cellMaterial << ZPrevMatMaskShift) & ZPrevMatMask); | ||
} | ||
inline uint3 getZPrevMaterial(uint3 cellMaterials) | ||
{ | ||
return (cellMaterials & ZPrevMatMask) >> ZPrevMatMaskShift; | ||
} | ||
inline void setZNextMaterial(inout uint3 cellMaterials, uint3 cellMaterial) | ||
{ | ||
cellMaterials = (cellMaterials & ~ZNextMatMask) | ((cellMaterial << ZNextMatMaskShift) & ZNextMatMask); | ||
} | ||
inline uint3 getZNextMaterial(uint3 cellMaterials) | ||
{ | ||
return (cellMaterials & ZNextMatMask) >> ZNextMatMaskShift; | ||
} | ||
|
||
|
||
inline bool isSolidCell(uint cellMaterial) | ||
{ | ||
return cellMaterial == CM_SOLID; | ||
} | ||
inline bool isFluidCell(uint cellMaterial) | ||
{ | ||
return cellMaterial == CM_FLUID; | ||
} | ||
inline bool isAirCell(uint cellMaterial) | ||
{ | ||
return cellMaterial == CM_AIR; | ||
} | ||
|
||
inline bool3 isSolidCell(uint3 cellMaterial) | ||
{ | ||
return cellMaterial == (uint3)CM_SOLID; | ||
} | ||
inline bool3 isFluidCell(uint3 cellMaterial) | ||
{ | ||
return cellMaterial == (uint3)CM_FLUID; | ||
} | ||
inline bool3 isAirCell(uint3 cellMaterial) | ||
{ | ||
return cellMaterial == (uint3)CM_AIR; | ||
} | ||
|
||
void enforceBoundaryCondition(inout float3 velocity, uint cellMaterial) | ||
{ | ||
bool3 is_solid_cell = | ||
or((bool3)isSolidCell(getCellMaterial(cellMaterial)), | ||
bool3(isSolidCell(getXPrevMaterial(cellMaterial)), isSolidCell(getYPrevMaterial(cellMaterial)), isSolidCell(getZPrevMaterial(cellMaterial)))); | ||
Comment on lines
+168
to
+170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. general algorithm question, is this a staggered grid?
and the solid flags are kept between cells? |
||
velocity = select(is_solid_cell, 0.0f, velocity); | ||
} | ||
|
||
// handling solid obstacles | ||
inline bool3 isSolidCell(float3 position) | ||
{ | ||
// no obstacles for now, in cuboid sim area | ||
return false; | ||
} | ||
|
||
#endif | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#ifndef _FLIP_EXAMPLE_COMMON_HLSL | ||
#define _FLIP_EXAMPLE_COMMON_HLSL | ||
|
||
#include "nbl/builtin/hlsl/cpp_compat.hlsl" | ||
|
||
#define NUM_THREADS 128 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 512 is probably better because then for 3D you can do 8x8x8 workgroups There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. eh, so you made WorkgroupGridDim 8, but kept 128 here!? |
||
|
||
NBL_CONSTEXPR uint32_t WorkgroupSize = NUM_THREADS; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's usually no need to have it as a define |
||
NBL_CONSTEXPR float ratioFLIPPIC = 0.95; | ||
NBL_CONSTEXPR float deltaTime = 1.0f / 60.0f; | ||
NBL_CONSTEXPR float gravity = 15.0f; | ||
|
||
#ifdef __HLSL_VERSION | ||
|
||
static const float FLT_MIN = 1.175494351e-38; | ||
static const float FLT_MAX = 3.402823466e+38; | ||
Comment on lines
+14
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. slight nitpick, we have this https://github.com/Devsh-Graphics-Programming/Nabla/blob/master/include/nbl/builtin/hlsl/limits.hlsl because there's no constexpr functions in HLSL and constexpr float variables were introduced in C++20 the usage is numeric_limits<float>::min; |
||
|
||
struct Particle | ||
{ | ||
float4 position; | ||
float4 velocity; | ||
|
||
uint id; | ||
uint pad[3]; | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
even if for some reason you assumed you must use std430 layout rules, would have expected float32_t3 position;
uint32_t id;
float32_t3 velocity;
uint32_t pad; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's even the need to keep an Also, because only certain shaders/dispatches only access certain properties of a particle, not everyone needs to know the Therefore I'd use "Structure of Arrays" rather than "Array of Structures", this will lead to better cache utilization and better perf struct Particles
{
nbl::hlsl::BdaAccessor<float32_t3> positions;
nbl::hlsl::BdaAccessor<float32_t3> velocities;
}; with BDA of course P.S. Sidenote it also looks like maaaybe Storage Texel Buffers ( P.P.S. More optimization discussion, since positions are always relative to the grid, they could be a custom UNORM format, e.g. 21,22,21 in a |
||
|
||
struct SMVPParams | ||
{ | ||
float4 camPos; | ||
|
||
float4x4 MVP; | ||
float4x4 M; | ||
float4x4 V; | ||
Comment on lines
+27
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. non projective matrices are |
||
float4x4 P; | ||
}; | ||
#endif | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#include "../common.hlsl" | ||
#include "../gridSampling.hlsl" | ||
#include "../descriptor_bindings.hlsl" | ||
|
||
[[vk::binding(b_apGridData, s_ap)]] | ||
cbuffer GridData | ||
{ | ||
SGridData gridData; | ||
}; | ||
Comment on lines
+13
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We tend to use BDA for everything but this is actually a use of an UBO I can commend, globals that don't change, ever (although it would probably fit in push constants - which are slightly faster) |
||
|
||
[[vk::binding(b_apPBuffer, s_ap)]] RWStructuredBuffer<Particle> particleBuffer; | ||
[[vk::binding(b_apVelFieldBuffer, s_ap)]] Texture3D<float4> velocityFieldBuffer; | ||
[[vk::binding(b_apVelSampler, s_ap)]] SamplerState velocityFieldSampler; | ||
|
||
// delta time push constant? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good idea. |
||
|
||
[numthreads(WorkgroupSize, 1, 1)] | ||
void main(uint32_t3 ID : SV_DispatchThreadID) | ||
{ | ||
uint32_t pid = ID.x; | ||
Comment on lines
+26
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we have |
||
|
||
Particle p = particleBuffer[pid]; | ||
|
||
// use RK4 | ||
float3 k1 = sampleVelocityAt(p.position.xyz, velocityFieldBuffer, velocityFieldSampler, gridData); | ||
float3 k2 = sampleVelocityAt(p.position.xyz + k1 * 0.5f * deltaTime, velocityFieldBuffer, velocityFieldSampler, gridData); | ||
float3 k3 = sampleVelocityAt(p.position.xyz + k2 * 0.5f * deltaTime, velocityFieldBuffer, velocityFieldSampler, gridData); | ||
float3 k4 = sampleVelocityAt(p.position.xyz + k3 * deltaTime, velocityFieldBuffer, velocityFieldSampler, gridData); | ||
float3 velocity = (k1 + 2.0f * k2 + 2.0f * k3 + k4) / 6.0f; | ||
|
||
p.position.xyz += velocity * deltaTime; | ||
|
||
p.position = clampPosition(p.position, gridData.worldMin, gridData.worldMax); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wouldn't you want to reflect/bounce the particle off the wall (with some dampening ofc) instead of making it come to an abrupt stop? |
||
|
||
particleBuffer[pid] = p; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#include "../common.hlsl" | ||
#include "../gridUtils.hlsl" | ||
#include "../cellUtils.hlsl" | ||
#include "../descriptor_bindings.hlsl" | ||
|
||
[[vk::binding(b_abfGridData, s_abf)]] | ||
cbuffer GridData | ||
{ | ||
SGridData gridData; | ||
}; | ||
|
||
[[vk::binding(b_abfVelFieldBuffer, s_abf)]] RWTexture3D<float4> velocityFieldBuffer; | ||
[[vk::binding(b_abfCMBuffer, s_abf)]] RWStructuredBuffer<uint> cellMaterialBuffer; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also I see your cell material data could actually fit in a |
||
|
||
[numthreads(WorkgroupSize, 1, 1)] | ||
void main(uint32_t3 ID : SV_DispatchThreadID) | ||
{ | ||
// only gravity for now | ||
uint c_id = ID.x; | ||
int3 cIdx = flatIdxToCellIdx(c_id, gridData.gridSize); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when doing compute over 3D textures, you shall use 3D dispatches with workgroup size 8x8x8 |
||
|
||
float3 velocity = velocityFieldBuffer[cIdx].xyz; | ||
velocity += float3(0, -1, 0) * gravity * deltaTime; | ||
|
||
enforceBoundaryCondition(velocity, cellMaterialBuffer[c_id]); | ||
|
||
velocityFieldBuffer[cIdx].xyz = velocity; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this could have been kernel fusioned with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also HLSL has enums