diff --git a/ACG/GL/DrawMesh.hh b/ACG/GL/DrawMesh.hh
index 43f6a0000bbd9b67eb161ccae3dfee2962015175..8176feabd9c2e0a8d03b782307ef5c6ff7336a77 100644
--- a/ACG/GL/DrawMesh.hh
+++ b/ACG/GL/DrawMesh.hh
@@ -293,6 +293,21 @@ public:
    */
   void updateFull() {rebuild_ |= REBUILD_FULL;}
 
+  /** \brief enable fast update for vertex-only changes
+   *
+   * Updates after changing halfedge attributes might introduce new vertex splits.
+   * In that case the fast update mode adds these splits to the end of the vbo.
+   * This might introduce more splits than necessary in favor for speed.
+   * 
+  */
+  void enableFastVertexUpdate() { enableFastVertexUpdate_ = true; }
+
+  /** \brief disable fast update for vertex-only changes
+   *
+   * Do a full rebuild if per halfedge attributes are changed.
+  */
+  void disableFastVertexUpdate() { enableFastVertexUpdate_ = false; }
+
   /** \brief returns the number of used textured of this mesh
    *
    * @return Number of different textures used in the mesh
@@ -828,6 +843,9 @@ private:
   /// hint on what to rebuild
   unsigned int rebuild_;
 
+  /// fast updates are possible at the cost of potentially more splits
+  bool enableFastVertexUpdate_;
+
   /** used to track mesh changes, that require a full rebuild
     * values directly taken from Mesh template
     */
diff --git a/ACG/GL/DrawMeshT.cc b/ACG/GL/DrawMeshT.cc
index 11a50374de742dfcad0de5bc7dcf964bcf01ac37..4b8d459bddd6d78d710469572038e5914d1cfc5a 100644
--- a/ACG/GL/DrawMeshT.cc
+++ b/ACG/GL/DrawMeshT.cc
@@ -81,6 +81,7 @@ template <class Mesh>
 DrawMeshT<Mesh>::DrawMeshT(Mesh& _mesh)
 :  mesh_(_mesh),
    rebuild_(REBUILD_NONE),
+   enableFastVertexUpdate_(false),
    prevNumFaces_(0), prevNumVerts_(0),
    colorMode_(1),
    curVBOColorMode_(1),
@@ -542,9 +543,14 @@ DrawMeshT<Mesh>::rebuild()
   }
 
 
-  // full rebuild:
-  delete meshComp_;
-  meshComp_ = new MeshCompiler(*vertexDecl_);
+  bool doFastUpdate = !(rebuild_ & (REBUILD_TOPOLOGY | REBUILD_FULL)) &&  enableFastVertexUpdate_ && meshComp_ != 0;
+
+  if (!doFastUpdate)
+  {
+    // full rebuild:
+    delete meshComp_;
+    meshComp_ = new MeshCompiler(*vertexDecl_);
+  }
 
 
   // search for convenient attribute indices
@@ -640,8 +646,17 @@ DrawMeshT<Mesh>::rebuild()
   }
 
 
-  // compile draw buffers
-  meshComp_->build(true, true, true, true);
+
+  if (doFastUpdate)
+  {
+    // just update vertices
+    meshComp_->fastVertexUpdate();
+  }
+  else
+  {
+    // compile draw buffers
+    meshComp_->build(true, true, true, true);
+  }
 
 
   // create inverse vertex map
diff --git a/ACG/GL/MeshCompiler.cc b/ACG/GL/MeshCompiler.cc
index cebb60a297ca69e20ff21535f9455af1251788cb..0db4aef2e979137765303d9b677db606aafad4dc 100644
--- a/ACG/GL/MeshCompiler.cc
+++ b/ACG/GL/MeshCompiler.cc
@@ -1539,7 +1539,7 @@ bool MeshCompiler::reconstructTriangulation(int _face, std::vector<int>& _triang
   int fsize = getFaceSize(_face);
   int ftris = fsize - 2;
 
-  if (int(_triangulation.size() < ftris) * 3)
+  if (int(_triangulation.size()) < ftris * 3)
     _triangulation.resize(ftris * 3);
 
   if (fsize == 3)
@@ -1930,24 +1930,23 @@ void MeshCompiler::build(bool _weldVertices, bool _optimizeVCache, bool _needPer
 void MeshCompiler::fastVertexUpdate()
 {
   /*
+  basic idea:
+
+  Check if the current index mapping for each (face, corner) has conflicting vertex data.
+  Resolve conflicts by adding new split vertices at the end of the vbo.
   
-  1. alloc vertex array that stores which (face, corner) is using it. init to all 0 (unused)
-  2. for each face and each corner
-       vertexID = mapToDrawVertex(face, corner);
-
-       if (unused[vertexID])
-         writeVertexData(vertexID, face, corner)
-       else
-         
-         char oldVertexData[] = getVertexDataFromVBO(vertexID)
-         char newVertexData[] = getInputVertexData(face, corner)
-
-         if (!compareVertex(oldVertexData, newVertexData))
-           add new vertex   // might be optimized to reduce split count.
-                            // use VertexSplitter to check if there is no previous split with the same vertex data
-           update mappings
+  The mapping given by mapToOriginalVertexID is not changed for all old vertices.
+  Those (face, corner) pairs that make use of the vertex but aren't returned by mapToOriginalVertexID,
+  will have new vertex ids if there is a conflict.
+
+  Conflicts are found by comparing full vertex data.
   */
 
+  // potential optimizations:
+  // - let user provide vbo data instead of querying it with getInputFaceVertexData (bottleneck)
+  // - skip comparison of position elements for each vertex
+
+
   // memory storage for comparing two vertices
   int vstride = getVertexDeclaration()->getVertexStride();
   std::vector<char> vdata0(vstride, 0);
@@ -1958,9 +1957,6 @@ void MeshCompiler::fastVertexUpdate()
 
   int numSplits = 0;
 
-  // alloc buffer to store the triangulation of a polygon
-  std::vector<int> triangulation((maxFaceSize_ - 2) * 3);
-
   // keep references from vertexID -> (face, corner) as they are in mapToOriginalVertexID at the moment
 
   for (int faceID = 0; faceID < numFaces_; ++faceID)
@@ -2005,52 +2001,13 @@ void MeshCompiler::fastVertexUpdate()
           // - this is done in createVertexMap() later
 
 
-          // update indices_ :
-
-
-          //  need to know which indices are associated with the (face, corner)
-          //  -> there might be more than one!
-          //  this is no easy task because of the triangulation of n-polys
-          //  might have to precompute this information somehow
-          //          mapToDrawTriID();
-
-//           if (!triangulationReady)
-//           {
-//             if (!reconstructTriangulation(faceID, triangulation))
-//             {
-//               std::cerr << "error: MeshCompiler::partialVertexUpdate() can't reconstruct triangulation for face " << faceID << std::endl;
-//               
-//               // todo: error handling and rollback
-//             }
-//             else
-//               triangulationReady = true;
-//           }
-// 
-// 
-//           // compute mapping  corner -> index offsets into ibo
-// 
-//           // there is probably a better solution than doing a linear search in the triangulation here
-//           for (int tri = 0; tri < fsize - 2; ++tri)
-//           {
-//             for (int triCorner = 0; triCorner < 3; ++triCorner)
-//             {
-//               int triFaceCorner = triangulation[tri * 3 + triCorner];
-// 
-//               if (triFaceCorner == cornerID)
-//               {
-//                 int drawTriID = mapToDrawTriID(faceID, tri);
-// 
-//                 // offset into index buffer of the corner of the triangle
-//                 int triFaceCornerOffset = drawTriID * 3 + triCorner;
-// 
-//                 assert(indices_[triFaceCornerOffset] == vertexID);
-//                 indices_[triFaceCornerOffset] = ;
-//               }
-//             }
-//           }
 
+          // update index buffer (indices_), which contains a triangulation of the polygon :
 
-          // without reconstructing the triangulation:
+          // the current (face, corner) vertex might have multiple instances!
+          // this depends on the triangulation result
+          // search for these instances without reconstructing the triangulation
+          int numChangedIndices = 0;
           for (int tri = 0; tri < fsize - 2; ++tri)
           {
             int drawTriID = mapToDrawTriID(faceID, tri);
@@ -2064,10 +2021,15 @@ void MeshCompiler::fastVertexUpdate()
               {
                 // change index to to new split vertex
                 indices_[triIndexOffset] = newVertexID;
+                ++numChangedIndices;
               }
             }
           }
 
+#ifdef _DEBUG
+          if (!numChangedIndices)
+            std::cout << "error: MeshCompiler::fastVertexUpdate - failed to update index buffer with new split id" << std::endl;
+#endif
         }
       }
     }
diff --git a/ACG/GL/MeshCompiler.hh b/ACG/GL/MeshCompiler.hh
index 39129896930fb89ddb6bc485896639d88ab28724..1d5d0da7fccc02c03d42fe854258144452f35a73 100644
--- a/ACG/GL/MeshCompiler.hh
+++ b/ACG/GL/MeshCompiler.hh
@@ -628,6 +628,16 @@ public:
   */
   int getIndex(int _i) const;
 
+  /** Get the triangulation of a face
+   *
+   * The triangulation is an array of 3 local corner ids for each triangle of the face.
+   * This data is not directly available, but has to be reconstructed from the final index buffer.
+   * This is done by matching the vertex ids with the (face, corner) mapping, so there is some overhead.
+   * @param _face face ID in input data
+   * @param _triangulation target buffer receiving the triangulation
+   * @return report if matching was successful
+  */
+  bool reconstructTriangulation(int _face, std::vector<int>& _triangulation) const;
 
 /** @} */  
 
@@ -1027,10 +1037,6 @@ private:
   // resolve triangulation
   void resolveTriangulation();
 
-  // reconstruct triangulation of a face from the final index buffer.
-  // the triangulation is an array of 3 local corner ids for each triangle of the face.
-  bool reconstructTriangulation(int _face, std::vector<int>& _triangulation) const;
-
   // sort input faces by group ids
   void sortFacesByGroup();
 
diff --git a/ObjectTypes/MeshObject/MeshObjectT.cc b/ObjectTypes/MeshObject/MeshObjectT.cc
index 1a37cd40c90683f1b8fd7116ddfb26e2f782975c..cc57d8edd9304f1aae8b92780c89ce20c2bcb892 100644
--- a/ObjectTypes/MeshObject/MeshObjectT.cc
+++ b/ObjectTypes/MeshObject/MeshObjectT.cc
@@ -221,6 +221,15 @@
 
     meshNode_    = new ACG::SceneGraph::MeshNodeT<MeshT>(*mesh_, shaderNode_, "NEW MeshNode");
 
+    if (meshNode_->getDrawMesh())
+    {
+      bool fastUpdate = OpenFlipperSettings().value("Core/Debug/FastVertexUpdate", false).toBool();
+      if (fastUpdate)
+        meshNode_->getDrawMesh()->enableFastVertexUpdate();
+      else
+        meshNode_->getDrawMesh()->disableFastVertexUpdate();
+    }
+
     QString shaderDir = OpenFlipper::Options::shaderDirStr() + OpenFlipper::Options::dirSeparator();
 
     std::string shaderDirectory = std::string( shaderDir.toUtf8() );
diff --git a/OpenFlipper/widgets/optionsWidget/optionsWidget.cc b/OpenFlipper/widgets/optionsWidget/optionsWidget.cc
index a1aa5da01580a7a30a9ef733804617173e05d5d8..ccde828632a839ad74452ebad4f1fb14468a6f40 100644
--- a/OpenFlipper/widgets/optionsWidget/optionsWidget.cc
+++ b/OpenFlipper/widgets/optionsWidget/optionsWidget.cc
@@ -341,6 +341,8 @@ void OptionsWidget::showEvent ( QShowEvent * /*event*/ ) {
   // debugging
   slotDebugging->setChecked(OpenFlipper::Options::doSlotDebugging());
 
+  fastVertexUpdate->setChecked(OpenFlipperSettings().value("Core/Debug/FastVertexUpdate", false).toBool());
+
   //keyBindings
   initKeyTree();
 
@@ -666,6 +668,7 @@ void OptionsWidget::slotApply() {
 
   // Debugging
   OpenFlipper::Options::doSlotDebugging(slotDebugging->isChecked());
+  OpenFlipperSettings().setValue("Core/Debug/FastVertexUpdate", fastVertexUpdate->isChecked());
 
   //viewer defaults
   for (int i=0; i < PluginFunctions::viewers(); i++){
diff --git a/OpenFlipper/widgets/optionsWidget/optionsWidget.ui b/OpenFlipper/widgets/optionsWidget/optionsWidget.ui
index b6278e7e4bd2c12ad1d3af0edcf0d71eef9a1988..893790a80a3d9e755c2f78079bbfdf4c2ad383cb 100644
--- a/OpenFlipper/widgets/optionsWidget/optionsWidget.ui
+++ b/OpenFlipper/widgets/optionsWidget/optionsWidget.ui
@@ -50,7 +50,7 @@
           <string/>
          </property>
          <property name="currentIndex">
-          <number>1</number>
+          <number>0</number>
          </property>
          <property name="usesScrollButtons">
           <bool>true</bool>
@@ -1744,6 +1744,13 @@ p, li { white-space: pre-wrap; }
              </item>
             </layout>
            </item>
+           <item>
+            <widget class="QCheckBox" name="fastVertexUpdate">
+             <property name="text">
+              <string>Enable Fast Vertex Update (experimental)</string>
+             </property>
+            </widget>
+           </item>
            <item>
             <spacer name="verticalSpacer_3">
              <property name="orientation">