aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2019-02-24 13:02:14 +0100
committerAdrian Kummerlaender2019-02-24 13:02:14 +0100
commit2d97364b3cdf1354e5b60807732d447217436523 (patch)
treeed53e8448671d7e2553b0bb0d5a4a462334c23de
parent1ab5f3db018a3169ad6074fc2b75d44c3a45dd16 (diff)
downloadcompustream-2d97364b3cdf1354e5b60807732d447217436523.tar
compustream-2d97364b3cdf1354e5b60807732d447217436523.tar.gz
compustream-2d97364b3cdf1354e5b60807732d447217436523.tar.bz2
compustream-2d97364b3cdf1354e5b60807732d447217436523.tar.lz
compustream-2d97364b3cdf1354e5b60807732d447217436523.tar.xz
compustream-2d97364b3cdf1354e5b60807732d447217436523.tar.zst
compustream-2d97364b3cdf1354e5b60807732d447217436523.zip
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.
-rw-r--r--src/main.cc33
-rw-r--r--src/shader/code/collide.glsl84
-rw-r--r--src/shader/code/interact.glsl127
3 files changed, 158 insertions, 86 deletions
diff --git a/src/main.cc b/src/main.cc
index 4621d30..2a3dd9b 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -18,6 +18,7 @@
#include "shader/code/vertex.glsl"
#include "shader/code/fragment.glsl"
+#include "shader/code/interact.glsl"
#include "shader/code/collide.glsl"
#include "shader/code/stream.glsl"
@@ -67,6 +68,7 @@ int renderWindow() {
std::unique_ptr<LatticeCellBuffer> lattice_b;
std::unique_ptr<FluidCellBuffer> fluid;
+ std::unique_ptr<ComputeShader> interact_shader;
std::unique_ptr<ComputeShader> collide_shader;
std::unique_ptr<ComputeShader> stream_shader;
@@ -87,11 +89,12 @@ int renderWindow() {
return 1; // everything shall be fluid
});
- collide_shader = std::make_unique<ComputeShader>(COLLIDE_SHADER_CODE);
- stream_shader = std::make_unique<ComputeShader>(STREAM_SHADER_CODE);
+ interact_shader = std::make_unique<ComputeShader>(INTERACT_SHADER_CODE);
+ collide_shader = std::make_unique<ComputeShader>(COLLIDE_SHADER_CODE);
+ stream_shader = std::make_unique<ComputeShader>(STREAM_SHADER_CODE);
});
- if ( !collide_shader->isGood() || !stream_shader->isGood() ) {
+ if ( !interact_shader->isGood() || !collide_shader->isGood() || !stream_shader->isGood() ) {
std::cerr << "Compute shader error." << std::endl;
return -1;
}
@@ -125,30 +128,40 @@ int renderWindow() {
if ( tick ) {
collide_shader->workOn(tick_buffers);
stream_shader->workOn(tick_buffers);
+ interact_shader->workOn(tick_buffers);
tick = false;
} else {
collide_shader->workOn(tock_buffers);
stream_shader->workOn(tock_buffers);
+ interact_shader->workOn(tock_buffers);
tick = true;
}
- {
- auto guard = collide_shader->use();
+ /// Handle mouse-based interaction
+ const auto m = window.getMouse();
- collide_shader->setUniform("prevMouseState", prevLatticeMouseState);
- collide_shader->setUniform("prevMousePos", prevLatticeMouseX, prevLatticeMouseY);
+ if ( std::get<0>(m) != 0 || prevLatticeMouseState != 0 ) {
+ auto guard = interact_shader->use();
+
+ interact_shader->setUniform("prevMouseState", prevLatticeMouseState);
+ interact_shader->setUniform("prevMousePos", prevLatticeMouseX, prevLatticeMouseY);
- const auto m = window.getMouse();
const float latticeMouseX = float(std::get<1>(m)) / window.getWidth() * world_width + nX/2;
const float latticeMouseY = float(std::get<2>(m)) / window.getHeight() * world_height + nY/2;
- collide_shader->setUniform("currMouseState", std::get<0>(m));
- collide_shader->setUniform("currMousePos", latticeMouseX, latticeMouseY);
+ interact_shader->setUniform("currMouseState", std::get<0>(m));
+ interact_shader->setUniform("currMousePos", latticeMouseX, latticeMouseY);
prevLatticeMouseState = std::get<0>(m);
prevLatticeMouseX = latticeMouseX;
prevLatticeMouseY = latticeMouseY;
+ interact_shader->dispatch(nX, nY);
+ }
+
+ /// Perform collide & stream steps
+ {
+ auto guard = collide_shader->use();
collide_shader->dispatch(nX, nY);
}
{
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);
+ }
+}
+)";