diff options
-rw-r--r-- | src/buffer/vertex/fluid_cell_buffer.cc | 12 | ||||
-rw-r--r-- | src/buffer/vertex/fluid_cell_buffer.h | 1 | ||||
-rw-r--r-- | src/main.cc | 64 | ||||
-rw-r--r-- | src/shader/code/extra.glsl | 53 | ||||
-rw-r--r-- | src/shader/code/interact.glsl | 2 | ||||
-rw-r--r-- | src/shader/code/vertex.glsl | 52 |
6 files changed, 164 insertions, 20 deletions
diff --git a/src/buffer/vertex/fluid_cell_buffer.cc b/src/buffer/vertex/fluid_cell_buffer.cc index 8fdc579..d9af989 100644 --- a/src/buffer/vertex/fluid_cell_buffer.cc +++ b/src/buffer/vertex/fluid_cell_buffer.cc @@ -5,11 +5,8 @@ FluidCellBuffer::FluidCellBuffer(GLuint nX, GLuint nY, std::function<int(int,int)>&& geometry): _nX(nX), _nY(nY) { glGenBuffers(1, &_buffer); - glBindVertexArray(_array); + enable(); init(std::forward<decltype(geometry)>(geometry)); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - } FluidCellBuffer::~FluidCellBuffer() { @@ -17,9 +14,14 @@ FluidCellBuffer::~FluidCellBuffer() { glDeleteVertexArrays(1, &_array); } -void FluidCellBuffer::init(std::function<int(int,int)>&& geometry) { +void FluidCellBuffer::enable() { + glBindVertexArray(_array); glBindBuffer(GL_ARRAY_BUFFER, _buffer); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); +} +void FluidCellBuffer::init(std::function<int(int,int)>&& geometry) { std::vector<GLfloat> data(3*_nX*_nY, GLfloat{}); for ( int x = 0; x < _nX; ++x ) { diff --git a/src/buffer/vertex/fluid_cell_buffer.h b/src/buffer/vertex/fluid_cell_buffer.h index 791ebea..5148606 100644 --- a/src/buffer/vertex/fluid_cell_buffer.h +++ b/src/buffer/vertex/fluid_cell_buffer.h @@ -16,6 +16,7 @@ public: FluidCellBuffer(GLuint nX, GLuint nY, std::function<int(int,int)>&& geometry); ~FluidCellBuffer(); + void enable(); void init(std::function<int(int,int)>&& geometry); GLuint getBuffer() const; diff --git a/src/main.cc b/src/main.cc index 394248c..a98ca44 100644 --- a/src/main.cc +++ b/src/main.cc @@ -20,6 +20,7 @@ #include "shader/code/interact.glsl" #include "shader/code/collide.glsl" +#include "shader/code/extra.glsl" #include "timer.h" @@ -27,6 +28,12 @@ GLuint maxLUPS = 100; GLuint nX = 512; GLuint nY = 256; +enum DisplayMode { + VELOCITY, + QUALITY, + CURL +}; + float getWorldHeight(int window_width, int window_height, float world_width) { return world_width / window_width * window_height; } @@ -84,9 +91,11 @@ int render() { std::unique_ptr<LatticeCellBuffer> lattice_a; std::unique_ptr<LatticeCellBuffer> lattice_b; std::unique_ptr<FluidCellBuffer> fluid; + std::unique_ptr<FluidCellBuffer> extra; std::unique_ptr<ComputeShader> interact_shader; std::unique_ptr<ComputeShader> collide_shader; + std::unique_ptr<ComputeShader> extra_shader; window.init([&]() { scene_shader = std::make_unique<GraphicShader>( @@ -94,9 +103,11 @@ int render() { lattice_a = std::make_unique<LatticeCellBuffer>(nX, nY); lattice_b = std::make_unique<LatticeCellBuffer>(nX, nY); + extra = std::make_unique< FluidCellBuffer>(nX, nY, setupOpenGeometry); fluid = std::make_unique< FluidCellBuffer>(nX, nY, setupOpenGeometry); interact_shader = std::make_unique<ComputeShader>(INTERACT_SHADER_CODE); + extra_shader = std::make_unique<ComputeShader>(EXTRA_SHADER_CODE); collide_shader = std::make_unique<ComputeShader>(COLLIDE_SHADER_CODE); }); @@ -110,8 +121,10 @@ int render() { auto pause_key = window.getKeyWatcher(GLFW_KEY_SPACE); bool update_lattice = true; - auto toggle_key = window.getKeyWatcher(GLFW_KEY_T); - bool show_fluid_quality = false; + auto velocity_mode_key = window.getKeyWatcher(GLFW_KEY_V); + auto quality_mode_key = window.getKeyWatcher(GLFW_KEY_Q); + auto curl_mode_key = window.getKeyWatcher(GLFW_KEY_C); + DisplayMode display_mode = DisplayMode::VELOCITY; auto palette_factor_incr = window.getKeyWatcher(GLFW_KEY_UP); auto palette_factor_decr = window.getKeyWatcher(GLFW_KEY_DOWN); @@ -125,8 +138,8 @@ int render() { float currLatticeMouseX; float currLatticeMouseY; - 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(), extra->getBuffer() }; + auto tock_buffers = { lattice_b->getBuffer(), lattice_a->getBuffer(), fluid->getBuffer(), extra->getBuffer() }; GLuint iT = 0; int statLUPS = 0; @@ -146,14 +159,22 @@ int render() { update_lattice = !update_lattice; } - if ( toggle_key.wasClicked() ) { - show_fluid_quality = !show_fluid_quality; + if ( velocity_mode_key.wasClicked() ) { + display_mode = DisplayMode::VELOCITY; + fluid->enable(); + } + if ( quality_mode_key.wasClicked() ) { + display_mode = DisplayMode::QUALITY; + fluid->enable(); + } + if ( curl_mode_key.wasClicked() ) { + display_mode = DisplayMode::CURL; + extra->enable(); } if ( palette_factor_incr.wasClicked() ) { palette_factor += 1; } - if ( palette_factor_decr.wasClicked() ) { palette_factor -= 1; } @@ -175,10 +196,12 @@ int render() { if ( tick ) { interact_shader->workOn(tick_buffers); collide_shader->workOn(tick_buffers); + extra_shader->workOn(tick_buffers); tick = false; } else { interact_shader->workOn(tock_buffers); collide_shader->workOn(tock_buffers); + extra_shader->workOn(tock_buffers); tick = true; } @@ -186,13 +209,18 @@ int render() { { auto guard = collide_shader->use(); - collide_shader->setUniform("show_fluid_quality", show_fluid_quality); + collide_shader->setUniform("show_fluid_quality", display_mode == DisplayMode::QUALITY); collide_shader->setUniform("iT", iT); iT += 1; collide_shader->dispatch(nX, nY); } + if ( display_mode == DisplayMode::CURL ) { + auto guard = extra_shader->use(); + extra_shader->dispatch(nX, nY); + } + last_lattice_update = timer::now(); } @@ -228,11 +256,27 @@ int render() { scene_shader->setUniform("MVP", MVP); scene_shader->setUniform("nX", nX); scene_shader->setUniform("nY", nY); - scene_shader->setUniform("show_fluid_quality", show_fluid_quality); scene_shader->setUniform("palette_factor", palette_factor); glClear(GL_COLOR_BUFFER_BIT); - fluid->draw(); + + switch ( display_mode ) { + case DisplayMode::VELOCITY: + scene_shader->setUniform("show_fluid_quality", false); + scene_shader->setUniform("show_curl", false); + fluid->draw(); + break; + case DisplayMode::QUALITY: + scene_shader->setUniform("show_fluid_quality", true); + scene_shader->setUniform("show_curl", false); + fluid->draw(); + break; + case DisplayMode::CURL: + scene_shader->setUniform("show_fluid_quality", false); + scene_shader->setUniform("show_curl", true); + extra->draw(); + break; + } } }); diff --git a/src/shader/code/extra.glsl b/src/shader/code/extra.glsl new file mode 100644 index 0000000..5ba6207 --- /dev/null +++ b/src/shader/code/extra.glsl @@ -0,0 +1,53 @@ +static const std::string EXTRA_SHADER_CODE = R"( +#version 430 + +layout (local_size_x = 1, local_size_y = 1) in; + +layout (std430, binding=3) buffer bufferFluid { float fluidCells[]; }; +layout (std430, binding=4) buffer bufferExtra { float extraCells[]; }; + +uniform uint nX; +uniform uint nY; + +const float convLength = 1.0 / float(max(nX,nY)); + +/// Array indexing + +uint indexOfDirection(int i, int j) { + return 3*(i+1) + (j+1); +} + +uint indexOfFluidVertex(uint x, uint y) { + return 3*nX*y + 3*x; +} + +/// Data access + +vec2 getFluidVelocity(uint x, uint y) { + const uint idx = indexOfFluidVertex(x, y); + return vec2( + fluidCells[idx + 0], + fluidCells[idx + 1] + ); +} + +void setFluidExtra(uint x, uint y, float curl) { + const uint idx = indexOfFluidVertex(x, y); + extraCells[idx + 0] = curl; +} + +void main() { + const uint x = gl_GlobalInvocationID.x; + const uint y = gl_GlobalInvocationID.y; + + if ( !(x < nX && y < nY) ) { + return; + } + + // simple central difference discretization of the 2d curl operator + const float dxvy = (getFluidVelocity(x+1,y).y - getFluidVelocity(x-1,y).y) / (2*convLength); + const float dyvx = (getFluidVelocity(x,y+1).x - getFluidVelocity(x,y-1).x) / (2*convLength); + + setFluidExtra(x, y, dxvy - dyvx); +} +)"; diff --git a/src/shader/code/interact.glsl b/src/shader/code/interact.glsl index 613c4cd..141673a 100644 --- a/src/shader/code/interact.glsl +++ b/src/shader/code/interact.glsl @@ -4,6 +4,7 @@ static const std::string INTERACT_SHADER_CODE = R"( layout (local_size_x = 1, local_size_y = 1) in; layout (std430, binding=3) buffer bufferFluid { float fluidCells[]; }; +layout (std430, binding=4) buffer bufferExtra { float extraCells[]; }; uniform uint nX; uniform uint nY; @@ -62,6 +63,7 @@ int getMaterial(uint x, uint y) { void setMaterial(uint x, uint y, int m) { const uint idx = indexOfFluidVertex(x, y); fluidCells[idx + 2] = m; + extraCells[idx + 2] = m; } /// Geometry cleanup diff --git a/src/shader/code/vertex.glsl b/src/shader/code/vertex.glsl index 0f0e07c..5136023 100644 --- a/src/shader/code/vertex.glsl +++ b/src/shader/code/vertex.glsl @@ -11,6 +11,7 @@ uniform uint nX; uniform uint nY; uniform bool show_fluid_quality; +uniform bool show_curl; uniform int palette_factor; float unit(float x) { @@ -65,6 +66,38 @@ vec3 trafficLightPalette(float x) { } } +vec3 blueBlackRedPalette(float x) { + if ( x < 0.5 ) { + return mix( + vec3(0.0, 0.0, 1.0), + vec3(0.0, 0.0, 0.0), + 2*x + ); + } else { + return mix( + vec3(0.0, 0.0, 0.0), + vec3(1.0, 0.0, 0.0), + 2*(x - 0.5) + ); + } +} + +vec3 blackGoldPalette(float x) { + return mix( + vec3(0.0, 0.0, 0.0), + vec3(0.5, 0.35, 0.05), + x + ); +} + +vec3 blueRedPalette(float x) { + return mix( + vec3(0.0, 0.0, 1.0), + vec3(1.0, 0.0, 0.0), + x + ); +} + void main() { const vec2 idx = fluidVertexAtIndex(gl_VertexID); @@ -83,12 +116,21 @@ void main() { vs_out.color = vec3(0.0, 0.0, 0.0); } else { if ( show_fluid_quality ) { - vs_out.color = trafficLightPalette(restrictedQuality(VertexPosition.y)); + vs_out.color = trafficLightPalette( + restrictedQuality(VertexPosition.y) + ); + } else if ( show_curl ) { + const float factor = 1.0 / float(100*palette_factor); + if ( abs(VertexPosition.x) > 1.0 ) { + vs_out.color = blueBlackRedPalette( + 0.5 + (VertexPosition.x * factor) + ); + } else { + 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), - norm(VertexPosition.xy) / float(palette_factor) + vs_out.color = blueRedPalette( + norm(VertexPosition.xy) / palette_factor ); } } |