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