volmetrics
changeset 9:40febfed6cff
rendering isosurfaces / added simple gui
author | Eleni Maria Stea <elene.mst@gmail.com> |
---|---|
date | Sun, 26 Jan 2014 23:13:37 +0200 |
parents | 928954bfefd7 |
children | 8ffa6d61eb56 |
files | Makefile src/main.cc src/mesh.cc src/mesh.h src/volume.cc src/volume.h |
diffstat | 6 files changed, 226 insertions(+), 25 deletions(-) [+] |
line diff
1.1 --- a/Makefile Sat Jan 25 19:25:32 2014 +0200 1.2 +++ b/Makefile Sun Jan 26 23:13:37 2014 +0200 1.3 @@ -9,7 +9,7 @@ 1.4 1.5 CXX = g++ 1.6 CXXFLAGS = -std=c++11 -pedantic -Wall $(dbg) $(opt) $(inc) 1.7 -LDFLAGS = -lGL -lGLU -lGLEW -lglut -limago -lm 1.8 +LDFLAGS = -lGL -lGLU -lGLEW -lglut -limago -lm -lmetasurf -lglui 1.9 1.10 $(bin): $(obj) 1.11 $(CXX) -o $@ $(obj) $(LDFLAGS)
2.1 --- a/src/main.cc Sat Jan 25 19:25:32 2014 +0200 2.2 +++ b/src/main.cc Sun Jan 26 23:13:37 2014 +0200 2.3 @@ -1,27 +1,40 @@ 2.4 #include <GL/glew.h> 2.5 #include <GL/glut.h> 2.6 +#include <GL/glui.h> 2.7 2.8 #include <stdio.h> 2.9 #include <assert.h> 2.10 2.11 +#include <vector> 2.12 + 2.13 +#include "mesh.h" 2.14 #include "volume.h" 2.15 2.16 -//static void init(void); 2.17 -static void display(void); 2.18 -static void reshape(int x, int y); 2.19 -static void keyboard(unsigned char key, int x, int y); 2.20 -static void mouse(int button, int state, int x, int y); 2.21 -static void motion(int x, int y); 2.22 +bool init(void); 2.23 +GLUI *create_ui(void); 2.24 +void display(void); 2.25 +void reshape(int x, int y); 2.26 +void keyboard(unsigned char key, int x, int y); 2.27 +void keyboard_up(unsigned char key, int x, int y); 2.28 +void mouse(int button, int state, int x, int y); 2.29 +void motion(int x, int y); 2.30 2.31 static int win_xsz, win_ysz; 2.32 +static float cam_phi, cam_theta, cam_dist = 6; 2.33 +static std::vector<bool> key_state(256); 2.34 2.35 ///////////////////////////// 2.36 // debug TODO remove 2.37 //////////////////////////// 2.38 -static bool init(); 2.39 2.40 static Volume *vol; 2.41 -static float cur_z; 2.42 +static Mesh *mesh; 2.43 +static float cur_z, thres = 0.5; 2.44 + 2.45 +static int use_orig_vol_res = 1; 2.46 +static int vol_res[3]; // volume sampling resolution x/y/z 2.47 + 2.48 +static GLUI *ui; 2.49 2.50 int main(int argc, char **argv) 2.51 { 2.52 @@ -36,6 +49,7 @@ 2.53 glutDisplayFunc(display); 2.54 glutReshapeFunc(reshape); 2.55 glutKeyboardFunc(keyboard); 2.56 + glutKeyboardUpFunc(keyboard_up); 2.57 glutMouseFunc(mouse); 2.58 glutMotionFunc(motion); 2.59 2.60 @@ -51,9 +65,85 @@ 2.61 return 0; 2.62 } 2.63 2.64 +bool init() 2.65 +{ 2.66 + vol = new Volume; 2.67 + if(!vol->load("data/test1.vol")) { 2.68 + fprintf(stderr, "Failed to load test1.vol"); 2.69 + return false; 2.70 + } 2.71 + mesh = new Mesh; 2.72 + cur_z = 0.5; 2.73 + 2.74 + vol_res[0] = vol->get_slice(0)->get_width(); 2.75 + vol_res[1] = vol->get_slice(0)->get_height(); 2.76 + vol_res[2] = vol->get_slice_count(); 2.77 + 2.78 + if(!(ui = create_ui())) { 2.79 + return false; 2.80 + } 2.81 + 2.82 + return true; 2.83 +} 2.84 + 2.85 +static GLUI_Spinner *res_spin[3]; 2.86 + 2.87 +static void toggle_use_orig(int id) 2.88 +{ 2.89 + for(int i=0; i<3; i++) { 2.90 + if(use_orig_vol_res) { 2.91 + res_spin[i]->disable(); 2.92 + } else { 2.93 + res_spin[i]->enable(); 2.94 + } 2.95 + } 2.96 +} 2.97 + 2.98 +static void thres_change(int id) 2.99 +{ 2.100 + static float prev_thres = thres; 2.101 + 2.102 + if(prev_thres != thres) { 2.103 + prev_thres = thres; 2.104 + mesh->clear(); 2.105 + } 2.106 +} 2.107 + 2.108 +GLUI *create_ui() 2.109 +{ 2.110 + GLUI *ui = GLUI_Master.create_glui("ui"); 2.111 + assert(ui); 2.112 + 2.113 + ui->set_main_gfx_window(glutGetWindow()); 2.114 + 2.115 + GLUI_Spinner *thres_spin = ui->add_spinner("iso threshold", GLUI_SPINNER_FLOAT, &thres, 0, thres_change); 2.116 + thres_spin->set_float_limits(0, 1); 2.117 + 2.118 + GLUI_Panel *res_panel = ui->add_panel("volume resolution"); 2.119 + 2.120 + ui->add_checkbox_to_panel(res_panel, "original resolution", &use_orig_vol_res, 0, toggle_use_orig); 2.121 + 2.122 + static const char *res_spin_name[] = {"x", "y", "z"}; 2.123 + for(int i=0; i<3; i++) { 2.124 + res_spin[i] = ui->add_spinner_to_panel(res_panel, res_spin_name[i], GLUI_SPINNER_INT, vol_res + i); 2.125 + res_spin[i]->set_int_limits(8, 256); // TODO limits as arguments or config 2.126 + res_spin[i]->disable(); 2.127 + } 2.128 + 2.129 + return ui; 2.130 +} 2.131 + 2.132 void display(void) 2.133 { 2.134 - //render 2.135 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 2.136 + 2.137 + glMatrixMode(GL_MODELVIEW); 2.138 + glLoadIdentity(); 2.139 + glTranslatef(0, 0, -cam_dist); 2.140 + glRotatef(cam_phi, 1, 0, 0); 2.141 + glRotatef(cam_theta, 0, 1, 0); 2.142 + 2.143 +/* 2.144 glBindTexture(GL_TEXTURE_3D, vol->get_texture()); 2.145 glEnable(GL_TEXTURE_3D); 2.146 glBegin(GL_QUADS); 2.147 @@ -63,7 +153,17 @@ 2.148 glTexCoord3f(1, 0, cur_z); glVertex3f(1, -1, 0); 2.149 glEnd(); 2.150 glDisable(GL_TEXTURE_3D); 2.151 +*/ 2.152 2.153 + if(mesh->is_empty()) { 2.154 + printf("recalculating isosurface ... "); 2.155 + fflush(stdout); 2.156 + vol->create_mesh(mesh, thres); 2.157 + printf("done.\n"); 2.158 + } 2.159 + mesh->draw(); 2.160 + 2.161 + //TODO: draw threshold 2.162 glutSwapBuffers(); 2.163 assert(glGetError() == GL_NO_ERROR); 2.164 } 2.165 @@ -71,8 +171,11 @@ 2.166 void reshape(int x, int y) 2.167 { 2.168 glViewport(0, 0, x, y); 2.169 + glMatrixMode(GL_PROJECTION); 2.170 + glLoadIdentity(); 2.171 + gluPerspective(45, (float)x / (float)y, 0.5, 500); 2.172 + 2.173 if(x != win_xsz || y != win_ysz) { 2.174 - //TODO raytex_needs_recalc = 1; 2.175 win_xsz = x; 2.176 win_ysz = y; 2.177 } 2.178 @@ -80,42 +183,91 @@ 2.179 2.180 void keyboard(unsigned char key, int x, int y) 2.181 { 2.182 + key_state[(int)key] = true; 2.183 + 2.184 switch(key) { 2.185 case 27: 2.186 exit(0); 2.187 + case 'w': 2.188 + { 2.189 + static bool wire; 2.190 + 2.191 + wire = !wire; 2.192 + glPolygonMode(GL_FRONT_AND_BACK, wire ? GL_LINE : GL_FILL); 2.193 + } 2.194 + break; 2.195 default: 2.196 break; 2.197 } 2.198 } 2.199 2.200 +void keyboard_up(unsigned char key, int x, int y) 2.201 +{ 2.202 + key_state[(int) key] = false; 2.203 +} 2.204 + 2.205 static int prev_x, prev_y; 2.206 +static bool bn_state[32]; 2.207 +static float prev_thres; 2.208 + 2.209 void mouse(int bn, int state, int x, int y) 2.210 { 2.211 prev_x = x; 2.212 prev_y = y; 2.213 + 2.214 + bn_state[bn - GLUT_LEFT_BUTTON] = (state == GLUT_DOWN); 2.215 + 2.216 + if(state == GLUT_DOWN) { 2.217 + prev_thres = thres; 2.218 + } 2.219 + else { 2.220 + if(thres != prev_thres) { 2.221 + mesh->clear(); 2.222 + } 2.223 + } 2.224 } 2.225 2.226 void motion(int x, int y) 2.227 { 2.228 int dx = x - prev_x; 2.229 int dy = y - prev_y; 2.230 + 2.231 + if(!dx && !dy) 2.232 + return; 2.233 + 2.234 prev_x = x; 2.235 prev_y = y; 2.236 2.237 - if(dx != 0) { 2.238 - cur_z = (float)x / (float)win_xsz; 2.239 + if(key_state[(int)'t']) { 2.240 + thres = (float)x / (float)win_xsz; 2.241 + printf("threshold: %f\n", thres); 2.242 + 2.243 + glutPostRedisplay(); 2.244 + return; 2.245 + } 2.246 + 2.247 + // camera 2.248 + if(bn_state[0]) { 2.249 + if(key_state[(int)'z']) { 2.250 + //zoom the camera 2.251 + 2.252 + cam_dist += dy * 0.1; 2.253 + 2.254 + if(cam_dist < 0) 2.255 + cam_dist = 0; 2.256 + } 2.257 + else { 2.258 + //rotate the camera 2.259 + 2.260 + cam_phi += dy * 0.5; 2.261 + cam_theta += dx * 0.5; 2.262 + 2.263 + if(cam_phi > 90) 2.264 + cam_phi = 90; 2.265 + if(cam_phi < -90) 2.266 + cam_phi = -90; 2.267 + } 2.268 + 2.269 glutPostRedisplay(); 2.270 } 2.271 } 2.272 - 2.273 -bool init() 2.274 -{ 2.275 - vol = new Volume; 2.276 - if(!vol->load("data/test1.vol")) { 2.277 - fprintf(stderr, "Failed to load test1.vol"); 2.278 - return false; 2.279 - } 2.280 - cur_z = 0.5; 2.281 - 2.282 - return true; 2.283 -}
3.1 --- a/src/mesh.cc Sat Jan 25 19:25:32 2014 +0200 3.2 +++ b/src/mesh.cc Sun Jan 26 23:13:37 2014 +0200 3.3 @@ -21,6 +21,11 @@ 3.4 normals.clear(); 3.5 } 3.6 3.7 +bool Mesh::is_empty() const 3.8 +{ 3.9 + return vertices.empty(); 3.10 +} 3.11 + 3.12 void Mesh::draw() const 3.13 { 3.14 size_t sz = vertices.size();
4.1 --- a/src/mesh.h Sat Jan 25 19:25:32 2014 +0200 4.2 +++ b/src/mesh.h Sun Jan 26 23:13:37 2014 +0200 4.3 @@ -16,6 +16,7 @@ 4.4 void add_normal(const Vector3 &normal); 4.5 4.6 void clear(); 4.7 + bool is_empty() const; 4.8 4.9 void draw() const; 4.10 };
5.1 --- a/src/volume.cc Sat Jan 25 19:25:32 2014 +0200 5.2 +++ b/src/volume.cc Sun Jan 26 23:13:37 2014 +0200 5.3 @@ -10,6 +10,9 @@ 5.4 #include <string> 5.5 #include <vector> 5.6 5.7 +#include <metasurf.h> 5.8 + 5.9 +#include "mesh.h" 5.10 #include "volume.h" 5.11 5.12 static char *strip_whitespaces(char *buf); 5.13 @@ -163,6 +166,38 @@ 5.14 return vol_tex; 5.15 } 5.16 5.17 +static Mesh *cur_mesh; 5.18 +static Volume *cur_vol; 5.19 + 5.20 +static float cb_eval(float x, float y, float z) 5.21 +{ 5.22 + const Image *img = cur_vol->get_slice_by_z((z + 1) / 2.0); 5.23 + const float *pixels = img->get_pixels(); 5.24 + 5.25 + int px = (x + 1) / 2.0 * img->get_width(); 5.26 + int py = (y + 1) / 2.0 * img->get_height(); 5.27 + 5.28 + return pixels[px + img->get_width() * py]; 5.29 +} 5.30 + 5.31 +void Volume::create_mesh(Mesh *mesh, float threshold) 5.32 +{ 5.33 + cur_mesh = mesh; 5.34 + cur_vol = this; 5.35 + 5.36 + metasurface *ms = msurf_create(); 5.37 + msurf_threshold(ms, threshold); 5.38 + msurf_resolution(ms, width, height, slices.size()); 5.39 + msurf_vertex_func(ms, 5.40 + [](float x, float y, float z){cur_mesh->add_vertex(Vector3(x, y, z));}); 5.41 + msurf_normal_func(ms, 5.42 + [](float x, float y, float z){cur_mesh->add_normal(Vector3(x, y, z));}); 5.43 + 5.44 + msurf_eval_func(ms, cb_eval); 5.45 + msurf_polygonize(ms); 5.46 + msurf_free(ms); 5.47 +} 5.48 + 5.49 void Volume::draw() const 5.50 { 5.51 }
6.1 --- a/src/volume.h Sat Jan 25 19:25:32 2014 +0200 6.2 +++ b/src/volume.h Sun Jan 26 23:13:37 2014 +0200 6.3 @@ -4,6 +4,8 @@ 6.4 #include <vector> 6.5 #include "image.h" 6.6 6.7 +class Mesh; 6.8 + 6.9 class Volume { 6.10 private: 6.11 std::vector<Image> slices; 6.12 @@ -25,13 +27,19 @@ 6.13 6.14 bool push_slice(Image &&slice); 6.15 const Image *get_slice(int num_slice) const; 6.16 + 6.17 + // z must be in [0, 1] 6.18 const Image *get_slice_by_z(float z) const; 6.19 + 6.20 int get_slice_count() const; 6.21 6.22 + // z must be in [0, 1] 6.23 int get_slice_idx_by_z(float z) const; 6.24 6.25 unsigned int get_texture() const; 6.26 6.27 + void create_mesh(Mesh *mesh, float threshold); 6.28 + 6.29 void draw() const; 6.30 }; 6.31