diff --git a/CMakeLists.txt b/CMakeLists.txt index 1adb795..9d493fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,9 @@ find_package(STIM REQUIRED) find_package(OpenGL REQUIRED) find_package(GLUT REQUIRED) +#find BOOST +find_package(Boost REQUIRED) + #find the pthreads package find_package(Threads) @@ -20,6 +23,7 @@ include_directories( ${STIM_INCLUDE_DIRS} ${GLUT_INCLUDE_DIR} ${OpenGL_INCLUDE_DIRS} + ${Boost_INCLUDE_DIR} ) #Assign source files to the appropriate variables diff --git a/main.cpp b/main.cpp index 0e366ac..c73ddd6 100644 --- a/main.cpp +++ b/main.cpp @@ -4,16 +4,18 @@ #include #include -#include +#include +#include #define theta_scale 0.01 #define phi_scale 0.01 +#define zoom_scale 0.1 //create a global camera that will specify the viewport stim::camera cam; int mx, my; //mouse coordinates in the window space -stim::sph_harmonics S; +stim::gl_spharmonics S; float d = 1.5; //initial distance between the camera and the sphere @@ -21,9 +23,7 @@ bool rotate_zoom = true; //sets the current camera mode (rotation = true, zoom = stim::arglist args; //class for processing command line arguments -#ifdef _WIN32 - args.set_ansi(false); -#endif +bool zaxis = false; //render the z-axis (set via a command line flag) bool init(){ @@ -36,16 +36,6 @@ bool init(){ cam.setFOV(40); //initialize the texture map stuff - - srand(time(NULL)); - unsigned int T = 40; - double c; - for(unsigned int t = 0; t < T; t++){ - - c = (double)rand() / RAND_MAX - 0.5; - S.push(c); - } - S.glInit(256); return true; @@ -67,9 +57,9 @@ void display(){ glLoadIdentity(); //set it to the identity matrix //get the camera parameters - stim::vec p = cam.getPosition(); - stim::vec u = cam.getUp(); - stim::vec d = cam.getDirection(); + stim::vec3 p = cam.getPosition(); + stim::vec3 u = cam.getUp(); + stim::vec3 d = cam.getDirection(); //specify the camera parameters to OpenGL gluLookAt(p[0], p[1], p[2], d[0], d[1], d[2], u[0], u[1], u[2]); @@ -77,6 +67,18 @@ void display(){ //draw the sphere S.glRender(); + //glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + //draw the z-axis if requested + if(zaxis){ + glDisable(GL_TEXTURE_2D); + glColor3f(0.0f, 1.0f, 0.0f); + glBegin(GL_LINES); + glVertex3f(0.0, 0.0, 0.0); + glVertex3f(0.0, 0.0, 100.0); + glEnd(); + } + //flush commands on the GPU glutSwapBuffers(); } @@ -86,7 +88,7 @@ void mouse_press(int button, int state, int x, int y){ //set the camera motion mode based on the mouse button pressed if(button == GLUT_LEFT_BUTTON) rotate_zoom = true; - else if(button == GLUT_MIDDLE_BUTTON) + else if(button == GLUT_RIGHT_BUTTON) rotate_zoom = false; //if the mouse is pressed @@ -108,7 +110,7 @@ void mouse_drag(int x, int y){ } //otherwize zoom else{ - cam.Push(my - y); + cam.Push(zoom_scale*(my - y)); } //update the mouse position @@ -120,20 +122,189 @@ void mouse_drag(int x, int y){ void process_arguments(int argc, char* argv[]){ args.add("help", "prints this help"); + args.add("rand", "generates a random set of SH coefficients", "", "[N min max]"); + args.add("sparse", "generates a function based on a set of sparse basis functions", "", "[l0 m0 c0 l1 m1 c1 l2 m2 c2 ...]"); + args.add("basis", "displays the specified SH basis function", "", "n, or [l m]"); + args.add("obj", "approximates a geometric object given as a Wavefront OBJ file", "", "filename"); + args.add("out", "filename for outputting spherical harmonics coefficients", "", "filename"); + args.add("zaxis", "render the z-axis as a green line"); //process the command line arguments args.parse(argc, argv); + //set the z-axis flag + if(args["zaxis"].is_set()) + zaxis = true; + + //if arguments are specified, push them as coefficients + if(args.nargs() > 0){ + //push all of the arguments to the spherical harmonics class as coefficients + for(unsigned int a = 0; a < args.nargs(); a++) + S.push(atof(args.arg(a).c_str())); + } + + //if the user wants to use a random set of SH coefficients + else if(args["rand"].is_set()){ + + //return an error if the user specifies both fixed and random coefficients + if(args.nargs() != 0){ + std::cout<<"Error: both fixed and random coefficients are specified"< C; //vector of 1D coefficients + unsigned int Cmax = 0; //maximum coefficient provided + + std::vector V; //vector of 1D coefficient values + + unsigned int c; + int l, m; + double v; + //for each provided coefficient + for(unsigned int i = 0; i < nC; i++){ + + //load data for a single coefficient from the command line + l = args["sparse"].as_int( i * 3 + 0 ); + m = args["sparse"].as_int( i * 3 + 1 ); + v = args["sparse"].as_float( i * 3 + 2 ); + + //calculate the 1D coefficient + c = pow(l + 1, 2) - (l - m) - 1; + + //update the maximum coefficient index + if(c > Cmax) Cmax = c; - //push all of the arguments to the spherical harmonics class as coefficients - for(unsigned int a = 0; a < args.nargs(); a++) - S.push(atof(args.arg(a).c_str())); + //insert the coefficient and value into vectors + C.push_back(c); + V.push_back(v); + } + + //set the size of the SH coefficient array + S.resize(Cmax + 1); + + //insert each coefficient + for(unsigned int i = 0; i < nC; i++){ + S.setc(C[i], V[i]); + } + + } + else if(args["obj"].is_set()){ + + std::string filename = args["obj"].as_string(0); + unsigned int l = args["obj"].as_int(1); + + //create an obj object + stim::obj object(filename); + + //get the centroid of the object + stim::vec c = object.centroid(); + + //get the number of vertices in the model + unsigned int nV = object.numV(); + + //for each vertex in the model, create an MC sample + std::vector< stim::vec > spherical; + stim::vec sample; + stim::vec centered; + for(unsigned int i = 0; i < nV; i++){ + + sample = object.getV(i); //get a vertex in cartesian coordinates + centered = sample - c; + spherical.push_back(centered.cart2sph()); + } + + //generate the spherical PDF + stim::spharmonics P; + P.pdf(spherical, l, l); + + //begin Monte-Carlo sampling, using the model vertices as samples + S.mcBegin(l, l); + double theta, phi, fx, px; + for(unsigned int i = 0; i < nV; i++){ + theta = spherical[i][1]; + phi = spherical[i][2]; + fx = spherical[i][0]; + px = P(theta, phi); + S.mcSample(theta, phi, fx / px); + } + S.mcEnd(); + } + + //if the user specifies an SH basis function + else if(args["basis"].is_set()){ + + unsigned int n; + + //if the user specifies one index for the basis function + if(args["basis"].nargs() == 1) + n = args["basis"].as_int(0); + else if(args["basis"].nargs() == 2){ + int l = args["basis"].as_int(0); //2D indexing (l, m) + int m = args["basis"].as_int(1); + + n = pow(l+1, 2) - (l - m) - 1; //calculate the 1D index + } + + //add zeros for the first (n-1) coefficients + for(unsigned int c = 0; c < n; c++) + S.push(0); + + //add the n'th coefficient + S.push(1); + } + + //output the spherical harmonics coefficients if requested + if(args["out"].is_set()){ + + if(args["out"].nargs() == 0) + std::cout<