From 2d97364b3cdf1354e5b60807732d447217436523 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Sun, 24 Feb 2019 13:02:14 +0100 Subject: Extract interaction logic into separate shader The collide shader became to crowded for my taste. As a nice side benefit we can now execute interaction processing only when actual interaction is taking place. --- src/shader/code/collide.glsl | 84 +++------------------------- src/shader/code/interact.glsl | 127 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 76 deletions(-) create mode 100644 src/shader/code/interact.glsl (limited to 'src/shader/code') diff --git a/src/shader/code/collide.glsl b/src/shader/code/collide.glsl index a73024e..0ddae7b 100644 --- a/src/shader/code/collide.glsl +++ b/src/shader/code/collide.glsl @@ -7,13 +7,6 @@ layout (std430, binding=1) buffer bufferCollide { float collideCells[]; }; layout (std430, binding=2) buffer bufferStream { float streamCells[]; }; layout (std430, binding=3) buffer bufferFluid { float fluidCells[]; }; -/// external influence - -uniform int prevMouseState; -uniform vec2 prevMousePos; -uniform int currMouseState; -uniform vec2 currMousePos; - /// LBM constants uniform uint nX; @@ -43,22 +36,6 @@ float norm(vec2 v) { return sqrt(dot(v,v)); } -float distanceToLineSegment(vec2 a, vec2 b, vec2 p) { - const vec2 ab = b - a; - - const vec2 pa = a - p; - if ( dot(ab, pa) > 0.0 ) { - return norm(pa); - } - - const vec2 bp = p - b; - if ( dot(ab, bp) > 0.0 ) { - return norm(bp); - } - - return norm(pa - ab * (dot(ab, pa) / dot(ab, ab))); -} - /// Array indexing uint indexOfDirection(int i, int j) { @@ -98,11 +75,6 @@ int getMaterial(uint x, uint y) { return int(fluidCells[idx + 2]); } -void setMaterial(uint x, uint y, int m) { - const uint idx = indexOfFluidVertex(x, y); - fluidCells[idx + 2] = m; -} - /// Moments float density(uint x, uint y) { @@ -127,50 +99,19 @@ float equilibrium(float d, vec2 v, int i, int j) { return w(i,j) * d * (1 + 3*comp(i,j,v) + 4.5*sq(comp(i,j,v)) - 1.5*sq(norm(v))); } -/// Disable wall interior - -void disableWallInterior(uint x, uint y) { - int wallNeighbors = 0; - - for ( int i = -1; i <= 1; ++i ) { - for ( int j = -1; j <= 1; ++j ) { - const int material = getMaterial(x+i,y+j); - if ( material == 0 || material == 2 || material == 3 ) { - ++wallNeighbors; - } - } - } +/// Material number meaning (geometry is only changed by the interaction shader) - if ( wallNeighbors == 9 ) { - setMaterial(x,y,0); - } -} - -/// Determine external influence - -bool isNearMouse(uint x, uint y, float eps) { - if ( prevMouseState == currMouseState ) { - return distanceToLineSegment(prevMousePos, currMousePos, vec2(x,y)) < eps; - } else { - return norm(vec2(x,y) - currMousePos) < eps; - } +bool isBulkFluidCell(int material) { + return material == 1 || material == 4; } -float getExternalPressureInflux(uint x, uint y) { - if ( currMouseState == 1 && isNearMouse(x, y, 3) ) { +float getExternalMassInflux(int material) { + if ( material == 4 ) { return 1.5; } else { return 0.0; } -} - -bool isWallRequestedAt(uint x, uint y) { - if ( currMouseState == 2 && isNearMouse(x, y, 3) ) { - return true; - } else { - return false; - } -} +}; /// Actual collide kernel @@ -184,17 +125,8 @@ void main() { const int material = getMaterial(x,y); - if ( isWallRequestedAt(x,y) && material == 1 ) { - setMaterial(x,y,3); - return; - } - - if ( material == 3 ) { // manually added wall - disableWallInterior(x,y); - } - - if ( material == 1 ) { // fluid - const float d = max(getExternalPressureInflux(x,y), density(x,y)); + if ( isBulkFluidCell(material) ) { + const float d = max(density(x,y), getExternalMassInflux(material)); const vec2 v = velocity(x,y,d); setFluid(x,y,v); diff --git a/src/shader/code/interact.glsl b/src/shader/code/interact.glsl new file mode 100644 index 0000000..a65d96a --- /dev/null +++ b/src/shader/code/interact.glsl @@ -0,0 +1,127 @@ +static const std::string INTERACT_SHADER_CODE = R"( +#version 430 + +layout (local_size_x = 1, local_size_y = 1) in; + +layout (std430, binding=3) buffer bufferFluid { float fluidCells[]; }; + +uniform uint nX; +uniform uint nY; + +/// External influence + +uniform int prevMouseState; +uniform vec2 prevMousePos; +uniform int currMouseState; +uniform vec2 currMousePos; + +/// Vector utilities + +float norm(vec2 v) { + return sqrt(dot(v,v)); +} + +float distanceToLineSegment(vec2 a, vec2 b, vec2 p) { + const vec2 ab = b - a; + + const vec2 pa = a - p; + if ( dot(ab, pa) > 0.0 ) { + return norm(pa); + } + + const vec2 bp = p - b; + if ( dot(ab, bp) > 0.0 ) { + return norm(bp); + } + + return norm(pa - ab * (dot(ab, pa) / dot(ab, ab))); +} + +/// Array indexing + +uint indexOfFluidVertex(uint x, uint y) { + return 3*nX*y + 3*x; +} + +/// Data access + +int getMaterial(uint x, uint y) { + const uint idx = indexOfFluidVertex(x, y); + return int(fluidCells[idx + 2]); +} + +void setMaterial(uint x, uint y, int m) { + const uint idx = indexOfFluidVertex(x, y); + fluidCells[idx + 2] = m; +} + +/// Geometry cleanup + +void disableWallInterior(uint x, uint y) { + int wallNeighbors = 0; + + for ( int i = -1; i <= 1; ++i ) { + for ( int j = -1; j <= 1; ++j ) { + const int material = getMaterial(x+i,y+j); + if ( material == 0 || material == 2 || material == 3 ) { + ++wallNeighbors; + } + } + } + + if ( wallNeighbors == 9 ) { + setMaterial(x,y,0); + } +} + +/// Determine external influence + +bool isNearMouse(uint x, uint y, float eps) { + if ( prevMouseState == currMouseState ) { + return distanceToLineSegment(prevMousePos, currMousePos, vec2(x,y)) < eps; + } else { + return norm(vec2(x,y) - currMousePos) < eps; + } +} + +bool isInfluxRequestedAt(uint x, uint y) { + return currMouseState == 1 && isNearMouse(x, y, 3); +} + +bool isWallRequestedAt(uint x, uint y) { + return currMouseState == 2 && isNearMouse(x, y, 3); +} + +/// Actual interaction kernel + +void main() { + const uint x = gl_GlobalInvocationID.x; + const uint y = gl_GlobalInvocationID.y; + + if ( !(x < nX && y < nY) ) { + return; + } + + const int material = getMaterial(x,y); + + if ( material == 1 ) { + if ( isInfluxRequestedAt(x,y) ) { + setMaterial(x,y,4); + return; + } + if ( isWallRequestedAt(x,y) ) { + setMaterial(x,y,3); + return; + } + } + + if ( material == 3 ) { + disableWallInterior(x,y); + } + + if ( material == 4 ) { + // reset influx material after execution + setMaterial(x,y,1); + } +} +)"; -- cgit v1.2.3