From 44f5ac32a68a617f93704d44c4339f7db13b323e Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Sat, 15 Dec 2018 23:09:32 +0100 Subject: Hacky D2Q9 BGK LBM on GPU using GLSL compute shaders Improvised on top of computicles's scaffolding. Works in a world where _works_ is defined as "displays stuff on screen that invokes thoughts of fluid movement". --- src/main.cc | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 src/main.cc (limited to 'src/main.cc') diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..914d505 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,156 @@ +#include +#include +#include + +#include +#include + +#include "glfw/guard.h" +#include "glfw/window.h" + +#include "buffer/vertex/fluid_cell_buffer.h" +#include "buffer/vertex/lattice_cell_buffer.h" + +#include "shader/wrap/graphic_shader.h" +#include "shader/wrap/compute_shader.h" + +#include "shader/code/vertex.glsl" +#include "shader/code/fragment.glsl" + +#include "shader/code/collide.glsl" +#include "shader/code/stream.glsl" + +#include "timer.h" + +float getWorldHeight(int window_width, int window_height, float world_width) { + return world_width / window_width * window_height; +} + +glm::mat4 getMVP(float world_width, float world_height) { + const glm::mat4 projection = glm::ortho( + -(world_width/2), world_width/2, + -(world_height/2), world_height/2, + 0.1f, 100.0f + ); + + const glm::mat4 view = glm::lookAt( + glm::vec3(0,0,1), + glm::vec3(0,0,0), + glm::vec3(0,1,0) + ); + + return projection * view; +} + +int renderWindow() { + Window window("compustream"); + + if ( !window.isGood() ) { + std::cerr << "Failed to open GLFW window." << std::endl; + return -1; + } + + int window_width = window.getWidth(); + int window_height = window.getHeight(); + + float world_width = 256.0; + float world_height = getWorldHeight(window_width, window_height, world_width); + + glm::mat4 MVP = getMVP(world_width, world_height); + + std::unique_ptr scene_shader; + + std::unique_ptr lattice_buffer_a; + std::unique_ptr lattice_buffer_b; + std::unique_ptr fluid_buffer; + + std::unique_ptr collide_shader; + std::unique_ptr stream_shader; + + window.init([&]() { + scene_shader = std::make_unique( + VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE); + + lattice_buffer_a = std::make_unique(); + lattice_buffer_b = std::make_unique(); + fluid_buffer = std::make_unique(); + + collide_shader = std::make_unique(COLLIDE_SHADER_CODE); + stream_shader = std::make_unique(STREAM_SHADER_CODE); + }); + + if ( !collide_shader->isGood() || !stream_shader->isGood() ) { + std::cerr << "Compute shader error. Check vector field definition." << std::endl; + return -1; + } + + auto last_frame = timer::now(); + + bool update_lattice = true; + bool tick = true; + + auto pause_key = window.getKeyWatcher(GLFW_KEY_SPACE); + + window.render([&]() { + if ( pause_key.wasClicked() ) { + update_lattice = !update_lattice; + } + + if ( window.getWidth() != window_width + || window.getHeight() != window_height ) { + window_width = window.getWidth(); + window_height = window.getHeight(); + glViewport(0, 0, window_width, window_height); + + world_height = getWorldHeight(window_width, window_height, world_width); + MVP = getMVP(world_width, world_height); + } + + if ( update_lattice ) { + if ( timer::millisecondsSince(last_frame) >= 1000/25 ) { + if ( tick ) { + collide_shader->workOn(lattice_buffer_a->getBuffer(), lattice_buffer_b->getBuffer(), fluid_buffer->getBuffer()); + stream_shader->workOn(lattice_buffer_a->getBuffer(), lattice_buffer_b->getBuffer(), fluid_buffer->getBuffer()); + tick = false; + } else { + collide_shader->workOn(lattice_buffer_b->getBuffer(), lattice_buffer_a->getBuffer(), fluid_buffer->getBuffer()); + stream_shader->workOn(lattice_buffer_b->getBuffer(), lattice_buffer_a->getBuffer(), fluid_buffer->getBuffer()); + tick = true; + } + + { + auto guard = collide_shader->use(); + collide_shader->dispatch(); + } + { + auto guard = stream_shader->use(); + stream_shader->dispatch(); + } + + last_frame = timer::now(); + } + + { + auto sdrGuard = scene_shader->use(); + + scene_shader->setUniform("MVP", MVP); + + glClear(GL_COLOR_BUFFER_BIT); + fluid_buffer->draw(); + } + } + }); + + return 0; +} + +int main(int argc, char* argv[]) { + GlfwGuard glfw; + + if( !glfw.isGood() ) { + std::cerr << "Failed to initialize GLFW." << std::endl; + return -1; + } + + return renderWindow(); +} -- cgit v1.2.3