ported shader-demo to new api

pull/3471/head
kallaballa 2 years ago
parent b40a44e432
commit db5af7ae67
  1. 321
      modules/v4d/samples/shader-demo.cpp

@ -22,39 +22,6 @@ const unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT));
constexpr const char* OUTPUT_FILENAME = "shader-demo.mkv"; constexpr const char* OUTPUT_FILENAME = "shader-demo.mkv";
#endif #endif
/* Mandelbrot control parameters */
static int glow_kernel_size = std::max(int(DIAG / 200 % 2 == 0 ? DIAG / 200 + 1 : DIAG / 200), 1);
// Red, green, blue and alpha. All from 0.0f to 1.0f
static float base_color_val[4] = {0.2, 0.6, 1.0, 1.0};
//contrast boost
static int contrast_boost = 50; //0.0-255
//max fractal iterations
static int max_iterations = 1000;
//center x coordinate
static float center_x = -0.119609;
//center y coordinate
static float center_y = 0.13262;
static float zoom_factor = 1.0;
static float current_zoom = 1.0;
static float zoom_incr = 0.99;
static bool manual_navigation = false;
/* GL uniform handles */
static thread_local GLint base_color_hdl;
static thread_local GLint contrast_boost_hdl;
static thread_local GLint max_iterations_hdl;
static thread_local GLint center_x_hdl;
static thread_local GLint center_y_hdl;
static thread_local GLint current_zoom_hdl;
static thread_local GLint resolution_hdl;
/* Shader program handle */
static thread_local GLuint shader_program_hdl;
/* Object handles */
static thread_local GLuint VAO;
static thread_local GLuint VBO, EBO;
// vertex position, color // vertex position, color
static const float vertices[] = { static const float vertices[] = {
// x y z // x y z
@ -66,34 +33,102 @@ static const unsigned int indices[] = {
// 0'---3 // 0'---3
0, 1, 2, 0, 3, 1 }; 0, 1, 2, 0, 3, 1 };
//Load objects and buffers //easing function for the bungee zoom
static void load_buffer_data() { static float easeInOutQuint(float x) {
glGenVertexArrays(1, &VAO); return x < 0.5f ? 16.0f * x * x * x * x * x : 1.0f - std::pow(-2.0f * x + 2.0f, 5.0f) / 2.0f;
glBindVertexArray(VAO); }
glGenBuffers(1, &VBO); #ifndef __EMSCRIPTEN__
glGenBuffers(1, &EBO); static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize) {
static thread_local cv::UMat resize;
static thread_local cv::UMat blur;
static thread_local cv::UMat dst16;
glBindBuffer(GL_ARRAY_BUFFER, VBO); cv::bitwise_not(src, dst);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); cv::resize(dst, resize, cv::Size(), 0.5, 0.5);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); cv::boxFilter(resize, resize, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true,
cv::BORDER_REPLICATE);
cv::resize(resize, blur, src.size());
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*) 0); cv::multiply(dst, blur, dst16, 1, CV_16U);
glEnableVertexAttribArray(0); cv::divide(dst16, cv::Scalar::all(255.0), dst, 1, CV_8U);
glBindBuffer(GL_ARRAY_BUFFER, 0); cv::bitwise_not(dst, dst);
glBindVertexArray(0);
} }
#endif
//mandelbrot shader code adapted from my own project: https://github.com/kallaballa/FractalDive#after using namespace cv::v4d;
static void load_shader() {
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3) class ShaderDemoPlan : public Plan {
struct Params {
/* Mandelbrot control parameters */
int glowKernelSize_ = std::max(int(DIAG / 200 % 2 == 0 ? DIAG / 200 + 1 : DIAG / 200), 1);
// Red, green, blue and alpha. All from 0.0f to 1.0f
float baseColorVal_[4] = {0.2, 0.6, 1.0, 1.0};
//contrast boost
int contrastBoost_ = 50; //0.0-255
//max fractal iterations
int maxIterations_ = 1000;
//center x coordinate
float centerX_ = -0.119609;
//center y coordinate
float centerY_ = 0.13262;
float zoomFactor_ = 1.0;
float currentZoom_ = 1.0;
float zoomIncr_ = 0.99;
bool manualNavigation_ = false;
} params_;
struct Handles {
/* GL uniform handles */
GLint baseColorHdl_;
GLint contrastBoostHdl_;
GLint maxIterationsHdl_;
GLint centerXHdl_;
GLint centerYHdl_;
GLint currentZoomHdl_;
GLint resolutionHdl_;
/* Shader program handle */
GLuint shaderHdl_;
/* Object handles */
GLuint vao_;
GLuint vbo_, ebo_;
} handles_;
cv::Size sz_;
public:
//Load objects and buffers
static void load_buffers(Handles& handles) {
GL_CHECK(glGenVertexArrays(1, &handles.vao_));
GL_CHECK(glBindVertexArray(handles.vao_));
GL_CHECK(glGenBuffers(1, &handles.vbo_));
GL_CHECK(glGenBuffers(1, &handles.ebo_));
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, handles.vbo_));
GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handles.ebo_));
GL_CHECK(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW));
GL_CHECK(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*) 0));
GL_CHECK(glEnableVertexAttribArray(0));
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
GL_CHECK(glBindVertexArray(0));
}
//mandelbrot shader code adapted from my own project: https://github.com/kallaballa/FractalDive#after
static GLuint load_shader() {
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3)
const string shaderVersion = "330"; const string shaderVersion = "330";
#else #else
const string shaderVersion = "300 es"; const string shaderVersion = "300 es";
#endif #endif
const string vert = const string vert =
" #version " + shaderVersion " #version " + shaderVersion
@ -116,8 +151,8 @@ static void load_shader() {
uniform int contrast_boost; uniform int contrast_boost;
uniform int max_iterations; uniform int max_iterations;
uniform float current_zoom; uniform float current_zoom;
uniform float center_x;
uniform float center_y; uniform float center_y;
uniform float center_x;
uniform vec2 resolution; uniform vec2 resolution;
int get_iterations() int get_iterations()
@ -164,149 +199,117 @@ static void load_shader() {
determine_color(); determine_color();
})"; })";
shader_program_hdl = cv::v4d::initShader(vert.c_str(), frag.c_str(), "fragColor"); return cv::v4d::initShader(vert.c_str(), frag.c_str(), "fragColor");
} }
//easing function for the bungee zoom
static float easeInOutQuint(float x) {
return x < 0.5f ? 16.0f * x * x * x * x * x : 1.0f - std::pow(-2.0f * x + 2.0f, 5.0f) / 2.0f;
}
//Initialize shaders, objects, buffers and uniforms //Initialize shaders, objects, buffers and uniforms
static void init_scene(const cv::Size& sz) { static void initScene(const cv::Size& sz, Handles& handles) {
glEnable(GL_BLEND); GL_CHECK(glEnable(GL_BLEND));
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
load_shader(); handles.shaderHdl_ = load_shader();
load_buffer_data(); load_buffers(handles);
base_color_hdl = glGetUniformLocation(shader_program_hdl, "base_color"); handles.baseColorHdl_ = glGetUniformLocation(handles.shaderHdl_, "base_color");
contrast_boost_hdl = glGetUniformLocation(shader_program_hdl, "contrast_boost"); handles.contrastBoostHdl_ = glGetUniformLocation(handles.shaderHdl_, "contrast_boost");
max_iterations_hdl = glGetUniformLocation(shader_program_hdl, "max_iterations"); handles.maxIterationsHdl_ = glGetUniformLocation(handles.shaderHdl_, "max_iterations");
current_zoom_hdl = glGetUniformLocation(shader_program_hdl, "current_zoom"); handles.currentZoomHdl_ = glGetUniformLocation(handles.shaderHdl_, "current_zoom");
center_x_hdl = glGetUniformLocation(shader_program_hdl, "center_x"); handles.centerXHdl_ = glGetUniformLocation(handles.shaderHdl_, "center_x");
center_y_hdl = glGetUniformLocation(shader_program_hdl, "center_y"); handles.centerYHdl_ = glGetUniformLocation(handles.shaderHdl_, "center_y");
resolution_hdl = glGetUniformLocation(shader_program_hdl, "resolution"); handles.resolutionHdl_ = glGetUniformLocation(handles.shaderHdl_, "resolution");
glViewport(0, 0, sz.width, sz.height); GL_CHECK(glViewport(0, 0, sz.width, sz.height));
} }
//Render the mandelbrot fractal on top of a video //Render the mandelbrot fractal on top of a video
static void render_scene(const cv::Size& sz) { static void renderScene(const cv::Size& sz, Params& params, Handles& handles) {
//bungee zoom //bungee zoom
if (current_zoom >= 1) { if (params.currentZoom_ >= 1) {
zoom_incr = -0.01; params.zoomIncr_ = -0.01;
} else if (current_zoom < 2.5e-06) { } else if (params.currentZoom_ < 2.5e-06) {
zoom_incr = +0.01; params.zoomIncr_ = +0.01;
} }
glUseProgram(shader_program_hdl); GL_CHECK(glUseProgram(handles.shaderHdl_));
glUniform4f(base_color_hdl, base_color_val[0], base_color_val[1], base_color_val[2], base_color_val[3]); GL_CHECK(glUniform4f(handles.baseColorHdl_, params.baseColorVal_[0], params.baseColorVal_[1], params.baseColorVal_[2], params.baseColorVal_[3]));
glUniform1i(contrast_boost_hdl, contrast_boost); GL_CHECK(glUniform1i(handles.contrastBoostHdl_, params.contrastBoost_));
glUniform1i(max_iterations_hdl, max_iterations); GL_CHECK(glUniform1i(handles.maxIterationsHdl_, params.maxIterations_));
glUniform1f(center_y_hdl, center_y); GL_CHECK(glUniform1f(handles.centerYHdl_, params.centerY_));
glUniform1f(center_x_hdl, center_x); GL_CHECK(glUniform1f(handles.centerXHdl_, params.centerX_));
if (!manual_navigation) { if (!params.manualNavigation_) {
current_zoom += zoom_incr; params.currentZoom_ += params.zoomIncr_;
glUniform1f(current_zoom_hdl, easeInOutQuint(current_zoom)); GL_CHECK(glUniform1f(handles.currentZoomHdl_, easeInOutQuint(params.currentZoom_)));
} else { } else {
current_zoom = 1.0 / pow(zoom_factor, 5.0f); params.currentZoom_ = 1.0 / pow(params.zoomFactor_, 5.0f);
glUniform1f(current_zoom_hdl, current_zoom); GL_CHECK(glUniform1f(handles.currentZoomHdl_, params.currentZoom_));
} }
float res[2] = {float(sz.width), float(sz.height)}; float res[2] = {float(sz.width), float(sz.height)};
glUniform2fv(resolution_hdl, 1, res); GL_CHECK(glUniform2fv(handles.resolutionHdl_, 1, res));
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
#ifndef __EMSCRIPTEN__
static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize) {
static thread_local cv::UMat resize;
static thread_local cv::UMat blur;
static thread_local cv::UMat dst16;
cv::bitwise_not(src, dst);
cv::resize(dst, resize, cv::Size(), 0.5, 0.5);
cv::boxFilter(resize, resize, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true,
cv::BORDER_REPLICATE);
cv::resize(resize, blur, src.size());
cv::multiply(dst, blur, dst16, 1, CV_16U);
cv::divide(dst16, cv::Scalar::all(255.0), dst, 1, CV_8U);
cv::bitwise_not(dst, dst);
}
#endif
using namespace cv::v4d; GL_CHECK(glBindVertexArray(handles.vao_));
GL_CHECK(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
}
//Setup the GUI using ImGUI. void gui(cv::Ptr<V4D> window) override {
static void setup_gui(cv::Ptr<V4D> window) { window->imgui([this](cv::Ptr<V4D> window, ImGuiContext* ctx) {
window->imgui([](ImGuiContext* ctx) {
using namespace ImGui; using namespace ImGui;
SetCurrentContext(ctx); SetCurrentContext(ctx);
Begin("Fractal"); Begin("Fractal");
Text("Navigation"); Text("Navigation");
SliderInt("Iterations", &max_iterations, 3, 50000); SliderInt("Iterations", &params_.maxIterations_, 3, 50000);
if(SliderFloat("X", &center_x, -1.0f, 1.0f)) if(SliderFloat("X", &params_.centerX_, -1.0f, 1.0f))
manual_navigation = true; params_.manualNavigation_ = true;
if(SliderFloat("Y", &center_y, -1.0f, 1.0f)) if(SliderFloat("Y", &params_.centerY_, -1.0f, 1.0f))
manual_navigation = true; params_.manualNavigation_ = true;
if(SliderFloat("Zoom", &zoom_factor, 1.0f, 100.0f)) if(SliderFloat("Zoom", &params_.zoomFactor_, 1.0f, 100.0f))
manual_navigation = true; params_.manualNavigation_ = true;
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
Text("Glow"); Text("Glow");
SliderInt("Kernel Size", &glow_kernel_size, 1, 127); SliderInt("Kernel Size", &params_.glowKernelSize_, 1, 127);
#endif #endif
Text("Color"); Text("Color");
ColorPicker4("Color", base_color_val); ColorPicker4("Color", params_.baseColorVal_);
SliderInt("Contrast boost", &contrast_boost, 1, 255); SliderInt("Contrast boost", &params_.contrastBoost_, 1, 255);
End(); End();
}); });
} }
class ShaderDemoPlan : public Plan { void setup(cv::Ptr<V4D> window) override {
public: sz_ = window->fbSize();
void setup(cv::Ptr<V4D> window) override { window->gl([](const cv::Size &sz, Handles& handles) {
window->gl([](const cv::Size &sz) { initScene(sz, handles);
init_scene(sz); }, sz_, handles_);
}, window->fbSize()); }
}
void infer(cv::Ptr<V4D> window) override { void infer(cv::Ptr<V4D> window) override {
window->capture(); window->capture();
window->gl([](const cv::Size &sz) { window->gl([](const cv::Size &sz, Params& params, Handles& handles) {
render_scene(sz); renderScene(sz, params, handles);
}, window->fbSize()); }, sz_, params_, handles_);
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
window->fb([](cv::UMat& framebuffer) { window->fb([](cv::UMat& framebuffer, const Params& params) {
glow_effect(framebuffer, framebuffer, glow_kernel_size); glow_effect(framebuffer, framebuffer, params.glowKernelSize_);
}); }, params_);
#endif #endif
window->write(); window->write();
} }
}; };
#ifndef __EMSCRIPTEN__
int main(int argc, char** argv) { int main(int argc, char** argv) {
#ifndef __EMSCRIPTEN__
if (argc != 2) { if (argc != 2) {
cerr << "Usage: shader-demo <video-file>" << endl; cerr << "Usage: shader-demo <video-file>" << endl;
exit(1); exit(1);
} }
#else #else
int main() { CV_UNUSED(args);
CV_UNUSED(argv);
#endif #endif
try { try {
cv::Ptr<V4D> window = V4D::make(WIDTH, HEIGHT, "Mandelbrot Shader Demo", IMGUI, OFFSCREEN, false, 0); cv::Ptr<V4D> window = V4D::make(WIDTH, HEIGHT, "Mandelbrot Shader Demo", IMGUI, OFFSCREEN);
if (!OFFSCREEN) {
setup_gui(window);
}
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
auto src = makeCaptureSource(window, argv[1]); auto src = makeCaptureSource(window, argv[1]);

Loading…
Cancel
Save