Commit 7e51db75 authored by Martin Schultz's avatar Martin Schultz

Manually added changes from pre submodule merge request Faster Vertex

Update branch meshcompiler_fast_update
parent 8b1648d7
...@@ -293,6 +293,21 @@ public: ...@@ -293,6 +293,21 @@ public:
*/ */
void updateFull() {rebuild_ |= REBUILD_FULL;} 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 /** \brief returns the number of used textured of this mesh
* *
* @return Number of different textures used in the mesh * @return Number of different textures used in the mesh
...@@ -828,6 +843,9 @@ private: ...@@ -828,6 +843,9 @@ private:
/// hint on what to rebuild /// hint on what to rebuild
unsigned int 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 /** used to track mesh changes, that require a full rebuild
* values directly taken from Mesh template * values directly taken from Mesh template
*/ */
......
...@@ -81,6 +81,7 @@ template <class Mesh> ...@@ -81,6 +81,7 @@ template <class Mesh>
DrawMeshT<Mesh>::DrawMeshT(Mesh& _mesh) DrawMeshT<Mesh>::DrawMeshT(Mesh& _mesh)
: mesh_(_mesh), : mesh_(_mesh),
rebuild_(REBUILD_NONE), rebuild_(REBUILD_NONE),
enableFastVertexUpdate_(false),
prevNumFaces_(0), prevNumVerts_(0), prevNumFaces_(0), prevNumVerts_(0),
colorMode_(1), colorMode_(1),
curVBOColorMode_(1), curVBOColorMode_(1),
...@@ -542,9 +543,15 @@ DrawMeshT<Mesh>::rebuild() ...@@ -542,9 +543,15 @@ DrawMeshT<Mesh>::rebuild()
} }
// full rebuild: bool doFastUpdate = !(rebuild_ & (REBUILD_TOPOLOGY | REBUILD_FULL)) && enableFastVertexUpdate_ && meshComp_ != 0;
delete meshComp_;
meshComp_ = new MeshCompiler(*vertexDecl_); if (!doFastUpdate)
{
// full rebuild:
delete meshComp_;
meshComp_ = new MeshCompiler(*vertexDecl_);
}
// search for convenient attribute indices // search for convenient attribute indices
...@@ -640,8 +647,16 @@ DrawMeshT<Mesh>::rebuild() ...@@ -640,8 +647,16 @@ DrawMeshT<Mesh>::rebuild()
} }
// compile draw buffers if (doFastUpdate)
meshComp_->build(true, true, true, true); {
// just update vertices
meshComp_->fastVertexUpdate();
}
else
{
// compile draw buffers
meshComp_->build(true, true, true, true);
}
// create inverse vertex map // create inverse vertex map
......
...@@ -1533,6 +1533,64 @@ void MeshCompiler::triangulate() ...@@ -1533,6 +1533,64 @@ void MeshCompiler::triangulate()
} }
bool MeshCompiler::reconstructTriangulation(int _face, std::vector<int>& _triangulation) const
{
int fsize = getFaceSize(_face);
int ftris = fsize - 2;
if (int(_triangulation.size()) < ftris * 3)
_triangulation.resize(ftris * 3);
if (fsize == 3)
{
// fast version for triangles
int drawTriID = mapToDrawTriID(_face);
// first vertex of the triangle
int drawVertexID = mapToDrawVertexID(_face, 0);
// account for rotation in the index buffer
for (int k = 0; k < 3; ++k)
{
if (indices_[drawTriID * 3 + k] == drawVertexID)
{
_triangulation[k] = 0;
_triangulation[(k + 1) % 3] = 1;
_triangulation[(k + 2) % 3] = 2;
return true;
}
}
return false;
}
else
{
// map from drawVertexID -> local corner id in face
std::map<int, int> cornerMap; // potential optimization: find better data structure to store this info
// init cornerMap
for (int k = 0; k < fsize; ++k)
{
int drawVertexID = mapToDrawVertexID(_face, k);
cornerMap[drawVertexID] = k;
}
// use cornerMap for simple reconstruction
for (int t = 0; t < ftris; ++t)
{
int drawTriID = mapToDrawTriID(_face, t);
for (int k = 0; k < 3; ++k)
{
// get vertexID from index buffer
int drawVertexID = indices_[drawTriID * 3 + k];
#ifdef _DEBUG
if (!cornerMap.count(drawVertexID))
{
std::cerr << "error: MeshCompiler::reconstructTriangulation - invalid mappings for face " << _face << std::endl;
return false;
}
#endif // _DEBUG
int cornerID = cornerMap[drawVertexID];
_triangulation[t * 3 + k] = cornerID;
}
}
}
return true;
}
void MeshCompiler::resolveTriangulation() void MeshCompiler::resolveTriangulation()
{ {
...@@ -1893,7 +1951,96 @@ void MeshCompiler::build(bool _weldVertices, bool _optimizeVCache, bool _needPer ...@@ -1893,7 +1951,96 @@ 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.
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);
std::vector<char> vdata1(vstride, 0);
int numReferencedVertices = numDrawVerts_ - numIsolatedVerts_;
int numSplits = 0;
// keep references from vertexID -> (face, corner) as they are in mapToOriginalVertexID at the moment
for (int faceID = 0; faceID < numFaces_; ++faceID)
{
int fsize = getFaceSize(faceID);
// only reconstruct triangulation when necessary
bool triangulationReady = false;
for (int cornerID = 0; cornerID < fsize; ++cornerID)
{
int vertexID = mapToDrawVertexID(faceID, cornerID);
int refFaceID, refCornerID;
mapToOriginalVertexID(vertexID, refFaceID, refCornerID);
if (faceID != refFaceID)
{
// this is a shared vertex
// compare vertex data with the reference
// get data of existing reference
getInputFaceVertexData(refFaceID, refCornerID, &vdata0[0]);
// get data of new vertex
getInputFaceVertexData(faceID, cornerID, &vdata1[0]);
if (!vertexCompare_->equalVertex(&vdata0[0], &vdata1[0], &decl_))
{
// split
++numSplits;
// update mapToDrawVertexID:
const int newVertexID = numReferencedVertices;
const int indexOffset = getInputIndexOffset(faceID, cornerID);
faceBufSplit_[indexOffset] = newVertexID;
++numReferencedVertices;
numDrawVerts_ = numReferencedVertices + numIsolatedVerts_;
// update mapToOriginalVertexID:
// - this is done in createVertexMap() later
// update index buffer (indices_), which contains a triangulation of the polygon :
// 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);
for (int triCorner = 0; triCorner < 3; ++triCorner)
{
int triIndexOffset = drawTriID * 3 + triCorner;
int triVertex = indices_[triIndexOffset];
if (triVertex == vertexID)
{
// 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
}
}
}
}
if (numSplits)
{
// fix isolated vertices
// resolve overlapping indices from the split vertices and isolates
numDrawVerts_ = numReferencedVertices; // isolated vertices are fixed in createVertexMap()
// update vertex -> (face, corner) map
createVertexMap(numIsolatedVerts_ > 0);
}
}
......
...@@ -513,6 +513,14 @@ public: ...@@ -513,6 +513,14 @@ public:
*/ */
void build(bool _weldVertices = false, bool _optimizeVCache = true, bool _needPerFaceAttribute = false, bool _keepIsolatedVertices = false); void build(bool _weldVertices = false, bool _optimizeVCache = true, bool _needPerFaceAttribute = false, bool _keepIsolatedVertices = false);
/** \brief Fast update of vertices
*
* Use this if some attributes of vertices have changed, but the face topology is unchanged.
* This might introduce new vertex splits, which are added to the end of the vertex buffer.
* In that case the mappings are also updated.
*/
void fastVertexUpdate();
/** Get number of vertices in final buffer. /** Get number of vertices in final buffer.
*/ */
int getNumVertices() const {return numDrawVerts_;} int getNumVertices() const {return numDrawVerts_;}
...@@ -618,6 +626,16 @@ public: ...@@ -618,6 +626,16 @@ public:
*/ */
int getIndex(int _i) const; 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;
/** @} */ /** @} */
......
...@@ -340,6 +340,8 @@ void OptionsWidget::showEvent ( QShowEvent * /*event*/ ) { ...@@ -340,6 +340,8 @@ void OptionsWidget::showEvent ( QShowEvent * /*event*/ ) {
// debugging // debugging
slotDebugging->setChecked(OpenFlipper::Options::doSlotDebugging()); slotDebugging->setChecked(OpenFlipper::Options::doSlotDebugging());
fastVertexUpdate->setChecked(OpenFlipperSettings().value("Core/Debug/FastVertexUpdate", false).toBool());
//keyBindings //keyBindings
initKeyTree(); initKeyTree();
...@@ -667,6 +669,7 @@ void OptionsWidget::slotApply() { ...@@ -667,6 +669,7 @@ void OptionsWidget::slotApply() {
// Debugging // Debugging
OpenFlipper::Options::doSlotDebugging(slotDebugging->isChecked()); OpenFlipper::Options::doSlotDebugging(slotDebugging->isChecked());
OpenFlipperSettings().setValue("Core/Debug/FastVertexUpdate", fastVertexUpdate->isChecked());
//viewer defaults //viewer defaults
for (int i=0; i < PluginFunctions::viewers(); i++){ for (int i=0; i < PluginFunctions::viewers(); i++){
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
<string/> <string/>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<property name="usesScrollButtons"> <property name="usesScrollButtons">
<bool>true</bool> <bool>true</bool>
...@@ -1773,6 +1773,13 @@ p, li { white-space: pre-wrap; } ...@@ -1773,6 +1773,13 @@ p, li { white-space: pre-wrap; }
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QCheckBox" name="fastVertexUpdate">
<property name="text">
<string>Enable Fast Vertex Update (experimental)</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer_3"> <spacer name="verticalSpacer_3">
<property name="orientation"> <property name="orientation">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment