Commit e4d08b323265fb544a159d3d3e7ccd2f15f31fe4
1 parent
31c961c7
implemented a new spherical harmonics renderer
Showing
2 changed files
with
323 additions
and
110 deletions
Show diff stats
1 | +# Copyright (c) 2012-2016 DreamWorks Animation LLC | |
2 | +# | |
3 | +# All rights reserved. This software is distributed under the | |
4 | +# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) | |
5 | +# | |
6 | +# Redistributions of source code must retain the above copyright | |
7 | +# and license notice and the following restrictions and disclaimer. | |
8 | +# | |
9 | +# * Neither the name of DreamWorks Animation nor the names of | |
10 | +# its contributors may be used to endorse or promote products derived | |
11 | +# from this software without specific prior written permission. | |
12 | +# | |
13 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
14 | +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
15 | +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
16 | +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
17 | +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, | |
18 | +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
19 | +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
20 | +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
21 | +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | +# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE | |
25 | +# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. | |
26 | +# | |
27 | + | |
28 | +#-*-cmake-*- | |
29 | +# - Find GLEW | |
30 | +# | |
31 | +# Author : Nicholas Yue yue.nicholas@gmail.com | |
32 | +# | |
33 | +# This auxiliary CMake file helps in find the GLEW headers and libraries | |
34 | +# | |
35 | +# GLEW_FOUND set if Glew is found. | |
36 | +# GLEW_INCLUDE_DIR GLEW's include directory | |
37 | +# GLEW_glew_LIBRARY GLEW libraries | |
38 | +# GLEW_glewmx_LIBRARY GLEWmx libraries (Mulitple Rendering Context) | |
39 | + | |
40 | +FIND_PACKAGE ( PackageHandleStandardArgs ) | |
41 | + | |
42 | +FIND_PATH( GLEW_LOCATION include/GL/glew.h | |
43 | + "$ENV{GLEW_ROOT}" | |
44 | + NO_DEFAULT_PATH | |
45 | + NO_SYSTEM_ENVIRONMENT_PATH | |
46 | + ) | |
47 | + | |
48 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( GLEW | |
49 | + REQUIRED_VARS GLEW_LOCATION | |
50 | + ) | |
51 | + | |
52 | +IF ( GLEW_LOCATION ) | |
53 | + | |
54 | + SET( GLEW_INCLUDE_DIR "${GLEW_LOCATION}/include" CACHE STRING "GLEW include path") | |
55 | + | |
56 | + SET ( ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) | |
57 | + IF (GLEW_USE_STATIC_LIBS) | |
58 | + IF (APPLE) | |
59 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") | |
60 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | |
61 | + NO_DEFAULT_PATH | |
62 | + NO_SYSTEM_ENVIRONMENT_PATH | |
63 | + ) | |
64 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | |
65 | + NO_DEFAULT_PATH | |
66 | + NO_SYSTEM_ENVIRONMENT_PATH | |
67 | + ) | |
68 | + # MESSAGE ( "APPLE STATIC" ) | |
69 | + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} ) | |
70 | + ELSEIF (WIN32) | |
71 | + # Link library | |
72 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") | |
73 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32S PATHS ${GLEW_LOCATION}/lib ) | |
74 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32MXS PATHS ${GLEW_LOCATION}/lib ) | |
75 | + ELSE (APPLE) | |
76 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") | |
77 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | |
78 | + NO_DEFAULT_PATH | |
79 | + NO_SYSTEM_ENVIRONMENT_PATH | |
80 | + ) | |
81 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | |
82 | + NO_DEFAULT_PATH | |
83 | + NO_SYSTEM_ENVIRONMENT_PATH | |
84 | + ) | |
85 | + # MESSAGE ( "LINUX STATIC" ) | |
86 | + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} ) | |
87 | + ENDIF (APPLE) | |
88 | + ELSE () | |
89 | + IF (APPLE) | |
90 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib") | |
91 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib ) | |
92 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib ) | |
93 | + ELSEIF (WIN32) | |
94 | + # Link library | |
95 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") | |
96 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32 PATHS ${GLEW_LOCATION}/lib ) | |
97 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32mx PATHS ${GLEW_LOCATION}/lib ) | |
98 | + # Load library | |
99 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") | |
100 | + FIND_LIBRARY ( GLEW_DLL_PATH GLEW32 PATHS ${GLEW_LOCATION}/bin | |
101 | + NO_DEFAULT_PATH | |
102 | + NO_SYSTEM_ENVIRONMENT_PATH | |
103 | + ) | |
104 | + FIND_LIBRARY ( GLEWmx_DLL_PATH GLEW32mx PATHS ${GLEW_LOCATION}/bin | |
105 | + NO_DEFAULT_PATH | |
106 | + NO_SYSTEM_ENVIRONMENT_PATH | |
107 | + ) | |
108 | + ELSE (APPLE) | |
109 | + # Unices | |
110 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | |
111 | + NO_DEFAULT_PATH | |
112 | + NO_SYSTEM_ENVIRONMENT_PATH | |
113 | + ) | |
114 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | |
115 | + NO_DEFAULT_PATH | |
116 | + NO_SYSTEM_ENVIRONMENT_PATH | |
117 | + ) | |
118 | + ENDIF (APPLE) | |
119 | + ENDIF () | |
120 | + # MUST reset | |
121 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES}) | |
122 | + | |
123 | + SET( GLEW_GLEW_LIBRARY ${GLEW_LIBRARY_PATH} CACHE STRING "GLEW library") | |
124 | + SET( GLEW_GLEWmx_LIBRARY ${GLEWmx_LIBRARY_PATH} CACHE STRING "GLEWmx library") | |
125 | + | |
126 | +ENDIF () | ... | ... |
main.cpp
... | ... | @@ -9,16 +9,15 @@ |
9 | 9 | #include <stim/visualization/gl_spharmonics.h> |
10 | 10 | #include <stim/math/constants.h> |
11 | 11 | |
12 | -#define theta_scale 0.01 | |
13 | -#define phi_scale 0.01 | |
14 | -#define zoom_scale 0.1 | |
12 | +#define theta_scale 0.01f | |
13 | +#define phi_scale 0.01f | |
14 | +#define zoom_scale 0.1f | |
15 | 15 | |
16 | 16 | //create a global camera that will specify the viewport |
17 | 17 | stim::camera cam; |
18 | 18 | int mx, my; //mouse coordinates in the window space |
19 | 19 | |
20 | -stim::spharmonics<double> S; | |
21 | -stim::gl_spharmonics<double> R; //spherical harmonics to render | |
20 | +stim::gl_spharmonics<float> SH(300); //spherical harmonics to render | |
22 | 21 | |
23 | 22 | float d = 1.5; //initial distance between the camera and the sphere |
24 | 23 | |
... | ... | @@ -26,13 +25,19 @@ bool rotate_zoom = true; //sets the current camera mode (rotation = true, zoom = |
26 | 25 | |
27 | 26 | stim::arglist args; //class for processing command line arguments |
28 | 27 | |
29 | -bool zaxis = false; //render the z-axis (set via a command line flag) | |
28 | +bool axis = false; //render the z-axis (set via a command line flag) | |
30 | 29 | |
31 | 30 | /// INTERPOLATION |
32 | -stim::gl_spharmonics<double> Si; | |
31 | +//stim::gl_spharmonics<double> Si; | |
33 | 32 | bool interp = false; //if we are interpolating |
34 | -float alpha = 0.0; //alpha value for interpolation | |
35 | -float dalpha = 0.1; //change in alpha value with a key press | |
33 | +float alpha = 0.0f; //alpha value for interpolation | |
34 | +float dalpha = 0.1f; //change in alpha value with a key press | |
35 | + | |
36 | +/// Visualization flags | |
37 | +bool mag = true; | |
38 | +bool cmap = true; | |
39 | +bool displace = true; | |
40 | +bool light = true; | |
36 | 41 | |
37 | 42 | bool init(){ |
38 | 43 | |
... | ... | @@ -45,11 +50,47 @@ bool init(){ |
45 | 50 | cam.setFOV(40); |
46 | 51 | |
47 | 52 | //initialize the texture map stuff |
48 | - R.glInit(256); | |
53 | + //R.glInit(256); | |
49 | 54 | |
50 | 55 | return true; |
51 | 56 | } |
52 | 57 | |
58 | +void render_axes() { | |
59 | + glDisable(GL_TEXTURE_2D); //turn off texture mapping | |
60 | + glBegin(GL_LINES); | |
61 | + glColor3f(1.0f, 0.0f, 0.0f); //set the color to RED and render X | |
62 | + glVertex3f(0.0, 0.0, 0.0); | |
63 | + glVertex3f(100.0, 0.0, 0.0); | |
64 | + | |
65 | + glColor3f(0.0f, 1.0f, 0.0f); //set the color to RED and render X | |
66 | + glVertex3f(0.0, 0.0, 0.0); | |
67 | + glVertex3f(0.0, 100.0, 0.0); | |
68 | + | |
69 | + glColor3f(0.0f, 0.0f, 1.0f); //set the color to RED and render X | |
70 | + glVertex3f(0.0, 0.0, 0.0); | |
71 | + glVertex3f(0.0, 0.0, 100.0); | |
72 | + glEnd(); | |
73 | +} | |
74 | + | |
75 | +void render_lights() { | |
76 | + | |
77 | + stim::vec3<float> view = cam.getDirection(); //get the camera view direction | |
78 | + stim::vec3<float> up = cam.getUp(); //get the camera up direction | |
79 | + stim::vec3<float> left = view.cross(up).norm(); //create a vector pointing to the left | |
80 | + | |
81 | + GLfloat light0_diffuse[] = { 0.5f, 0.5f, 0.5f, 1 }; //create a directional light shining from the viewer's left | |
82 | + GLfloat light0_position[] = { left[0], left[1], left[2], 0.0 }; | |
83 | + glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); | |
84 | + glLightfv(GL_LIGHT0, GL_POSITION, light0_position); | |
85 | + | |
86 | + GLfloat light1_diffuse[] = { 0.8f, 0.8f, 0.8f, 1 }; //create a directional light shining from the viewer's position | |
87 | + GLfloat light1_position[] = { -view[0], -view[1], -view[2], 0.0 }; | |
88 | + glLightfv(GL_LIGHT1, GL_DIFFUSE, light0_diffuse); | |
89 | + glLightfv(GL_LIGHT1, GL_POSITION, light1_position); | |
90 | + | |
91 | + | |
92 | +} | |
93 | + | |
53 | 94 | //code that is run every time the user changes something |
54 | 95 | void display(){ |
55 | 96 | //clear the screen |
... | ... | @@ -73,28 +114,28 @@ void display(){ |
73 | 114 | //specify the camera parameters to OpenGL |
74 | 115 | gluLookAt(p[0], p[1], p[2], d[0], d[1], d[2], u[0], u[1], u[2]); |
75 | 116 | |
76 | - //draw the sphere | |
77 | - if (interp) | |
78 | - R = (S * (1.0f - alpha) + Si * alpha); | |
79 | - else | |
80 | - R = S; | |
81 | - R.glRender(); | |
82 | - | |
83 | - | |
84 | - //glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | |
85 | - | |
86 | - //draw the z-axis if requested | |
87 | - if(zaxis){ | |
88 | - glDisable(GL_TEXTURE_2D); | |
89 | - glColor3f(0.0f, 1.0f, 0.0f); | |
90 | - glBegin(GL_LINES); | |
91 | - glVertex3f(0.0, 0.0, 0.0); | |
92 | - glVertex3f(0.0, 0.0, 100.0); | |
93 | - glEnd(); | |
117 | + if (light) { | |
118 | + glEnable(GL_LIGHTING); | |
119 | + glEnable(GL_LIGHT0); | |
120 | + glEnable(GL_LIGHT1); | |
121 | + } | |
122 | + | |
123 | + glEnable(GL_COLOR_MATERIAL); | |
124 | + glEnable(GL_CULL_FACE); | |
125 | + glEnable(GL_DEPTH_TEST); | |
126 | + | |
127 | + render_lights(); //render the lights | |
128 | + glColor3f(1.0, 1.0, 1.0); | |
129 | + SH.render(); | |
130 | + | |
131 | + if (light) { | |
132 | + glDisable(GL_LIGHTING); //disable lighting to render the axes | |
133 | + glDisable(GL_LIGHT0); | |
134 | + glDisable(GL_LIGHT1); | |
94 | 135 | } |
95 | 136 | |
96 | - //flush commands on the GPU | |
97 | - glutSwapBuffers(); | |
137 | + if(axis) render_axes(); //render the axes if the user requests them | |
138 | + glutSwapBuffers(); //swap in the back buffer (double-buffering is used to prevent tearing) | |
98 | 139 | } |
99 | 140 | |
100 | 141 | void mouse_press(int button, int state, int x, int y){ |
... | ... | @@ -104,11 +145,8 @@ void mouse_press(int button, int state, int x, int y){ |
104 | 145 | rotate_zoom = true; |
105 | 146 | else if(button == GLUT_RIGHT_BUTTON) |
106 | 147 | rotate_zoom = false; |
107 | - | |
108 | - //if the mouse is pressed | |
109 | - if(state == GLUT_DOWN){ | |
110 | - //set the current mouse position | |
111 | - mx = x; my = y; | |
148 | + if(state == GLUT_DOWN){ //if the mouse is pressed | |
149 | + mx = x; my = y; //set the current mouse position | |
112 | 150 | } |
113 | 151 | } |
114 | 152 | |
... | ... | @@ -139,28 +177,26 @@ float uniformRandom() |
139 | 177 | } |
140 | 178 | |
141 | 179 | std::vector<stim::vec3 <float> > |
142 | -sample_sphere(int num_samples, float radius = 1.0) | |
143 | -{ | |
180 | +sample_sphere(int num_samples, float radius = 1.0) { | |
144 | 181 | |
145 | - float solidAngle = stim::TAU; ///Solid angle to sample over | |
146 | - float PHI[2], Z[2], range; ///Range of angles in cylinderical coordinates | |
147 | - PHI[0] = solidAngle/2; ///project the solid angle into spherical coords | |
148 | - PHI[1] = asin(0); /// | |
149 | - Z[0] = cos(PHI[0]); ///project the z into spherical coordinates | |
150 | - Z[1] = cos(PHI[1]); /// | |
151 | - range = Z[0] - Z[1]; ///the range of all possible z values. | |
182 | + float solidAngle = (float)stim::TAU; ///Solid angle to sample over | |
183 | + float PHI[2], Z[2], range; ///Range of angles in cylinderical coordinates | |
184 | + PHI[0] = solidAngle/2; ///project the solid angle into spherical coords | |
185 | + PHI[1] = (float)asin(0); | |
186 | + Z[0] = cos(PHI[0]); ///project the z into spherical coordinates | |
187 | + Z[1] = cos(PHI[1]); | |
188 | + range = Z[0] - Z[1]; ///the range of all possible z values. | |
152 | 189 | |
153 | - float z, theta, phi; /// temporary individual | |
190 | + float z, theta, phi; /// temporary individual | |
154 | 191 | |
155 | 192 | std::vector<stim::vec3<float> > samples; |
156 | 193 | |
157 | - //srand(time(NULL)); ///set random seed | |
158 | - srand(100); ///set random seed | |
194 | + srand(100); ///set random seed | |
159 | 195 | |
160 | 196 | for(int i = 0; i < num_samples; i++) |
161 | 197 | { |
162 | 198 | z = uniformRandom()*range + Z[1]; |
163 | - theta = uniformRandom() * stim::TAU; | |
199 | + theta = uniformRandom() * (float)stim::TAU; | |
164 | 200 | phi = acos(z); |
165 | 201 | stim::vec3<float> sph(1, theta, phi); |
166 | 202 | stim::vec3<float> cart = sph.sph2cart(); |
... | ... | @@ -187,37 +223,81 @@ sample_sphere(int num_samples, float radius = 1.0) |
187 | 223 | return samples; |
188 | 224 | } |
189 | 225 | |
226 | +std::vector<stim::vec3<float>> obj2vec3(stim::obj<float>& o) { | |
227 | + stim::vec3<float> c = o.centroid(); //calculate the centroid | |
228 | + size_t nv = o.numV(); //get the number of vertices in the obj file | |
229 | + std::vector<stim::vec3<float>> vlist(nv); //create an array to store the vertices | |
230 | + stim::vec3<float> p, v, s; | |
231 | + for (size_t vi = 0; vi < nv; vi++) { //for each vertex in the obj file | |
232 | + v = o.getV(vi); | |
233 | + p = (v - c); //center and normalize | |
234 | + s = p.cart2sph(); //convert to spherical coordinates | |
235 | + vlist[vi] = s; //store the spherical coordinates in the point list | |
236 | + } | |
237 | + return vlist; | |
238 | +} | |
239 | + | |
240 | +void advertise() { | |
241 | + std::cout << "usage: shview c0 c1 c2 c3 ... --option [A B C]" << std::endl; | |
242 | + std::cout << "examples:" << std::endl; | |
243 | + std::cout << " generate a spherical function with 4 coefficients (l=0 to 2)" << std::endl; | |
244 | + std::cout << " shview 1.3 0.2 2.3 1.34" << std::endl; | |
245 | + std::cout << " display a spherical function representing the spherical harmonic l = 3, m = -2" << std::endl; | |
246 | + std::cout << " shview --basis 3 -2" << std::endl; | |
247 | + std::cout << args.str(); | |
248 | + exit(0); | |
249 | +} | |
250 | + | |
190 | 251 | void process_arguments(int argc, char* argv[]){ |
191 | 252 | |
192 | 253 | args.add("help", "prints this help"); |
254 | + args.section("Coefficients"); | |
255 | + args.add("coef", "specify spherical harmonic coefficients", "", "c0 c1 c2 c3 ..."); | |
193 | 256 | args.add("rand", "generates a random set of SH coefficients", "", "[N min max]"); |
194 | 257 | args.add("sparse", "generates a function based on a set of sparse basis functions", "", "[l0 m0 c0 l1 m1 c1 l2 m2 c2 ...]"); |
195 | - args.add("basis", "displays the specified SH basis function", "", "n, or [l m]"); | |
258 | + args.section("Projection"); | |
259 | + args.add("image", "approximates a spherical function represented by an image", "", "filename1.ppm filename2.ppm"); | |
260 | + args.add("n", "number of spherical harmonics coefficients to use for a projection", "10", "positive integer"); | |
261 | + args.add("basis", "displays the specified SH basis function", "", "n, or [l m]"); | |
196 | 262 | args.add("obj", "approximates a geometric object given as a Wavefront OBJ file", "", "filename"); |
197 | 263 | args.add("out", "filename for outputting spherical harmonics coefficients", "", "filename"); |
198 | - args.add("zaxis", "render the z-axis as a green line"); | |
199 | 264 | args.add("pdf", "outputs the PDF if an OBJ files is given"); |
265 | + args.section("Visualization"); | |
266 | + args.add("axis", "render the z-axis as a green line"); | |
267 | + args.add("nodisp", "render the spherical function without displacement"); | |
268 | + args.add("nocmap", "render the spherical function without color mapping"); | |
269 | + args.add("nomag", "render the spherical function without calculating the absolute value (negative values are displaced negatively"); | |
270 | + args.add("nolight", "render the spherical function without lighting"); | |
200 | 271 | args.add("interp", "interpolates between two specified sets of coefficients", "", "[c0 c1 c2 c3 ...]"); |
201 | 272 | |
202 | 273 | //process the command line arguments |
203 | 274 | args.parse(argc, argv); |
204 | 275 | |
205 | - //set the z-axis flag | |
206 | - if(args["zaxis"].is_set()) | |
207 | - zaxis = true; | |
208 | - | |
209 | - if (args["interp"]) { //if an interpolation harmonic is provided | |
210 | - for (unsigned int a = 0; a < args["interp"].nargs(); a++) | |
211 | - Si.push(args["interp"].as_float(a)); | |
276 | + //if the user asks for help, give it and exit | |
277 | + if (args["help"].is_set()) { | |
278 | + advertise(); | |
212 | 279 | } |
213 | 280 | |
281 | + //set the z-axis flag | |
282 | + if(args["axis"].is_set()) | |
283 | + axis = true; | |
284 | + if (args["nodisp"]) displace = false; | |
285 | + if (args["nocmap"]) cmap = false; | |
286 | + if (args["nomag"]) mag = false; | |
287 | + if (args["nolight"]) light = false; | |
288 | + SH.rendermode(displace, cmap, mag); | |
289 | + | |
290 | + //if (args["interp"]) { //if an interpolation harmonic is provided | |
291 | + // for (unsigned int a = 0; a < args["interp"].nargs(); a++) | |
292 | + // Si.push(args["interp"].as_float(a)); | |
293 | + //} | |
294 | + | |
214 | 295 | //if arguments are specified, push them as coefficients |
215 | - if(args.nargs() > 0){ | |
296 | + if(args["coef"]){ | |
216 | 297 | //push all of the arguments to the spherical harmonics class as coefficients |
217 | - for(unsigned int a = 0; a < args.nargs(); a++) | |
218 | - S.push(atof(args.arg(a).c_str())); | |
298 | + for(unsigned int a = 0; a < args["coef"].nargs(); a++) | |
299 | + SH.push((float)args["coef"].as_float(a)); | |
219 | 300 | } |
220 | - | |
221 | 301 | //if the user wants to use a random set of SH coefficients |
222 | 302 | else if(args["rand"].is_set()){ |
223 | 303 | |
... | ... | @@ -228,21 +308,21 @@ void process_arguments(int argc, char* argv[]){ |
228 | 308 | } |
229 | 309 | |
230 | 310 | //seed the random number generator |
231 | - srand(time(NULL)); | |
311 | + srand((unsigned int)time(NULL)); | |
232 | 312 | |
233 | - unsigned int N = args["rand"].as_int(0); //get the number of random coefficients | |
234 | - double Cmin = args["rand"].as_float(1); //get the minimum and maximum coefficient values | |
235 | - double Cmax = args["rand"].as_float(2); | |
313 | + unsigned int N = args["rand"].as_int(0); //get the number of random coefficients | |
314 | + float Cmin = (float)args["rand"].as_float(1); //get the minimum and maximum coefficient values | |
315 | + float Cmax = (float)args["rand"].as_float(2); | |
236 | 316 | |
237 | 317 | //generate the coefficients |
238 | 318 | for(unsigned int c = 0; c < N; c++){ |
239 | 319 | |
240 | - double norm = (double) rand() / RAND_MAX; //calculate a random number in the range [0, 1] | |
241 | - double scaled = norm * (Cmax - Cmin) + Cmin; //scale the random number to [Cmin, Cmax] | |
242 | - S.push(scaled); //push the value as a coefficient | |
320 | + float norm = (float) rand() / RAND_MAX; //calculate a random number in the range [0, 1] | |
321 | + float scaled = norm * (Cmax - Cmin) + Cmin; //scale the random number to [Cmin, Cmax] | |
322 | + SH.push(scaled); //push the value as a coefficient | |
243 | 323 | } |
244 | 324 | } |
245 | - else if(args["sparse"].is_set()){ | |
325 | + else if (args["sparse"].is_set()) { | |
246 | 326 | |
247 | 327 | //calculate the number of sparse coefficients |
248 | 328 | unsigned int nC = args["sparse"].nargs() / 3; |
... | ... | @@ -256,36 +336,59 @@ void process_arguments(int argc, char* argv[]){ |
256 | 336 | int l, m; |
257 | 337 | double v; |
258 | 338 | //for each provided coefficient |
259 | - for(unsigned int i = 0; i < nC; i++){ | |
339 | + for (unsigned int i = 0; i < nC; i++) { | |
260 | 340 | |
261 | 341 | //load data for a single coefficient from the command line |
262 | - l = args["sparse"].as_int( i * 3 + 0 ); | |
263 | - m = args["sparse"].as_int( i * 3 + 1 ); | |
264 | - v = args["sparse"].as_float( i * 3 + 2 ); | |
342 | + l = args["sparse"].as_int(i * 3 + 0); | |
343 | + m = args["sparse"].as_int(i * 3 + 1); | |
344 | + v = args["sparse"].as_float(i * 3 + 2); | |
265 | 345 | |
266 | 346 | //calculate the 1D coefficient |
267 | 347 | c = pow(l + 1, 2) - (l - m) - 1; |
268 | 348 | |
269 | 349 | //update the maximum coefficient index |
270 | - if(c > Cmax) Cmax = c; | |
350 | + if (c > Cmax) Cmax = c; | |
271 | 351 | |
272 | 352 | //insert the coefficient and value into vectors |
273 | 353 | C.push_back(c); |
274 | - V.push_back(v); | |
354 | + V.push_back(v); | |
275 | 355 | } |
276 | 356 | |
277 | 357 | //set the size of the SH coefficient array |
278 | - S.resize(Cmax + 1); | |
279 | - | |
358 | + SH.resize(Cmax + 1); | |
359 | + | |
280 | 360 | //insert each coefficient |
281 | - for(unsigned int i = 0; i < nC; i++){ | |
282 | - S.setc(C[i], V[i]); | |
361 | + for (unsigned int i = 0; i < nC; i++) { | |
362 | + SH.setc(C[i], V[i]); | |
363 | + } | |
364 | + } | |
365 | + else if (args["image"]) { | |
366 | + if (args["image"].nargs() == 0) { | |
367 | + std::cout << "ERROR: an image file must be specified as an argument to --image" << std::endl; | |
368 | + exit(1); | |
369 | + } | |
370 | + stim::image<float> I(args["image"].as_string(0)); //load the image | |
371 | + if (I.channels() > 1) I = I.channel(0); //if a color image is provided, convert to monochrome | |
372 | + I = I.stretch(0.0f, 1.0f); //stretch the function so that it lies in [0 1] | |
373 | + SH.project(I.data(), I.width(), I.height(), args["n"].as_int(0)); //project the image function onto a spherical harmonics basis | |
374 | + if (args["image"].nargs() > 1) { //if the user provides two images | |
375 | + I.load(args["image"].as_string(1)); | |
376 | + if (I.channels() > 1) I = I.channel(0); //if a color image is provided, convert to monochrome | |
377 | + I = I.stretch(0.0f, 1.0f); //stretch the function so that it lies in [0 1] | |
378 | + SH.Sc.project(I.data(), I.width(), I.height(), args["n"].as_int(0)); | |
283 | 379 | } |
284 | - | |
285 | 380 | } |
381 | + | |
286 | 382 | else if(args["obj"].is_set()){ |
383 | + if (args["obj"].nargs() == 0) { | |
384 | + std::cout << "ERROR: an OBJ file must be specified as an argument to --obj" << std::endl; | |
385 | + exit(1); | |
386 | + } | |
387 | + stim::obj<float> OBJ(args["obj"].as_string(0)); //open the OBJ file | |
388 | + std::vector<stim::vec3<float>> vlist = obj2vec3(OBJ); //get the centered points for the OBJ | |
389 | + SH.pdf(vlist, args["n"].as_int(0)); | |
287 | 390 | |
288 | - std::string filename = args["obj"].as_string(0); | |
391 | + /*std::string filename = args["obj"].as_string(0); | |
289 | 392 | unsigned int l = args["obj"].as_int(1); |
290 | 393 | int p = args["obj"].as_int(2); |
291 | 394 | std::cout << p << std::endl; |
... | ... | @@ -354,9 +457,9 @@ void process_arguments(int argc, char* argv[]){ |
354 | 457 | S.mcSample(sph[1], sph[2], weights[i]); |
355 | 458 | } |
356 | 459 | S.mcEnd(); |
357 | - | |
460 | + */ | |
358 | 461 | } |
359 | - else{ | |
462 | + /*else{ | |
360 | 463 | //begin Monte-Carlo sampling, using the model vertices as samples |
361 | 464 | S.mcBegin(l, l); |
362 | 465 | double theta, phi, fx, px; |
... | ... | @@ -368,11 +471,11 @@ void process_arguments(int argc, char* argv[]){ |
368 | 471 | S.mcSample(theta, phi, fx / px); |
369 | 472 | } |
370 | 473 | S.mcEnd(); |
371 | - } | |
372 | - } | |
474 | + }*/ | |
475 | + //} | |
373 | 476 | |
374 | 477 | //if the user specifies an SH basis function |
375 | - else if(args["basis"].is_set()){ | |
478 | + /*if(args["basis"].is_set()){ | |
376 | 479 | |
377 | 480 | unsigned int n; |
378 | 481 | |
... | ... | @@ -388,14 +491,14 @@ void process_arguments(int argc, char* argv[]){ |
388 | 491 | |
389 | 492 | //add zeros for the first (n-1) coefficients |
390 | 493 | for(unsigned int c = 0; c < n; c++) |
391 | - S.push(0); | |
494 | + SH.push(0); | |
392 | 495 | |
393 | 496 | //add the n'th coefficient |
394 | - S.push(1); | |
395 | - } | |
497 | + SH.push(1); | |
498 | + }*/ | |
396 | 499 | |
397 | 500 | //output the spherical harmonics coefficients if requested |
398 | - if(args["out"].is_set()){ | |
501 | + /*if(args["out"].is_set()){ | |
399 | 502 | |
400 | 503 | if(args["out"].nargs() == 0) |
401 | 504 | std::cout<<S.str()<<std::endl; |
... | ... | @@ -409,26 +512,7 @@ void process_arguments(int argc, char* argv[]){ |
409 | 512 | |
410 | 513 | outfile.close(); |
411 | 514 | } |
412 | - } | |
413 | - | |
414 | - | |
415 | - | |
416 | - | |
417 | - | |
418 | - //if the user asks for help, give it and exit | |
419 | - if(args["help"].is_set()){ | |
420 | - std::cout<<"usage: shview c0 c1 c2 c3 ... --option [A B C]"<<std::endl; | |
421 | - std::cout<<"examples:"<<std::endl; | |
422 | - std::cout<<" generate a spherical function with 4 coefficients (l=0 to 2)"<<std::endl; | |
423 | - std::cout<<" shview 1.3 0.2 2.3 1.34"<<std::endl; | |
424 | - std::cout<<" display a spherical function representing the spherical harmonic l = 3, m = -2"<<std::endl; | |
425 | - std::cout<<" shview --basis 3 -2"<<std::endl; | |
426 | - | |
427 | - | |
428 | - | |
429 | - std::cout<<args.str(); | |
430 | - exit(0); | |
431 | - } | |
515 | + }*/ | |
432 | 516 | } |
433 | 517 | |
434 | 518 | int main(int argc, char *argv[]){ |
... | ... | @@ -451,6 +535,9 @@ int main(int argc, char *argv[]){ |
451 | 535 | //create the GLUT window (and an OpenGL context) |
452 | 536 | glutCreateWindow("Spherical Harmonic Viewport"); |
453 | 537 | |
538 | + //SH.rendermode(false, true, true); | |
539 | + //SH.colormap(); //use color-mapping | |
540 | + | |
454 | 541 | //set the display function (which will be called repeatedly by glutMainLoop) |
455 | 542 | glutDisplayFunc(display); |
456 | 543 | ... | ... |