This logic has been enhanced in 3 small ways:
- I look up the "parent" node to make further processing easier
- I update a counter for the number of child nodes, this will allow us to vary the thickness of the tree later on.
- I calculate the dot product of the vector of the parent node and the new node to see if it is backtracking on itself (which is what happens in the aforementioned situation) and branch out in a separate direction using the cross product of the two vectors.
Calculating the dot product of two normalised vectors gives us the cosine for the angle between the two vectors, a very handy and oft used little calculation. A value of 1.0 means the vectors are in the same direction, a value of 0.0 means they are at right angles and a value of -1.0 means they are in opposite direction (which is what we're checking for).
The cross product of two vectors gives us a vector that is at right angle to the two vectors. Very handy.
Interface changes
Another small change I added is that I no longer rotate the model automatically but rotated it based on scrolling horizontally and going closer/further away using vertical scrolling. This works really well on a MacBook pro as these actions are controlled by using two fingers on the touchpad but may be unwanted using traditional mice, you may want to stray away from this.
I'm also drawing larger dots for the vertices of the tree to better show the output of the algorithm.
Optimising the nodes
The real enhancement and the subject of this blog post is the added optimisation step.
After generating our tree (and zooming in a bit), we can see how many segments we've created:
This level of detail is overkill for what we're doing. Again our trusty dot product comes to the rescue. If we have two nodes whose vectors are pointing in (roughly) the same direction we could merge the nodes to a single node between the two end points and remove the point in the middle. We can only do this if a node has only one child node, if it has multiple branches the detail remains. We thus need to test for that situation.
void treelogic::optimiseNodes() { unsigned int node = 0; std::vector<unsigned int> children; while (node < mNodes.size()) { unsigned int mergeWith = 0; // we need to find out how many children we have, we can only optimise if just one is found children.clear(); for (unsigned int n = node+1; n < mNodes.size(); n++) { if (mNodes[n].parent == node) { children.push_back(n); }; }; // only one child? check if we need to merge if (children.size() == 1) { vec3 parentVector = mVertices[mNodes[node].b] - mVertices[mNodes[node].a]; parentVector = parentVector.normalized(); vec3 childVector = mVertices[mNodes[children[0]].b] - mVertices[mNodes[children[0]].a]; childVector = childVector.normalized(); // use dot product, this gives our cosine, the closer to 1.0 the more the vectors match direction if ((parentVector % childVector) > 0.9) { mergeWith = children[0]; }; }; // and merge if (mergeWith!=0) { unsigned int eraseVertice = mNodes[node].b; // should be same as mNodes[mergeWith].a, this we'll erase.. // merge our nodes... mNodes[mergeWith].a = mNodes[node].a; mNodes[mergeWith].childcount = mNodes[node].childcount; mNodes[mergeWith].parent = mNodes[node].parent; mNodes.erase(mNodes.begin() + node); // erase our vertice mVertices.erase(mVertices.begin() + eraseVertice); // adjust our nodes for (unsigned int n = 0; n < mNodes.size(); n++) { if (mNodes[n].parent > node)mNodes[n].parent--; if (mNodes[n].a > eraseVertice) mNodes[n].a--; if (mNodes[n].b > eraseVertice) mNodes[n].b--; }; } else { node++; }; }; };
This removes most of our in between nodes:
At this point we can see that we've removed a little to much detail because some of our curves have gone. This is because the small angles between nodes when there are a lot of segments means we end up removing too much. I'm still playing around to see if this can be improved.
Next up however, taking our nodes and turning it into a mesh that we can then further process.
Next up however, taking our nodes and turning it into a mesh that we can then further process.
No comments:
Post a Comment