Topology-Varying 3D Shape Creation via Structural Blending




  • Paper topic: Geometry
  • Software type: Code
  • Able to run a replicability test: True
  • Replicability score: 5
  • Software language: C/C++
  • License: unspecified
  • Build mechanism: IDE Project (VS,..)
  • Dependencies: Qt / GLee / starlib / Eigen
  • Documentation score {0,1,2}: 1
  • Reviewer: Nicolas Bonneel <>
  • Time spent for the test (build->first run, timeout at 100min): 100min

Source code information


I updated the code so that it runs on current generation of libraries, that is, Qt 5.14 (with VS 2017) instead of Qt 4.2, Glew instead of GLee, and the last version of the StarLib dependency, which compiles with Qt 5. For that, a large number of steps need to be performed, which took me more than a day to investigate.
First, building the last Starlib:mini. First, install Qt 5.14 (about 40GB), add the Eigen path to the include paths in INCLUDEPATH += c:\absolute_path_to_starlab\core\external\eigen-3.2.5\ and add the path to your Visual Studio cl.exe in the system path (typically, :\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64).
Then, go to a command prompt, and "moc" the following cpp files by executing:
moc ParametersFrame.h -o moc_ParametersFrame.cpp
moc RichParameterSet.h -o moc_RichParameterSet.cpp
moc RichParameterWidget.h -o moc_RichParameterWidget.cpp
in the right folders.
Then add moc_ParametersFrame.cpp, moc_RichParameterSet.cpp and moc_RichParameterWidget.cpp to the project for them to be compiled (folder core/starlib/Sources/parameters).

Then you need to compile the old topo-blend project, and a number of edits need to be performed:
* The Eigen constructor Vector3(float) doesn't exist. You thus need to edit:
- CustomDrawObjects.h, line 332: glv(Vector3(center + ((Vector3d)n[i] * 0.2 * scale))); to glv(Vector3(center + (Vector3d(n[i].x(), n[i].y(), n[i].z()) * 0.2 * scale)));
- CustomDrawObjects.h, line 299: Voxel corner (Vector3d((minimum - Vector3d(voxel_size)) / voxel_size)); to Voxel corner (Vector3d((minimum - Vector3d(voxel_size, voxel_size, voxel_size)) / voxel_size));
- StructureNode.h, lines 48-49
        inline Vector4d minCoord(){ return Vector4d(0.0); } to inline Vector4d minCoord(){ return Vector4d(0.0, 0.0, 0.0, 0.0); }
        inline Vector4d maxCoord(){ return Vector4d(1.0); } to inline Vector4d maxCoord(){ return Vector4d(1.0, 1.0, 1.0, 1.0); }
- nurbs_plugin.cpp, line 965: createSheet(Vector3d(0,0,0),Vector3d(0.01)); => createSheet(Vector3d(0,0,0),Vector3d(0.01, 0.01, 0.01));        

* The file QtConcurrentRun is now in the folder QtConcurrent. You need to edit:
#include <QtConcurrentRun> to #include <QtConcurrent/QtConcurrentRun>
in GraphExplorer.cpp and Scheduler.cpp and SynthesisManager.cpp and DemoGlobal.cpp

* For some reasons, colors like Qt::lightGray cannot be accessed. Changing them to the corresponding constants uglily but quickly fixes the error:
- GraphModifyWidget.cpp, line 129: node->vis_property["color"] = Qt::lightGray; change  Qt::lightGray; to the constant 6
- GraphModifyWidget.cpp, lines 135 and 138: change Qt::red to 7, and Qt::green to 8
- QuickGroup.cpp, lines 82 and 88: same thing.
- QuickAlignment.cpp, lines 99, 104, 110, 113:  same thing. 
- landmarks_dialog.cpp, lines 248, 254, 257, 264, 270, 273, 289, 296, 306, 309, 677, 684, 693, 696: same things (use Qt::yellow=12)

* A number of string literals are typed char* instead of const char* which produces compile errors.
- StructureGlobal.h, line 532: static inline std::string exec(char* cmd) { should be changed to static inline std::string exec(const char* cmd) {
- kmeans.h, line 296: void init_Mu( ExtMat &X, ExtMat &Mu, char* initname ) to void init_Mu( ExtMat &X, ExtMat &Mu, const char* initname )
- PlyFile.cpp, line 41: char *type_names[] = to const char *type_names[] =
- PlyFile.cpp, line 1457: int equal_strings(char *s1, char *s2) to int equal_strings(const char *s1, const char *s2), and change the definition in PlyFile.h
- Ply.h, line 85: char *name; to QString name; and #include <QString>  (outside of the extern "C" !!)

* stdext::hash_map is now obsolete and now part of the STL under the name "unordered_map". You thus need to change:
- Geometry.h, line 278: hash_map<long long,int> edgeMap; to unordered_map<long long,int> edgeMap;
- Hash.h, line 4: #include <hash_map> to #include <unordered_map>
- Hash.h, line 5: using stdext::hash_map; to using std::unordered_map;
- MultiGridOctreeData.h, lines 244, 310, 312: hash_map< long long , std::pair< RootInfo< OutputDensity > , int > >* vertexCount; to unordered_map<...>
- Geometry.inl, line 325: same thing.
- MultiGridOctreeData.inl, lines 2877, 3004, 3955, 3994, 4096, 4097: same thing. 
- resample/disjoint_set.h and topoblenderlib/disjoint_set.h, lines 6--8 : hash_map to unordered_map, hash_set to unordered_set, and #define STDEXT stdext to #define STDEXT std
- resample/disjoint_set.h and topoblenderlib/disjoint_set.h, lines 58-59 hash_map => unordered_map

* some includes are missing.
- MultiGridOctreeData.h, add #include "Octree.h"
- GraphEmbed.h, add #include "StructureNode.h"
- ShapeRenderer.cpp, add #include "qglviewer/manipulatedCameraFrame.h" before the #include "qglviewer/camera.h"
- GraphItem.cpp, Scene.cpp, BlendPathRenderer.cpp, also add #include "qglviewer/manipulatedCameraFrame.h" 

* other edits:
- Task.h, line 9: add Q_OBJECT, before public
- ProductEvaluators.h (in Eigen), lines 181--192: comment out the function. It produces an error otherwise, and should not impact much performances. 
- PlyFile.h, lines 148-149: remove extern char *my_alloc(); and replace #define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) by #define myalloc(mem_size) malloc((mem_size))
- ProgressItem.cpp, line 9: replace items = new QGraphicsItemGroup(0,scene); by items = new QGraphicsItemGroup(0); and then immediately call scene->addItem(items);
- ProgressItem.cpp, lines 98-100:
        spinner->translate( 0.5 * x,  0.5 * y);
        spinner->translate(-0.5 * x, -0.5 * y);
should be replace by 
                spinner->setTransform(QTransform().translate(0.5*x, 0.5*y).rotate(10).translate(-0.5*x, -0.5*y));
- qglviewer/camera.h, line 334: move the definition of ManipulatedCameraFrame* frame() const { return frame_; } to the cpp file.
the .h file should look like ManipulatedCameraFrame* frame() const; 
and the camera.cpp file should have a function ManipulatedCameraFrame* Camera::frame() const { return frame_; }        
- BlendPathRenderer.cpp, lines 176 and 213: replace event->posF(); by event->localPos();
- poissonrecon.cpp: add #pragma once at the begining        
- QtAwesome.cpp, line 15: remove Q_INIT_RESOURCE_EXTERN(QtAwesome), and put Q_INIT_RESOURCE(QtAwesome); in line 121, in QtAwesome's constructor (this may not be needed though)
- ShapeRenderer.cpp, line 124: replace setRevolveAroundPoint by setPivotPoint (otherwise annoying warnings during execution, but this is not mandatory)
- GraphItem.cpp, line 52: replace setRevolveAroundPoint by setPivotPoint
- BlendPathRenderer.cpp, line 185: replace revolveAroundPoint by pivotPoint
- Scene.cpp, line 243: replace revolveAroundPoint by pivotPoint
- topo-blend.cpp, line 640: replace revolveAroundPoint by pivotPoint

* Replacing GLee by a fresh Glew install.
- GlSplatRendererLib/ replace Glee by Glew
- change all the #include of Glee to GL/glew.h.
- topo_blend_widget.cpp: add an #include <GL/glew.h> before all other includes, otherwise glew complains that other gl libraries were included before glew.
- GLSplat.cpp, line 16: put an #include <GL/glew.h> before all other includes
- GLSplat.cpp,line 124 and 314, 321, 329, 407, 421: glActiveTexture should be changed to __glewActiveTexture
- GLSplat.cpp,line 191 and 206: glFramebufferTexture2DEXT => __glewFramebufferTexture2D
- GLSplat.cpp,line 250: glDrawBuffersARB => __glewDrawBuffersARB
- GLSplat.cpp,line 345, 350, 355, 360: glMultiTexCoord2f => __glewMultiTexCoord2f
- GLSplat.cpp,line 411: glBlendFuncSeparate => __glewBlendFuncSeparate
- GLSplat.cpp,line 426: glPointParameterf => __glewPointParameterf
- Shader.h, lines 103, 109, 112, 115, 118, 121, 124: glUniform*(glGetUniformLocation(...)) => __glewUniform*(__glewGetUniformLocation
- and add LIBS += -lglew32 -LC:/[path-to-glew]/glew-2.1.0/lib/Release/x64 

* toAscii does not exist anymore:
- GLSplat.cpp, line 56, 102, 103: .toAscii() => .toLocal8Bit()
- nurbs_plugin.cpp, line 426: toAscii() => toLatin1()
- poissonrecon.cpp, line 18: toAscii() => toLatin1()

* the way Qt plugins are handled has changed:
- voxel_resampler.cpp, line 170: remove the line Q_EXPORT_PLUGIN
- nurbs_plugin.cpp, line 1014: remove the line Q_EXPORT_PLUGIN
- topo-blend.cpp, line 996: remove the line Q_EXPORT_PLUGIN
- voxel_resampler.h, line 10: add Q_PLUGIN_METADATA(IID "voxel_resampler") 
- nurbs_plugin.h, line 25: add Q_PLUGIN_METADATA(IID "nurbs_plugin") 
- topo-blend.h, line 26: add Q_PLUGIN_METADATA(IID "topoblend") 

* __iob_func does not exist anymore:
- voxel_resampler.cpp and nurbs_plugin.cpp: add at the begining: extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
- and LIBS += -llegacy_stdio_definitions

make sure starlib.lib is present in the newly created release directory

* Now going to linking errors:
- Src/PoissonRecon.cpp, line 494, add 
    SimpleMesh s;
    PoissonRecon::makeFromCloud(std::vector<std::vector<float>>(), std::vector<std::vector<float>>(), s, 0);
and #include "poissonrecon.h" at the beginning. Otherwise the makeFromCloud symbol does not get exported if it is never used. This is a hack but works.
- It is unclear if this is needed, but at some point I had to put  ../Reconstruction/poissonrecon.cpp in the compiled sources in the project file and add LIBS += $$PWD/../Reconstruction/$$CFG/lib/Reconstruction.lib at the end. It randomly changes between "undefined reference to ..." to "duplicate reference to ...", and changes if I compile in debug or release.

* Now going to execution errors:
- ShapesGallery.cpp, lines 94--10 : comment out everything. This relates to shadows, and crashes the program.
- BlendPathRenderer.cpp, line 42 and 78, replace updateGL by paintGL. Otherwise the interpolated chair thumbnails are black. This is ackwards since updateGL is supposed to call paintGL though.
- SynthesisManager.cpp, lines 971--973, comment out the inside of bufferCleanup(). This is a hack which can have side effects, but otherwise crashes.

On my machine, the code only runs within the Qt Creator environment, otherwise some VCRUNTIME140_APP.dll/MSVCP140.dll error appear.
Also the program crashes when exporting the mesh, during the rendering of the snapshot. However, it still outputs the obj mesh, so it is possible to use that mesh for comparison purpose. In practice, the authors have made available a demo compiled for Windows, and shows a better rendering output than the code compiled with the instructions above.
While the interface is quite intuitive, my main issues are the lack of documentation, and most importantly, that I have no idea how the input data directories were generated and thus I have no clue as to how I would interpolate my own models. In particular, it seems that the provided xml files (likely?) contain the skeletonized and B-spline fits of the meshes, which is a non trivial step.

If you want to contribute with another review, please follow these instructions.

Please consider to cut/paste/edit the raw JSON data attached to this paper.