Tatooine
render_topological_skeleton.h
Go to the documentation of this file.
1#ifndef TATOOINE_RENDER_TOPOLOGICAL_SKELETON
2#define TATOOINE_RENDER_TOPOLOGICAL_SKELETON
3//==============================================================================
4#include <tatooine/diff.h>
5#include <tatooine/gpu/lic.h>
7#include <tatooine/grid_sampler.h>
8#include <tatooine/sampled_field.h>
14#include <tatooine/gl/orthographiccamera.h>
17
18#include <boost/range/adaptor/transformed.hpp>
19#include <boost/range/algorithm/copy.hpp>
20//==============================================================================
21namespace tatooine {
22//==============================================================================
24template <typename Real, typename Integrator,
25 template <typename> typename Interpolator>
27 const sampled_field<
28 grid_sampler<Real, 2, vec<Real, 2>, interpolation::linear,
30 Real, 2, 2>& v,
31 const integration::integrator<Real, 2, Interpolator, Integrator>&
32 integrator,
33 const vec<size_t, 2>& resolution,
34 const Real tau = 100, const Real eps = 1e-7) {
35 using namespace gl;
36 struct point_shader : shader {
37 point_shader() {
38 add_stage<vertexshader>(
39 "#version 450\n"
40 "layout(location = 0) in vec2 pos;\n"
41 "layout(location = 1) in vec3 col;\n"
42 "out vec2 geom_pos;\n"
43 "out vec3 geom_col;\n"
44 "void main() {\n"
45 " geom_pos = pos;\n"
46 " geom_col = col;\n"
47 "}",
48 shaderstageparser::SOURCE);
49 add_stage<geometryshader>(
50 "#version 450\n"
51 "#define pi 3.1415926535897932384626433832795\n"
52 "layout (points) in;\n"
53 "layout (triangle_strip, max_vertices = 100) out;\n"
54 "\n"
55 "uniform mat4 projection;\n"
56 "uniform vec2 domain_min;\n"
57 "uniform vec2 domain_max;\n"
58 "uniform float radius;\n"
59 "\n"
60 "in vec2[] geom_pos;\n"
61 "in vec3[] geom_col;\n"
62 "\n"
63 "out vec3 frag_col;\n"
64 "out float frag_param;\n"
65 "\n"
66 "void main() {\n"
67 " uint n = 20;\n"
68 " frag_col = geom_col[0];\n"
69 " for (uint i = 0; i < n - 1; ++i) {\n"
70 " gl_Position = projection * vec4(geom_pos[0], 0, 1);\n"
71 " frag_param = 0;\n"
72 " EmitVertex();\n"
73 " gl_Position = projection * vec4(geom_pos[0] +\n"
74 " vec2(cos(float(i) / float(n-1) * 2*pi),\n"
75 " sin(float(i) / float(n-1) * 2*pi)) * radius,\n"
76 " 0, 1);\n"
77 " frag_param = 1;\n"
78 " EmitVertex();\n"
79 " gl_Position = projection * vec4(geom_pos[0] +\n"
80 " vec2(cos(float(i+1) / float(n-1) * 2*pi),\n"
81 " sin(float(i+1) / float(n-1) * 2*pi)) * radius,\n"
82 " 0, 1);\n"
83 " frag_param = 1;\n"
84 " EmitVertex();\n"
85 " EndPrimitive();\n"
86 " }\n"
87 "}",
88 shaderstageparser::SOURCE);
89 add_stage<fragmentshader>(
90 "#version 450\n"
91 "in vec3 frag_col;\n"
92 "in float frag_param;\n"
93 "layout(location = 0) out vec4 frag;\n"
94 "void main() {\n"
95 " if (frag_param > 0.8) {\n"
96 " frag = vec4(vec3(0), 1);\n"
97 " } else {\n"
98 " frag = vec4(frag_col, 1);\n"
99 " }\n"
100 "}",
101 shaderstageparser::SOURCE);
102 create();
103 }
104 void set_projection(const glm::mat4x4& p) { set_uniform("projection", p); }
105 void set_radius(const GLfloat radius) { set_uniform("radius", radius); }
106 };
107 //==============================================================================
108 struct line_shader : shader {
109 line_shader() {
110 add_stage<vertexshader>(
111 "#version 450\n"
112 "uniform mat4 projection;\n"
113 "layout(location = 0) in vec2 pos;\n"
114 "void main() {\n"
115 " gl_Position = projection * vec4(pos, 0, 1);\n"
116 "}\n",
117 shaderstageparser::SOURCE);
118 add_stage<fragmentshader>(
119 "#version 450\n"
120 "layout(location = 0) out vec4 frag;\n"
121 "void main() {\n"
122 " frag = vec4(0,0,0,1);\n"
123 "}\n",
124 shaderstageparser::SOURCE);
125 create();
126 }
127 void set_projection(const glm::mat4x4& p) { set_uniform("projection", p); }
128 };
129 using namespace interpolation;
130 using gpu_point_data_t = indexeddata<vec2f, vec3f>;
131 using gpu_line_data_t = indexeddata<vec2f>;
132 using sampler_t = grid_sampler<double, 2, vec<double, 2>, linear, linear>;
133
134 gpu_point_data_t::vbo_data_vec vbo_point_data;
135 gpu_point_data_t::ibo_data_vec ibo_point_data;
136 gpu_line_data_t::vbo_data_vec vbo_line_data;
137 gpu_line_data_t::ibo_data_vec ibo_line_data;
138
139 auto skel = compute_topological_skeleton(v, integrator);
140
141 // upload critical points
142 for (const auto& x : skel.saddles) {
143 vbo_point_data.push_back({{float(x(0)), float(x(1))}, {1.0f, 1.0f, .0f}});
144 ibo_point_data.push_back(ibo_point_data.size());
145 }
146 for (const auto& x : skel.sinks) {
147 vbo_point_data.push_back({{float(x(0)), float(x(1))}, {1.0f, .0f, .0f}});
148 ibo_point_data.push_back(ibo_point_data.size());
149 }
150 for (const auto& x : skel.sources) {
151 vbo_point_data.push_back({{float(x(0)), float(x(1))}, {.0f, .0f, 1.0f}});
152 ibo_point_data.push_back(ibo_point_data.size());
153 }
154 for (const auto& x : skel.attracting_foci) {
155 vbo_point_data.push_back({{float(x(0)), float(x(1))}, {1.0f, .25f, .25f}});
156 ibo_point_data.push_back(ibo_point_data.size());
157 }
158 for (const auto& x : skel.repelling_foci) {
159 vbo_point_data.push_back({{float(x(0)), float(x(1))}, {.25f, .25f, 1.0f}});
160 ibo_point_data.push_back(ibo_point_data.size());
161 }
162 for (const auto& x : skel.centers) {
163 vbo_point_data.push_back({{float(x(0)), float(x(1))}, {.0f, 0.75f, 0.0f}});
164 ibo_point_data.push_back(ibo_point_data.size());
165 }
166 for (const auto& x : skel.boundary_switch_points) {
167 vbo_point_data.push_back({{float(x(0)), float(x(1))}, {1.0f, 1.0f, 1.0f}});
168 ibo_point_data.push_back(ibo_point_data.size());
169 }
170 gpu_point_data_t gpu_point_data{vbo_point_data, ibo_point_data};
171 gpu_point_data.setup_vao();
172
173 // upload separatrices
174 size_t line_cnt = 0;
175 for (const auto& separatrix : skel.separatrices) {
176 for (size_t i = 0; i < separatrix.vertices().size(); ++i) {
177 vbo_line_data.push_back({static_cast<float>(separatrix.vertex_at(i)(0)),
178 static_cast<float>(separatrix.vertex_at(i)(1))});
179 }
180 for (size_t i = 0; i < separatrix.vertices().size() - 1; ++i) {
181 ibo_line_data.push_back(line_cnt);
182 ibo_line_data.push_back(++line_cnt);
183 }
184 ++line_cnt;
185 }
186 gpu_line_data_t gpu_line_data{vbo_line_data, ibo_line_data};
187 gpu_line_data.setup_vao();
188
189 // create lic texture
190 const Real pixel_size =
191 std::min((v.sampler().back(0) - v.sampler().front(0)) / resolution(0),
192 (v.sampler().back(1) - v.sampler().front(1)) / resolution(1));
193 const Real lic_stepsize = pixel_size / 4;
194 const size_t lic_num_samples = 100;
195 auto image = gpu::lic(v.sampler(), resolution, lic_num_samples, lic_stepsize,
196 {256, 256});
197 orthographiccamera cam(v.sampler().front(0), v.sampler().back(0),
198 v.sampler().front(1), v.sampler().back(1), -10, 10, 0,
199 0, resolution(0), resolution(1));
200
201 // render separatrices and critical points over lic image
202 framebuffer fbo{image};
203 fbo.bind();
204 gl::viewport(cam.viewport());
205 {
206 // render lines
207 line_shader shader;
208 shader.bind();
209 shader.set_projection(cam.projection_matrix());
211 gpu_line_data.draw_lines();
212 }
213 {
214 // render points
215 point_shader shader;
216 shader.bind();
217 shader.set_projection(cam.projection_matrix());
218 shader.set_radius(pixel_size*10);
219 gpu_point_data.draw_points();
220 }
221 fbo.unbind();
222
223 return image;
224}
225//==============================================================================
226} // namespace tatooine
227//==============================================================================
228
229#endif
DLL_API auto line_width(GLfloat width) -> void
DLL_API auto viewport(GLint x, GLint y, GLsizei width, GLsizei height) -> void
Definition: algorithm.h:6
auto render_topological_skeleton(const sampled_field< grid_sampler< Real, 2, vec< Real, 2 >, interpolation::linear, interpolation::linear >, Real, 2, 2 > &v, const integration::integrator< Real, 2, Interpolator, Integrator > &integrator, const vec< size_t, 2 > &resolution, const Real tau=100, const Real eps=1e-7)
you need a gl::context for this
Definition: render_topological_skeleton.h:26
auto compute_topological_skeleton(const sampled_field< grid_sampler< Real, 2, vec< Real, 2 >, interpolation::linear, interpolation::linear >, Real, 2, 2 > &v, const integration::integrator< Real, 2, Interpolator, Integrator > &integrator, const Real tau=100, const Real eps=1e-7)
Definition: topological_skeleton.h:31
Definition: interpolation.h:16
Definition: vec.h:12