Tatooine
volume.h
Go to the documentation of this file.
11//==============================================================================
12namespace tatooine::rendering {
13//==============================================================================
14template <typename DimX, typename DimY, typename DimZ, floating_point ValueType,
15 bool HasNonConstReference>
19 HasNonConstReference> const& prop) -> void {
21 bool menu_open = true;
22 auto const gpu_tex = tatooine::gpu::upload_tex(prop);
23
25
26 auto viridis_tex_1d = gl::tex1rgba32f{};
27 auto viridis_data = std::vector<vec4f>{};
28 for (std::size_t i = 0; i < v.num_samples(); ++i) {
29 viridis_data.push_back(
30 vec4f{v.data()[i](0), v.data()[i](1), v.data()[i](2), 1});
31 }
32 viridis_tex_1d.upload_data(viridis_data, v.num_samples());
33
34 auto viridis_tex_2d = gl::tex2rgba32f{};
35 viridis_tex_2d.resize(v.num_samples(), 2);
36 for (std::size_t i = 0; i < v.num_samples(); ++i) {
37 viridis_data.push_back(
38 vec4f{v.data()[i](0), v.data()[i](1), v.data()[i](2), 1});
39 }
40 viridis_tex_2d.upload_data(viridis_data, v.num_samples(), 2);
41
42 auto const color_scales = std::array{
43 std::tuple{"Viridis", std::move(viridis_tex_1d),
44 std::move(viridis_tex_2d)}
45 //,std::tuple{"Magma", color_scales::magma<float>{}.to_gpu_tex(),
46 // color_scales::magma<float>{}.to_gpu_tex2d()}
47 };
48 typename decltype(color_scales)::value_type const* current_color_scale =
49 &color_scales.front();
50 auto cube_data = gl::indexeddata<vec3f>{};
51 cube_data.vertexbuffer().resize(8);
52 cube_data.indexbuffer().resize(36);
53 {
54 size_t i = 0;
55 auto data = cube_data.vertexbuffer().wmap();
56 data[i++] = vec3f{0, 0, 0};
57 data[i++] = vec3f{1, 0, 0};
58 data[i++] = vec3f{0, 1, 0};
59 data[i++] = vec3f{1, 1, 0};
60 data[i++] = vec3f{0, 0, 1};
61 data[i++] = vec3f{1, 0, 1};
62 data[i++] = vec3f{0, 1, 1};
63 data[i++] = vec3f{1, 1, 1};
64 }
65 {
66 size_t i = 0;
67 auto data = cube_data.indexbuffer().wmap();
68 // front
69 data[i++] = 0;
70 data[i++] = 1;
71 data[i++] = 2;
72 data[i++] = 1;
73 data[i++] = 3;
74 data[i++] = 2;
75
76 // back
77 data[i++] = 4;
78 data[i++] = 7;
79 data[i++] = 5;
80 data[i++] = 4;
81 data[i++] = 6;
82 data[i++] = 7;
83
84 // right
85 data[i++] = 1;
86 data[i++] = 5;
87 data[i++] = 3;
88 data[i++] = 5;
89 data[i++] = 7;
90 data[i++] = 3;
91
92 // left
93 data[i++] = 0;
94 data[i++] = 2;
95 data[i++] = 4;
96 data[i++] = 2;
97 data[i++] = 6;
98 data[i++] = 4;
99
100 // top
101 data[i++] = 2;
102 data[i++] = 3;
103 data[i++] = 6;
104 data[i++] = 3;
105 data[i++] = 7;
106 data[i++] = 6;
107
108 // bottom
109 data[i++] = 0;
110 data[i++] = 4;
111 data[i++] = 1;
112 data[i++] = 1;
113 data[i++] = 4;
114 data[i++] = 5;
115 }
116 auto screenspace_quad_data = gl::indexeddata<vec2f>{};
117 screenspace_quad_data.vertexbuffer().resize(4);
118 screenspace_quad_data.indexbuffer().resize(6);
119 {
120 size_t i = 0;
121 auto data = screenspace_quad_data.vertexbuffer().wmap();
122 data[i++] = vec2f{-1, -1};
123 data[i++] = vec2f{1, -1};
124 data[i++] = vec2f{-1, 1};
125 data[i++] = vec2f{1, 1};
126 }
127 {
128 size_t i = 0;
129 auto data = screenspace_quad_data.indexbuffer().wmap();
130 data[i++] = 0;
131 data[i++] = 1;
132 data[i++] = 2;
133 data[i++] = 1;
134 data[i++] = 3;
135 data[i++] = 2;
136 }
137
138 struct position_shader_t : gl::shader {
139 position_shader_t() {
140 add_stage<gl::vertexshader>(gl::shadersource{
141 "#version 330 core\n"
142 "layout(location = 0) in vec3 pos;\n"
143 "out vec3 frag_pos;\n"
144 "uniform mat4 projection_matrix;\n"
145 "uniform mat4 modelview_matrix;\n"
146 "//"
147 "------------------------------------------------------------------\n"
148 "void main() {\n"
149 " gl_Position = projection_matrix * modelview_matrix * vec4(pos, "
150 "1);\n"
151 " frag_pos = pos;\n"
152 "}\n"});
153 add_stage<gl::fragmentshader>(gl::shadersource{
154 "#version 330 core\n"
155 "in vec3 frag_pos;\n"
156 "out vec4 frag_out;\n"
157 "//"
158 "------------------------------------------------------------------\n"
159 "void main() {\n"
160 " frag_out = vec4(frag_pos, 1);\n"
161 "}\n"});
162 create();
163 }
164 auto set_modelview_matrix(mat4f const& MV) -> void {
165 set_uniform_mat4("modelview_matrix", MV.data());
166 }
167 auto set_projection_matrix(mat4f const& P) -> void {
168 set_uniform_mat4("projection_matrix", P.data());
169 }
170 } position_shader;
171 struct dvr_shader_t : gl::shader {
172 dvr_shader_t() {
173 add_stage<gl::vertexshader>(gl::shadersource{
174 "#version 330 core\n"
175 "layout(location = 0) in vec2 pos;\n"
176 "//----------------------------------------------------------------\n"
177 "void main() {\n"
178 " gl_Position = vec4(pos, 0, 1);\n"
179 "}\n"});
180 add_stage<gl::fragmentshader>(gl::shadersource{
181 "#version 430 core\n"
182 "uniform float shininess;\n"
183 "uniform vec3 specular_color;\n"
184 "uniform mat4 model_matrix;\n"
185 "uniform mat4 modelview_matrix;\n"
186 "uniform vec3 eps;\n"
187 "uniform sampler3D volume_data;\n"
188 "uniform sampler1D color_scale;\n"
189 "uniform sampler1D alpha;\n"
190 "uniform int mode;\n"
191 "uniform float range_min;\n"
192 "uniform float range_max;\n"
193 "uniform float ray_offset;\n"
194 "layout(rgba32f, binding = 0) readonly uniform image2D front_cube;\n"
195 "layout(rgba32f, binding = 1) readonly uniform image2D back_cube;\n"
196 "out vec4 frag_out;\n"
197 "//----------------------------------------------------------------\n"
198 "vec3 phong_brdf(vec3 light_dir, vec3 view_dir,\n"
199 " vec3 normal, vec3 diffuse_color) {\n"
200 " vec3 color = diffuse_color;\n"
201 " vec3 reflect_dir = reflect(-light_dir, normal);\n"
202 " float spec_dot = abs(dot(reflect_dir, view_dir));\n"
203 " color += pow(spec_dot, shininess) * specular_color;\n"
204 " return color;\n"
205 "}\n"
206 "//----------------------------------------------------------------\n"
207 "void main() {\n"
208 " vec4 front = imageLoad(front_cube, ivec2(gl_FragCoord.xy));\n"
209 " vec4 back = imageLoad(back_cube, ivec2(gl_FragCoord.xy));\n"
210 " if (front.w == 0) {\n"
211 " frag_out = vec4(1, 1, 1, 1);\n"
212 " return;\n"
213 " }\n"
214 " if (mode == 0) {\n"
215 " vec3 direction = back.xyz - front.xyz;\n"
216 " float distance = length(direction);\n"
217 " direction = normalize(direction);\n"
218 " vec3 modelview_direction =\n"
219 " normalize((modelview_matrix * back).xyz -\n"
220 " (modelview_matrix * front).xyz);\n"
221 " int num_steps = int(distance / ray_offset);\n"
222 " float actual_ray_offset = distance / num_steps;\n"
223 " vec4 accumulator = vec4(0, 0, 0, 0);\n"
224 " vec3 physical_eps = vec3(\n"
225 " length((model_matrix * vec4(2 * eps.x, 0, 0, 1)).xyz),\n"
226 " length((model_matrix * vec4(0, 2 * eps.y, 0, 1)).xyz),\n"
227 " length((model_matrix * vec4(0, 0, 2 * eps.z, 1)).xyz)\n"
228 " );\n"
229 " for (int i = 0; i < num_steps; ++i) {\n"
230 " vec3 cur_pos = front.xyz + direction * i * actual_ray_offset;"
231 " float s = texture(volume_data, cur_pos).x;\n"
232 " vec3 gradient = vec3(\n"
233 " (texture(volume_data, cur_pos + vec3(eps.x, 0, 0)).x -\n"
234 " texture(volume_data, cur_pos - vec3(eps.x, 0, 0)).x),\n"
235 " (texture(volume_data, cur_pos + vec3(0, eps.y, 0)).x -\n"
236 " texture(volume_data, cur_pos - vec3(0, eps.y, 0)).x),\n"
237 " (texture(volume_data, cur_pos + vec3(0, 0, eps.z)).x -\n"
238 " texture(volume_data, cur_pos - vec3(0, 0, eps.z)).x)) / "
239 "physical_eps;\n"
240 " float normalized_sample = (s-range_min) / "
241 "(range_max-range_min);\n"
242 " vec3 normal = normalize(gradient);\n"
243 " vec3 albedo = texture(color_scale, normalized_sample).rgb;\n"
244 " vec3 luminance = albedo * 0.1;\n"
245 " float illuminance = abs(dot(modelview_direction, normal));\n"
246 " luminance += phong_brdf(modelview_direction, "
247 "modelview_direction,\n"
248 " normal, albedo) * illuminance;\n"
249 " float cur_alpha = texture(alpha, normalized_sample).r;\n"
250 " accumulator.rgb += (1 - accumulator.a) * cur_alpha * "
251 "luminance;\n"
252 " accumulator.a += (1 - accumulator.a) * cur_alpha;\n"
253 " if (accumulator.a >= 0.95) { break; }\n"
254 " }\n"
255 " frag_out.xyz = vec3(1 - accumulator.a) + accumulator.xyz * "
256 "accumulator.a ;\n"
257 " } else if (mode == 1) {\n"
258 " frag_out = front;\n"
259 " } else if (mode == 2) {\n"
260 " frag_out = back;\n"
261 " } else if (mode == 3) {\n"
262 " float s = texture(volume_data, front.xyz).x;\n"
263 " float normalized_sample = (s-range_min) / "
264 "(range_max-range_min);\n"
265 " //vec3 color = vec3(normalized_sample);\n"
266 " vec3 color = texture(color_scale, normalized_sample).xyz;\n"
267 " frag_out = vec4(color, 1);\n"
268 " }\n"
269 "}\n"});
270 create();
271 set_mode(0);
272 }
273 auto set_shininess(float shininess) -> void {
274 set_uniform("shininess", shininess);
275 }
276 auto set_volume_data_sampler_unit(int unit) -> void {
277 set_uniform("volume_data", unit);
278 }
279 auto set_color_scale_sampler_unit(int unit) -> void {
280 set_uniform("color_scale", unit);
281 }
282 auto set_alpha_sampler_unit(int unit) -> void {
283 set_uniform("alpha", unit);
284 }
285 auto set_model_matrix(mat4f const& M) -> void {
286 set_uniform_mat4("model_matrix", M.data());
287 }
288 auto set_modelview_matrix(mat4f const& MV) -> void {
289 set_uniform_mat4("modelview_matrix", MV.data());
290 }
291 auto set_mode(int mode) -> void { set_uniform("mode", mode); }
292 auto set_range_min(float range_min) -> void {
293 set_uniform("range_min", range_min);
294 }
295 auto set_specular_color(vec3f const& specular_color) -> void {
296 set_uniform_vec3("specular_color", specular_color.data());
297 }
298 auto set_eps(vec3f const& eps) -> void {
299 set_uniform_vec3("eps", eps.data());
300 }
301 auto set_range_max(float range_max) -> void {
302 set_uniform("range_max", range_max);
303 }
304 auto set_ray_offset(float ray_offset) -> void {
305 set_uniform("ray_offset", ray_offset);
306 }
307 } dvr_shader;
308
309 auto front_cube_tex = gl::tex2rgba32f{32, 32};
310 auto back_cube_tex = gl::tex2rgba32f{32, 32};
311 auto specular_color = vec3f{0.1f, 0.1f, 0.1f};
312 float range_min = 0.0f;
313 float range_max = 1.0f;
314 float ray_offset = 0.01f;
315 float shininess = 100.0f;
316 size_t const num_alpha_samples = 100;
317 auto alpha_tex = gl::tex1r32f{num_alpha_samples};
318 std::vector<float> handles{0.0f, 0.0f, 0.1f, 0.0f, 0.45f, 0.0f, 0.45f,
319 0.0f, 0.5f, 1.0f, 0.5f, 1.0f, 0.55f, 0.0f,
320 0.55f, 0.0f, 1.0f, 0.0f, 0.9f, 0.0f};
321 alpha_tex.set_wrap_mode(gl::CLAMP_TO_EDGE);
322 std::vector<float> alpha_data(num_alpha_samples);
323 dvr_shader.set_volume_data_sampler_unit(0);
324 dvr_shader.set_color_scale_sampler_unit(1);
325 dvr_shader.set_alpha_sampler_unit(2);
326 dvr_shader.set_range_min(range_min);
327 dvr_shader.set_range_max(range_max);
328 dvr_shader.set_shininess(shininess);
329 dvr_shader.set_specular_color(specular_color);
330 dvr_shader.set_ray_offset(ray_offset);
331 dvr_shader.set_eps(vec3f{1.0f / prop.grid().template size<0>(),
332 1.0f / prop.grid().template size<1>(),
333 1.0f / prop.grid().template size<2>()});
334
335 struct listener_t : gl::window_listener {
336 gl::tex2rgba32f& front_cube_tex;
337 gl::tex2rgba32f& back_cube_tex;
338 listener_t(gl::tex2rgba32f& f, gl::tex2rgba32f& b)
339 : front_cube_tex{f}, back_cube_tex{b} {}
340 auto on_resize(int width, int height) -> void override {
341 front_cube_tex.resize(width, height);
342 back_cube_tex.resize(width, height);
343 }
344 } listener{front_cube_tex, back_cube_tex};
345 win.add_listener(listener);
346
347 win.render_loop([&](auto const /*dt*/) {
348 front_cube_tex.clear(1, 1, 1, 0);
349 back_cube_tex.clear(1, 1, 1, 0);
350 gl::clear_color(1, 1, 1, 1);
352
355 position_shader.bind();
356 auto const M =
357 rendering::translation_matrix(prop.grid().template front<0>(),
358 prop.grid().template front<1>(),
359 prop.grid().template front<2>()) *
360 rendering::scale_matrix(prop.grid().template extent<0>(),
361 prop.grid().template extent<1>(),
362 prop.grid().template extent<2>());
363 auto const MV = win.camera_controller().view_matrix() * M;
364 position_shader.set_modelview_matrix(MV);
365 dvr_shader.set_model_matrix(M);
366 dvr_shader.set_modelview_matrix(MV);
367 position_shader.set_projection_matrix(
368 win.camera_controller().projection_matrix());
369
370 auto front_cube_framebuffer = gl::framebuffer{front_cube_tex};
371 front_cube_framebuffer.bind();
373 cube_data.draw_triangles();
374
375 auto back_cube_framebuffer = gl::framebuffer{back_cube_tex};
376 back_cube_framebuffer.bind();
378 cube_data.draw_triangles();
379
383
384 dvr_shader.bind();
385
386 front_cube_tex.bind_image_texture(0);
387 back_cube_tex.bind_image_texture(1);
388 gpu_tex.bind(0);
389 std::get<1>(*current_color_scale).bind(1);
390
391 for (size_t i = 0; i < num_alpha_samples; ++i) {
392 float const pos = i / (float)(num_alpha_samples - 1);
393 alpha_data[i] = ImGui::BezierValue(pos, handles);
394 }
395 alpha_tex.upload_data(alpha_data, num_alpha_samples);
396 alpha_tex.bind(2);
397 screenspace_quad_data.draw_triangles();
398
399 if (menu_open) {
400 float width = std::min<float>(400, win.width() / 2);
401 ImGui::SetNextWindowSize(ImVec2{width, float(win.height())});
402 ImGui::SetNextWindowPos(ImVec2{win.width() - width, 0});
403 ImGui::Begin("", &menu_open,
404 ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
405 ImGuiWindowFlags_NoMove);
406
407 if (ImGui::Button("Volume")) {
408 dvr_shader.set_mode(0);
409 }
410 ImGui::SameLine();
411 if (ImGui::Button("Front")) {
412 dvr_shader.set_mode(1);
413 }
414 ImGui::SameLine();
415 if (ImGui::Button("Back")) {
416 dvr_shader.set_mode(2);
417 }
418 ImGui::SameLine();
419 if (ImGui::Button("Map")) {
420 dvr_shader.set_mode(3);
421 }
422 if (ImGui::DragFloat("Ray Offset", &ray_offset, 0.001f, 0.0001f, 0.1f)) {
423 dvr_shader.set_ray_offset(ray_offset);
424 }
425 if (ImGui::DragFloat("Min", &range_min, 0.001f,
426 -std::numeric_limits<float>::max(), range_max)) {
427 dvr_shader.set_range_min(range_min);
428 }
429 if (ImGui::DragFloat("Max", &range_max, 0.001f, range_min,
430 std::numeric_limits<float>::max())) {
431 dvr_shader.set_range_max(range_max);
432 }
433 if (ImGui::DragFloat("Shininess", &shininess, 5.0f)) {
434 dvr_shader.set_shininess(shininess);
435 }
436 if (ImGui::ColorEdit3("Specular Color", specular_color.data())) {
437 dvr_shader.set_specular_color(specular_color);
438 }
439 ImGui::Bezier("alpha", handles);
440
441 ImGuiStyle& style = ImGui::GetStyle();
442 float w = ImGui::CalcItemWidth();
443 float spacing = style.ItemInnerSpacing.x;
444 float button_sz = ImGui::GetFrameHeight();
445 ImVec2 combo_pos = ImGui::GetCursorScreenPos();
446 ImGui::PushItemWidth(w - spacing * 2.0f - button_sz * 2.0f);
447 if (ImGui::BeginCombo("##custom combo", "")) {
448 size_t i = 0;
449 for (auto const& color_scale : color_scales) {
450 bool is_selected = (current_color_scale == &color_scale);
451 ImGui::PushID(i++);
452 if (ImGui::Selectable("##foo", is_selected)) {
453 current_color_scale = &color_scale;
454 }
455 ImGui::PopID();
456 ImGui::SameLine();
457 ImGui::Image((void*)(intptr_t)std::get<2>(color_scale).id(),
458 ImVec2(100, 10));
459 ImGui::SameLine();
460 ImGui::SetCursorPosX(
461 ImGui::GetCursorPosX() + ImGui::GetColumnWidth() -
462 ImGui::CalcTextSize(std::get<0>(color_scale)).x -
463 ImGui::GetScrollX() - 2 * ImGui::GetStyle().ItemSpacing.x);
464 ImGui::TextUnformatted(std::get<0>(color_scale));
465 if (is_selected) {
466 ImGui::SetItemDefaultFocus();
467 }
468 }
469 ImGui::EndCombo();
470 }
471 ImGui::PopItemWidth();
472 ImGui::SameLine(0, style.ItemInnerSpacing.x);
473 ImVec2 backup_pos = ImGui::GetCursorScreenPos();
474 ImGui::SetCursorScreenPos(
475 ImVec2(combo_pos.x + style.FramePadding.x, combo_pos.y));
476 ImGui::Image((void*)(intptr_t)std::get<2>(*current_color_scale).id(),
477 ImVec2(100, 10));
478 ImGui::SetCursorScreenPos(backup_pos);
479 ImGui::SameLine();
480 ImGui::SetCursorPosX(
481 ImGui::GetCursorPosX() + ImGui::GetColumnWidth() -
482 ImGui::CalcTextSize(std::get<0>(*current_color_scale)).x -
483 ImGui::GetScrollX() - 2 * ImGui::GetStyle().ItemSpacing.x);
484 ImGui::TextUnformatted(std::get<0>(*current_color_scale));
485 ImGui::End();
486 } else {
487 ImGui::SetNextWindowSize(ImVec2{50, 50});
488 ImGui::SetNextWindowPos(ImVec2{float(win.width() - 50), 0.0f});
489 ImGui::Begin("", nullptr,
490 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
491 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground);
492 if (ImGui::Button("<", ImGui::GetWindowContentRegionMax() -
493 ImGui::GetWindowContentRegionMin())) {
494 menu_open = true;
495 }
496 ImGui::End();
497 }
498 });
499}
500//==============================================================================
501} // namespace tatooine::rendering
502//==============================================================================
Definition: framebuffer.h:10
static DLL_API void unbind()
Definition: indexeddata.h:13
auto vertexbuffer() -> auto &
Definition: indexeddata.h:148
Definition: shader.h:24
Definition: texture.h:61
auto set_wrap_mode(wrap_mode mode) -> void
setting all wrapmodes to same mode
Definition: texture.h:747
Definition: rectilinear_grid.h:38
constexpr auto data() -> ValueType *
Definition: static_multidim_array.h:260
auto Bezier(const char *label, std::vector< float > &handles) -> int
auto BezierValue(float dt01, std::vector< float > const &handles) -> float
DLL_API auto clear_color(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) -> void
DLL_API auto set_back_face_culling() -> void
DLL_API auto set_front_face_culling() -> void
DLL_API auto enable_depth_test() -> void
DLL_API auto disable_depth_test() -> void
DLL_API auto enable_face_culling() -> void
tex2rgba< GLfloat > tex2rgba32f
Definition: texture.h:957
DLL_API auto clear_color_depth_buffer() -> void
tex1rgba< GLfloat > tex1rgba32f
Definition: texture.h:921
DLL_API auto disable_face_culling() -> void
auto upload_tex(std::vector< Tensor > const &data, integral auto const ... res)
Definition: upload.h:41
Definition: camera.h:12
auto interactive(std::vector< line< Real, N > > const &lines)
Definition: line.h:104
auto constexpr scale_matrix(Real s)
Definition: matrices.h:26
auto constexpr translation_matrix(Real const x, Real const y, Real const z)
Definition: matrices.h:11
typename value_type_impl< T >::type value_type
Definition: type_traits.h:280
Definition: viridis.h:12
Definition: shadersource.h:8
Definition: window_listener.h:10
Definition: mat.h:14
Definition: first_person_window.h:15
Definition: vec.h:12