|
|
|
@ -7,7 +7,6 @@ |
|
|
|
|
//adapted from https://gitlab.com/wikibooks-opengl/modern-tutorials/-/blob/master/tut05_cube/cube.cpp
|
|
|
|
|
|
|
|
|
|
/* Demo Parameters */ |
|
|
|
|
|
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|
constexpr size_t NUMBER_OF_CUBES = 10; |
|
|
|
|
constexpr long unsigned int WIDTH = 1280; |
|
|
|
@ -23,7 +22,7 @@ constexpr double FPS = 60; |
|
|
|
|
constexpr const char* OUTPUT_FILENAME = "many_cubes-demo.mkv"; |
|
|
|
|
#endif |
|
|
|
|
const unsigned long DIAG = hypot(double(WIDTH), double(HEIGHT)); |
|
|
|
|
const int glow_kernel_size = std::max(int(DIAG / 138 % 2 == 0 ? DIAG / 138 + 1 : DIAG / 138), 1); |
|
|
|
|
const int GLOW_KERNEL_SIZE = std::max(int(DIAG / 138 % 2 == 0 ? DIAG / 138 + 1 : DIAG / 138), 1); |
|
|
|
|
|
|
|
|
|
using std::cerr; |
|
|
|
|
using std::endl; |
|
|
|
@ -65,173 +64,178 @@ const unsigned short triangle_indices[] = { |
|
|
|
|
// Top
|
|
|
|
|
5, 1, 0, 0, 4, 5 |
|
|
|
|
}; |
|
|
|
|
//Simple transform & pass-through shaders
|
|
|
|
|
static GLuint load_shader() { |
|
|
|
|
//Shader versions "330" and "300 es" are very similar.
|
|
|
|
|
//If you are careful you can write the same code for both versions.
|
|
|
|
|
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3) |
|
|
|
|
const string shaderVersion = "330"; |
|
|
|
|
#else |
|
|
|
|
const string shaderVersion = "300 es"; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
const string vert = |
|
|
|
|
" #version " + shaderVersion |
|
|
|
|
+ R"( |
|
|
|
|
precision lowp float; |
|
|
|
|
layout(location = 0) in vec3 pos; |
|
|
|
|
layout(location = 1) in vec3 vertex_color; |
|
|
|
|
|
|
|
|
|
uniform mat4 transform; |
|
|
|
|
|
|
|
|
|
out vec3 color; |
|
|
|
|
void main() { |
|
|
|
|
gl_Position = transform * vec4(pos, 1.0); |
|
|
|
|
color = vertex_color; |
|
|
|
|
} |
|
|
|
|
)"; |
|
|
|
|
|
|
|
|
|
const string frag = |
|
|
|
|
" #version " + shaderVersion |
|
|
|
|
+ R"( |
|
|
|
|
precision lowp float; |
|
|
|
|
in vec3 color; |
|
|
|
|
|
|
|
|
|
out vec4 frag_color; |
|
|
|
|
|
|
|
|
|
void main() { |
|
|
|
|
frag_color = vec4(color, 1.0); |
|
|
|
|
} |
|
|
|
|
)"; |
|
|
|
|
|
|
|
|
|
//Initialize the shaders and returns the program
|
|
|
|
|
return cv::v4d::initShader(vert.c_str(), frag.c_str(), "fragColor"); |
|
|
|
|
} |
|
|
|
|
using namespace cv::v4d; |
|
|
|
|
class ManyCubesDemoPlan : public Plan { |
|
|
|
|
struct Cache { |
|
|
|
|
cv::UMat down_; |
|
|
|
|
cv::UMat up_; |
|
|
|
|
cv::UMat blur_; |
|
|
|
|
cv::UMat dst16_; |
|
|
|
|
} cache_; |
|
|
|
|
cv::UMat frame_; |
|
|
|
|
GLuint vao[NUMBER_OF_CUBES]; |
|
|
|
|
GLuint shaderProgram[NUMBER_OF_CUBES]; |
|
|
|
|
GLuint uniformTransform[NUMBER_OF_CUBES]; |
|
|
|
|
cv::Size sz_; |
|
|
|
|
//Simple transform & pass-through shaders
|
|
|
|
|
static GLuint load_shader() { |
|
|
|
|
//Shader versions "330" and "300 es" are very similar.
|
|
|
|
|
//If you are careful you can write the same code for both versions.
|
|
|
|
|
#if !defined(__EMSCRIPTEN__) && !defined(OPENCV_V4D_USE_ES3) |
|
|
|
|
const string shaderVersion = "330"; |
|
|
|
|
#else |
|
|
|
|
const string shaderVersion = "300 es"; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
const string vert = |
|
|
|
|
" #version " + shaderVersion |
|
|
|
|
+ R"( |
|
|
|
|
precision lowp float; |
|
|
|
|
layout(location = 0) in vec3 pos; |
|
|
|
|
layout(location = 1) in vec3 vertex_color; |
|
|
|
|
|
|
|
|
|
uniform mat4 transform; |
|
|
|
|
|
|
|
|
|
out vec3 color; |
|
|
|
|
void main() { |
|
|
|
|
gl_Position = transform * vec4(pos, 1.0); |
|
|
|
|
color = vertex_color; |
|
|
|
|
} |
|
|
|
|
)"; |
|
|
|
|
|
|
|
|
|
const string frag = |
|
|
|
|
" #version " + shaderVersion |
|
|
|
|
+ R"( |
|
|
|
|
precision lowp float; |
|
|
|
|
in vec3 color; |
|
|
|
|
|
|
|
|
|
out vec4 frag_color; |
|
|
|
|
|
|
|
|
|
void main() { |
|
|
|
|
frag_color = vec4(color, 1.0); |
|
|
|
|
} |
|
|
|
|
)"; |
|
|
|
|
|
|
|
|
|
//Initialize the shaders and returns the program
|
|
|
|
|
return cv::v4d::initShader(vert.c_str(), frag.c_str(), "fragColor"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//Initializes objects, buffers, shaders and uniforms
|
|
|
|
|
static void init_scene(const cv::Size& sz, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { |
|
|
|
|
glEnable (GL_DEPTH_TEST); |
|
|
|
|
//Initializes objects, buffers, shaders and uniforms
|
|
|
|
|
static void init_scene(const cv::Size& sz, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { |
|
|
|
|
glEnable (GL_DEPTH_TEST); |
|
|
|
|
|
|
|
|
|
glGenVertexArrays(1, &vao); |
|
|
|
|
glBindVertexArray(vao); |
|
|
|
|
glGenVertexArrays(1, &vao); |
|
|
|
|
glBindVertexArray(vao); |
|
|
|
|
|
|
|
|
|
unsigned int triangles_ebo; |
|
|
|
|
glGenBuffers(1, &triangles_ebo); |
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles_ebo); |
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof triangle_indices, triangle_indices, |
|
|
|
|
GL_STATIC_DRAW); |
|
|
|
|
unsigned int triangles_ebo; |
|
|
|
|
glGenBuffers(1, &triangles_ebo); |
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles_ebo); |
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof triangle_indices, triangle_indices, |
|
|
|
|
GL_STATIC_DRAW); |
|
|
|
|
|
|
|
|
|
unsigned int verticies_vbo; |
|
|
|
|
glGenBuffers(1, &verticies_vbo); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, verticies_vbo); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); |
|
|
|
|
unsigned int verticies_vbo; |
|
|
|
|
glGenBuffers(1, &verticies_vbo); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, verticies_vbo); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); |
|
|
|
|
|
|
|
|
|
glVertexAttribPointer(vertices_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); |
|
|
|
|
glEnableVertexAttribArray(vertices_index); |
|
|
|
|
glVertexAttribPointer(vertices_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); |
|
|
|
|
glEnableVertexAttribArray(vertices_index); |
|
|
|
|
|
|
|
|
|
unsigned int colors_vbo; |
|
|
|
|
glGenBuffers(1, &colors_vbo); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, colors_vbo); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof vertex_colors, vertex_colors, GL_STATIC_DRAW); |
|
|
|
|
unsigned int colors_vbo; |
|
|
|
|
glGenBuffers(1, &colors_vbo); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, colors_vbo); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof vertex_colors, vertex_colors, GL_STATIC_DRAW); |
|
|
|
|
|
|
|
|
|
glVertexAttribPointer(colors_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); |
|
|
|
|
glEnableVertexAttribArray(colors_index); |
|
|
|
|
glVertexAttribPointer(colors_index, 3, GL_FLOAT, GL_FALSE, 0, NULL); |
|
|
|
|
glEnableVertexAttribArray(colors_index); |
|
|
|
|
|
|
|
|
|
glBindVertexArray(0); |
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
|
|
|
glBindVertexArray(0); |
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
|
|
|
|
|
|
|
|
shaderProgram = load_shader(); |
|
|
|
|
uniformTransform = glGetUniformLocation(shaderProgram, "transform"); |
|
|
|
|
glViewport(0,0, sz.width, sz.height); |
|
|
|
|
} |
|
|
|
|
shaderProgram = load_shader(); |
|
|
|
|
uniformTransform = glGetUniformLocation(shaderProgram, "transform"); |
|
|
|
|
glViewport(0,0, sz.width, sz.height); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//Renders a rotating rainbow-colored cube on a blueish background
|
|
|
|
|
static void render_scene(const double& x, const double& y, const double& angleMod, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { |
|
|
|
|
//Use the prepared shader program
|
|
|
|
|
glUseProgram(shaderProgram); |
|
|
|
|
|
|
|
|
|
//Scale and rotate the cube depending on the current time.
|
|
|
|
|
float angle = fmod(double(cv::getTickCount()) / double(cv::getTickFrequency()) + angleMod, 2 * M_PI); |
|
|
|
|
double scale = 0.25; |
|
|
|
|
cv::Matx44f scaleMat( |
|
|
|
|
scale, 0.0, 0.0, 0.0, |
|
|
|
|
0.0, scale, 0.0, 0.0, |
|
|
|
|
0.0, 0.0, scale, 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f rotXMat( |
|
|
|
|
1.0, 0.0, 0.0, 0.0, |
|
|
|
|
0.0, cos(angle), -sin(angle), 0.0, |
|
|
|
|
0.0, sin(angle), cos(angle), 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f rotYMat( |
|
|
|
|
cos(angle), 0.0, sin(angle), 0.0, |
|
|
|
|
0.0, 1.0, 0.0, 0.0, |
|
|
|
|
-sin(angle), 0.0,cos(angle), 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f rotZMat( |
|
|
|
|
cos(angle), -sin(angle), 0.0, 0.0, |
|
|
|
|
sin(angle), cos(angle), 0.0, 0.0, |
|
|
|
|
0.0, 0.0, 1.0, 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f translateMat( |
|
|
|
|
1.0, 0.0, 0.0, 0.0, |
|
|
|
|
0.0, 1.0, 0.0, 0.0, |
|
|
|
|
0.0, 0.0, 1.0, 0.0, |
|
|
|
|
x, y, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
//calculate the transform
|
|
|
|
|
cv::Matx44f transform = scaleMat * rotXMat * rotYMat * rotZMat * translateMat; |
|
|
|
|
//set the corresponding uniform
|
|
|
|
|
glUniformMatrix4fv(uniformTransform, 1, GL_FALSE, transform.val); |
|
|
|
|
//Bind our vertex array
|
|
|
|
|
glBindVertexArray(vao); |
|
|
|
|
//Draw
|
|
|
|
|
glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_SHORT, NULL); |
|
|
|
|
} |
|
|
|
|
//Renders a rotating rainbow-colored cube on a blueish background
|
|
|
|
|
static void render_scene(const double& x, const double& y, const double& angleMod, GLuint& vao, GLuint& shaderProgram, GLuint& uniformTransform) { |
|
|
|
|
//Use the prepared shader program
|
|
|
|
|
glUseProgram(shaderProgram); |
|
|
|
|
|
|
|
|
|
//Scale and rotate the cube depending on the current time.
|
|
|
|
|
float angle = fmod(double(cv::getTickCount()) / double(cv::getTickFrequency()) + angleMod, 2 * M_PI); |
|
|
|
|
double scale = 0.25; |
|
|
|
|
cv::Matx44f scaleMat( |
|
|
|
|
scale, 0.0, 0.0, 0.0, |
|
|
|
|
0.0, scale, 0.0, 0.0, |
|
|
|
|
0.0, 0.0, scale, 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f rotXMat( |
|
|
|
|
1.0, 0.0, 0.0, 0.0, |
|
|
|
|
0.0, cos(angle), -sin(angle), 0.0, |
|
|
|
|
0.0, sin(angle), cos(angle), 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f rotYMat( |
|
|
|
|
cos(angle), 0.0, sin(angle), 0.0, |
|
|
|
|
0.0, 1.0, 0.0, 0.0, |
|
|
|
|
-sin(angle), 0.0,cos(angle), 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f rotZMat( |
|
|
|
|
cos(angle), -sin(angle), 0.0, 0.0, |
|
|
|
|
sin(angle), cos(angle), 0.0, 0.0, |
|
|
|
|
0.0, 0.0, 1.0, 0.0, |
|
|
|
|
0.0, 0.0, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
cv::Matx44f translateMat( |
|
|
|
|
1.0, 0.0, 0.0, 0.0, |
|
|
|
|
0.0, 1.0, 0.0, 0.0, |
|
|
|
|
0.0, 0.0, 1.0, 0.0, |
|
|
|
|
x, y, 0.0, 1.0); |
|
|
|
|
|
|
|
|
|
//calculate the transform
|
|
|
|
|
cv::Matx44f transform = scaleMat * rotXMat * rotYMat * rotZMat * translateMat; |
|
|
|
|
//set the corresponding uniform
|
|
|
|
|
glUniformMatrix4fv(uniformTransform, 1, GL_FALSE, transform.val); |
|
|
|
|
//Bind our vertex array
|
|
|
|
|
glBindVertexArray(vao); |
|
|
|
|
//Draw
|
|
|
|
|
glDrawElements(GL_TRIANGLES, triangles * 3, GL_UNSIGNED_SHORT, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|
//applies a glow effect to an image
|
|
|
|
|
static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize) { |
|
|
|
|
thread_local cv::UMat resize; |
|
|
|
|
thread_local cv::UMat blur; |
|
|
|
|
thread_local cv::UMat dst16; |
|
|
|
|
|
|
|
|
|
cv::bitwise_not(src, dst); |
|
|
|
|
|
|
|
|
|
//Resize for some extra performance
|
|
|
|
|
cv::resize(dst, resize, cv::Size(), 0.5, 0.5); |
|
|
|
|
//Cheap blur
|
|
|
|
|
cv::boxFilter(resize, resize, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true, |
|
|
|
|
cv::BORDER_REPLICATE); |
|
|
|
|
//Back to original size
|
|
|
|
|
cv::resize(resize, blur, src.size()); |
|
|
|
|
|
|
|
|
|
//Multiply the src image with a blurred version of itself
|
|
|
|
|
cv::multiply(dst, blur, dst16, 1, CV_16U); |
|
|
|
|
//Normalize and convert back to CV_8U
|
|
|
|
|
cv::divide(dst16, cv::Scalar::all(255.0), dst, 1, CV_8U); |
|
|
|
|
|
|
|
|
|
cv::bitwise_not(dst, dst); |
|
|
|
|
} |
|
|
|
|
//applies a glow effect to an image
|
|
|
|
|
static void glow_effect(const cv::UMat& src, cv::UMat& dst, const int ksize, Cache& cache) { |
|
|
|
|
cv::bitwise_not(src, dst); |
|
|
|
|
|
|
|
|
|
//Resize for some extra performance
|
|
|
|
|
cv::resize(dst, cache.down_, cv::Size(), 0.5, 0.5); |
|
|
|
|
//Cheap blur
|
|
|
|
|
cv::boxFilter(cache.down_, cache.blur_, -1, cv::Size(ksize, ksize), cv::Point(-1, -1), true, |
|
|
|
|
cv::BORDER_REPLICATE); |
|
|
|
|
//Back to original size
|
|
|
|
|
cv::resize(cache.blur_, cache.up_, src.size()); |
|
|
|
|
|
|
|
|
|
//Multiply the src image with a blurred version of itself
|
|
|
|
|
cv::multiply(dst, cache.up_, cache.dst16_, 1, CV_16U); |
|
|
|
|
//Normalize and convert back to CV_8U
|
|
|
|
|
cv::divide(cache.dst16_, cv::Scalar::all(255.0), dst, 1, CV_8U); |
|
|
|
|
|
|
|
|
|
cv::bitwise_not(dst, dst); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
using namespace cv::v4d; |
|
|
|
|
class ManyCubesDemoPlan : public Plan { |
|
|
|
|
cv::UMat frame_; |
|
|
|
|
GLuint vao[NUMBER_OF_CUBES]; |
|
|
|
|
GLuint shaderProgram[NUMBER_OF_CUBES]; |
|
|
|
|
GLuint uniformTransform[NUMBER_OF_CUBES]; |
|
|
|
|
public: |
|
|
|
|
void setup(cv::Ptr<V4D> window) { |
|
|
|
|
sz_ = window->fbSize(); |
|
|
|
|
for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) { |
|
|
|
|
window->gl(i, [](const cv::Size& sz, GLuint& v, GLuint& sp, GLuint& ut){ |
|
|
|
|
init_scene(sz, v, sp, ut); |
|
|
|
|
}, window->fbSize(), vao[i], shaderProgram[i], uniformTransform[i]); |
|
|
|
|
window->gl(i, [](const size_t& ctxIdx, cv::Size& sz, GLuint& v, GLuint& sp, GLuint& ut){ |
|
|
|
|
CV_UNUSED(ctxIdx); |
|
|
|
|
init_scene(sz, v, sp, ut); |
|
|
|
|
}, sz_, vao[i], shaderProgram[i], uniformTransform[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
void infer(cv::Ptr<V4D> window) { |
|
|
|
@ -243,20 +247,20 @@ public: |
|
|
|
|
|
|
|
|
|
//Render using multiple OpenGL contexts
|
|
|
|
|
for(size_t i = 0; i < NUMBER_OF_CUBES; ++i) { |
|
|
|
|
window->gl(i, [i](GLuint& v, GLuint& sp, GLuint& ut){ |
|
|
|
|
double pos = (((double(i) / NUMBER_OF_CUBES) * 2.0) - 1) + (1.0 / NUMBER_OF_CUBES); |
|
|
|
|
double angle = sin((double(i) / NUMBER_OF_CUBES) * 2 * M_PI); |
|
|
|
|
window->gl(i, [](const int32_t& ctxIdx, GLuint& v, GLuint& sp, GLuint& ut){ |
|
|
|
|
double pos = (((double(ctxIdx) / NUMBER_OF_CUBES) * 2.0) - 1) + (1.0 / NUMBER_OF_CUBES); |
|
|
|
|
double angle = sin((double(ctxIdx) / NUMBER_OF_CUBES) * 2 * M_PI); |
|
|
|
|
render_scene(pos, pos, angle, v, sp, ut); |
|
|
|
|
}, vao[i], shaderProgram[i], uniformTransform[i]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//Aquire the frame buffer for use by OpenCV
|
|
|
|
|
window->fb([](cv::UMat& framebuffer, cv::UMat& f) { |
|
|
|
|
window->fb([](cv::UMat& framebuffer, cv::UMat& f, Cache& cache) { |
|
|
|
|
#ifndef __EMSCRIPTEN__ |
|
|
|
|
glow_effect(framebuffer, framebuffer, glow_kernel_size); |
|
|
|
|
glow_effect(framebuffer, framebuffer, GLOW_KERNEL_SIZE, cache); |
|
|
|
|
#endif |
|
|
|
|
framebuffer.copyTo(f); |
|
|
|
|
}, frame_); |
|
|
|
|
}, frame_, cache_); |
|
|
|
|
|
|
|
|
|
window->write([](cv::UMat& outputFrame, const cv::UMat& f){ |
|
|
|
|
f.copyTo(outputFrame); |
|
|
|
|