From f0b536ac93b3a9a49dfff8a7637f09b153a3b955 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Fri, 22 Feb 2019 21:49:07 +0100 Subject: Improvise interactive wall drawing Internal wall cells need to be disabled to prevent delayed propagation of the reflected populations. This is just quickly thrown together - both the visual drawing and the backend's material handling remain to be improved. --- src/buffer/vertex/material_buffer.cc | 51 ++++++++++++++++++++++++ src/buffer/vertex/material_buffer.h | 18 +++++++++ src/glfw/window.cc | 11 ++++-- src/glfw/window.h | 2 +- src/main.cc | 7 +++- src/shader/code/collide.glsl | 75 +++++++++++++++++++++++++----------- src/shader/code/stream.glsl | 15 ++++++-- src/shader/code/vertex.glsl | 16 +++++--- 8 files changed, 157 insertions(+), 38 deletions(-) create mode 100644 src/buffer/vertex/material_buffer.cc create mode 100644 src/buffer/vertex/material_buffer.h (limited to 'src') diff --git a/src/buffer/vertex/material_buffer.cc b/src/buffer/vertex/material_buffer.cc new file mode 100644 index 0000000..82ccea2 --- /dev/null +++ b/src/buffer/vertex/material_buffer.cc @@ -0,0 +1,51 @@ +#include "material_buffer.h" + +#include + +MaterialBuffer::MaterialBuffer(GLuint nX, GLuint nY): + _nX(nX), _nY(nY) { + glGenVertexArrays(1, &_array); + glGenBuffers(1, &_buffer); + + glBindVertexArray(_array); + glBindBuffer(GL_ARRAY_BUFFER, _buffer); + + std::vector data(nX*nY, GLint{1}); + + for ( int x = 0; x < nX; ++x ) { + data[ 0*nX + x] = 0; + data[(nY-1)*nX + x] = 0; + } + for ( int y = 0; y < nY; ++y ) { + data[y*nX + 0] = 0; + data[y*nX + nX-1] = 0; + } + + for ( int x = 1; x < nX-1; ++x ) { + data[ 1*nX + x] = 2; + data[(nY-2)*nX + x] = 2; + } + for ( int y = 1; y < nY-1; ++y ) { + data[y*nX + 1] = 2; + data[y*nX + nX-2] = 2; + } + + glBufferData( + GL_ARRAY_BUFFER, + data.size() * sizeof(GLint), + data.data(), + GL_STATIC_DRAW + ); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, nullptr); +} + +MaterialBuffer::~MaterialBuffer() { + glDeleteBuffers(1, &_buffer); + glDeleteVertexArrays(1, &_array); +} + +GLuint MaterialBuffer::getBuffer() const { + return _buffer; +} diff --git a/src/buffer/vertex/material_buffer.h b/src/buffer/vertex/material_buffer.h new file mode 100644 index 0000000..eccf008 --- /dev/null +++ b/src/buffer/vertex/material_buffer.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class MaterialBuffer { +private: + const GLuint _nX; + const GLuint _nY; + + GLuint _array; + GLuint _buffer; + +public: + MaterialBuffer(GLuint nX, GLuint nY); + ~MaterialBuffer(); + + GLuint getBuffer() const; +}; diff --git a/src/glfw/window.cc b/src/glfw/window.cc index 98890b7..4f14501 100644 --- a/src/glfw/window.cc +++ b/src/glfw/window.cc @@ -37,14 +37,19 @@ int Window::getHeight() const { return _height; } -std::tuple Window::getMouse() const { - const bool clicked = glfwGetMouseButton(_handle, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; +std::tuple Window::getMouse() const { + int state = 0; + if ( glfwGetMouseButton(_handle, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS ) { + state = 1; + } else if ( glfwGetMouseButton(_handle, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS ) { + state = 2; + } double x, y; glfwGetCursorPos(_handle, &x, &y); return std::make_tuple( - clicked, + state, x - int(getWidth()/2), int(getHeight()/2 - y) ); diff --git a/src/glfw/window.h b/src/glfw/window.h index af7ba4d..143d457 100644 --- a/src/glfw/window.h +++ b/src/glfw/window.h @@ -27,7 +27,7 @@ public: int getWidth() const; int getHeight() const; - std::tuple getMouse() const; + std::tuple getMouse() const; KeyWatcher getKeyWatcher(int key) const; diff --git a/src/main.cc b/src/main.cc index 3048979..0a400a5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -10,6 +10,7 @@ #include "buffer/vertex/fluid_cell_buffer.h" #include "buffer/vertex/lattice_cell_buffer.h" +#include "buffer/vertex/material_buffer.h" #include "shader/wrap/graphic_shader.h" #include "shader/wrap/compute_shader.h" @@ -66,6 +67,7 @@ int renderWindow() { std::unique_ptr lattice_a; std::unique_ptr lattice_b; std::unique_ptr fluid; + std::unique_ptr geometry; std::unique_ptr collide_shader; std::unique_ptr stream_shader; @@ -77,6 +79,7 @@ int renderWindow() { lattice_a = std::make_unique(nX, nY); lattice_b = std::make_unique(nX, nY); fluid = std::make_unique< FluidCellBuffer>(nX, nY); + geometry = std::make_unique< MaterialBuffer>(nX, nY); collide_shader = std::make_unique(COLLIDE_SHADER_CODE); stream_shader = std::make_unique(STREAM_SHADER_CODE); @@ -94,8 +97,8 @@ int renderWindow() { auto pause_key = window.getKeyWatcher(GLFW_KEY_SPACE); - auto tick_buffers = { lattice_a->getBuffer(), lattice_b->getBuffer(), fluid->getBuffer() }; - auto tock_buffers = { lattice_b->getBuffer(), lattice_a->getBuffer(), fluid->getBuffer() }; + auto tick_buffers = { lattice_a->getBuffer(), lattice_b->getBuffer(), fluid->getBuffer(), geometry->getBuffer() }; + auto tock_buffers = { lattice_b->getBuffer(), lattice_a->getBuffer(), fluid->getBuffer(), geometry->getBuffer() }; window.render([&](bool window_size_changed) { if ( pause_key.wasClicked() ) { diff --git a/src/shader/code/collide.glsl b/src/shader/code/collide.glsl index cb950cb..b58bec3 100644 --- a/src/shader/code/collide.glsl +++ b/src/shader/code/collide.glsl @@ -3,9 +3,10 @@ static const std::string COLLIDE_SHADER_CODE = R"( layout (local_size_x = 1, local_size_y = 1) in; -layout (std430, binding=1) buffer bufferCollide{ float collideCells[]; }; -layout (std430, binding=2) buffer bufferStream{ float streamCells[]; }; -layout (std430, binding=3) buffer bufferFluid{ float fluidCells[]; }; +layout (std430, binding=1) buffer bufferCollide { float collideCells[]; }; +layout (std430, binding=2) buffer bufferStream { float streamCells[]; }; +layout (std430, binding=3) buffer bufferFluid { float fluidCells[]; }; +layout (std430, binding=4) buffer bufferGeometry { int materialCells[]; }; /// external influence @@ -76,6 +77,22 @@ void setFluid(uint x, uint y, vec2 v, float d) { fluidCells[idx + 2] = d; } +int getMaterial(uint x, uint y) { + return materialCells[nX*y + x]; +} + +void setMaterial(uint x, uint y, int m) { + materialCells[nX*y + x] = m; +} + +void disableFluid(uint x, uint y) { + const uint idx = indexOfFluidVertex(x, y); + fluidCells[idx + 0] = 0.0; + fluidCells[idx + 1] = 0.0; + fluidCells[idx + 2] = -2.0; +} + + /// Moments float density(uint x, uint y) { @@ -103,21 +120,19 @@ float equilibrium(float d, vec2 v, int i, int j) { /// Determine external influence float getExternalPressureInflux(uint x, uint y) { - if ( mouseState == 1 && norm(vec2(x,y) - mousePos) < 4 ) { + if ( mouseState == 1 && norm(vec2(x,y) - mousePos) < 2 ) { return 1.5; } else { return 0.0; } } -/// Domain description - -bool isEndOfWorld(uint x, uint y) { - return x == 0 || x == nX-1 || y == 0 || y == nY-1; -} - -bool isOuterWall(uint x, uint y) { - return x == 1 || x == nX-2 || y == 1 || y == nY-2; +bool getExternalWallRequest(uint x, uint y) { + if ( mouseState == 2 && norm(vec2(x,y) - mousePos) < 4 ) { + return true; + } else { + return false; + } } /// Actual collide kernel @@ -130,22 +145,38 @@ void main() { return; } - if ( isEndOfWorld(x,y) ) { - return; + if ( getExternalWallRequest(x,y) ) { + setMaterial(x,y,2); + disableFluid(x,y); } - if ( isOuterWall(x,y) ) { - return; + const int material = getMaterial(x,y); + + if ( material == 2 ) { + 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 ) { + ++wallNeighbors; + } + } + } + if ( wallNeighbors == 9 ) { + setMaterial(x,y,0); + } } - const float d = max(getExternalPressureInflux(x,y), density(x,y)); - const vec2 v = velocity(x,y,d); + if ( material == 1 ) { // fluid + const float d = max(getExternalPressureInflux(x,y), density(x,y)); + const vec2 v = velocity(x,y,d); - setFluid(x,y,v,d); + setFluid(x,y,v,d); - for ( int i = -1; i <= 1; ++i ) { - for ( int j = -1; j <= 1; ++j ) { - set(x,y,i,j, get(x,y,i,j) + omega * (equilibrium(d,v,i,j) - get(x,y,i,j))); + for ( int i = -1; i <= 1; ++i ) { + for ( int j = -1; j <= 1; ++j ) { + set(x,y,i,j, get(x,y,i,j) + omega * (equilibrium(d,v,i,j) - get(x,y,i,j))); + } } } } diff --git a/src/shader/code/stream.glsl b/src/shader/code/stream.glsl index 345127d..a8aec1d 100644 --- a/src/shader/code/stream.glsl +++ b/src/shader/code/stream.glsl @@ -3,8 +3,9 @@ static const std::string STREAM_SHADER_CODE = R"( layout (local_size_x = 1, local_size_y = 1) in; -layout (std430, binding=1) buffer bufferCollide{ float collideCells[]; }; -layout (std430, binding=2) buffer bufferStream{ float streamCells[]; }; +layout (std430, binding=1) buffer bufferCollide { float collideCells[]; }; +layout (std430, binding=2) buffer bufferStream { float streamCells[]; }; +layout (std430, binding=4) buffer bufferGeometry { int materialCells[]; }; /// LBM constants @@ -33,6 +34,10 @@ void set(uint x, uint y, int i, int j, float v) { streamCells[indexOfLatticeCell(x,y) + indexOfDirection(i,j)] = v; } +int getMaterial(uint x, uint y) { + return materialCells[nX*y + x]; +} + /// Domain description bool isEndOfWorld(uint x, uint y) { @@ -63,11 +68,13 @@ void main() { return; } - if ( isEndOfWorld(x,y) ) { + const int material = getMaterial(x,y); + + if ( material == 0 ) { return; } - if ( isOuterWall(x,y) ) { + if ( material == 2 ) { bounceBack(x,y); } diff --git a/src/shader/code/vertex.glsl b/src/shader/code/vertex.glsl index 700a9b7..52d9403 100644 --- a/src/shader/code/vertex.glsl +++ b/src/shader/code/vertex.glsl @@ -10,7 +10,7 @@ out VS_OUT { uniform uint nX; uniform uint nY; -const float displayAmplifier = 5.0; +const float displayAmplifier = 50.0; float unit(float x) { return 1.0/(1.0+exp(-x)); @@ -42,10 +42,14 @@ void main() { 1. ); - vs_out.color = mix( - vec3(-0.5, 0.0, 1.0), - vec3( 1.0, 0.0, 0.0), - displayAmplifier * VertexPosition.z * norm(VertexPosition.xy) - ); + if ( VertexPosition.z < -1.0 ) { + vs_out.color = vec3(0.0, 0.0, 0.0); + } else { + vs_out.color = mix( + vec3(-0.5, 0.0, 1.0), + vec3( 1.0, 0.0, 0.0), + displayAmplifier * VertexPosition.z * norm(VertexPosition.xy) + ); + } } )"; -- cgit v1.2.3