[osg-users] code for merging tri strips in a cache friendly way
Christian Buchner
christian.buchner at gmail.com
Tue Jan 3 04:34:08 PST 2017
When loading .obj files (e.g. exported from Blender) into OSG - especially
those that are exported with the "group by material" option - you might
find a lot of individual tri strips in the resulting OSG geometry.
Here is a piece of code (a node visitor) that will join these tri strips
into a single large strip, taking into account cache locality aspects: The
tri strips are sorted by their median vertex index before joining. This can
be useful to improve the performance of hardware instancing.
Some C++11 language features may be used in the code (range based for and
others). Feel free to modify/use/improve on this code.
Christian
/**
* A visitor that merges triangle strip drawables by creating some
degenerate triangles.
*/
class TriStripMergeVisitor : public osg::NodeVisitor
{
public:
TriStripMergeVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
virtual void apply(osg::Node& node)
{
traverse(node);
}
virtual void apply(osg::Geode& node)
{
for(unsigned int i=0;i<node.getNumDrawables();++i)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable) apply(*drawable);
}
traverse(node);
}
virtual void apply(osg::Drawable& drawable)
{
osg::Geometry *geo = dynamic_cast<osg::Geometry*>(&drawable);
if (geo != NULL) apply(*geo);
}
virtual void apply(osg::Geometry& geometry)
{
osg::Geometry::PrimitiveSetList &psl =
geometry.getPrimitiveSetList();
// count the number of tri strips
int num_tristrips = 0;
unsigned int total_indices = 0;
std::vector< std::pair<std::vector<unsigned int>, unsigned int> >
tristrips;
bool first = true;
for (auto &ps : psl)
{
osg::DrawElements *de =
dynamic_cast<osg::DrawElements*>(ps.get());
if (de != NULL)
{
if (de->getMode() == osg::PrimitiveSet::TRIANGLE_STRIP)
{
num_tristrips++;
std::vector<unsigned int> indices;
unsigned int num_indices = de->getNumIndices();
if (!first) total_indices += 2;
total_indices += num_indices;
indices.reserve(num_indices);
for (unsigned int i=0; i < num_indices; i++)
indices.push_back(de->index(i));
std::vector<unsigned int> sorted_indices(indices);
std::sort(sorted_indices.begin(), sorted_indices.end());
int median_index =
sorted_indices[sorted_indices.size()/2];
tristrips.emplace_back(indices, median_index);
first = false;
}
}
}
// merge all tri-strips in a cache-friendly manner
if (num_tristrips >= 2)
{
std::sort(tristrips.begin(), tristrips.end(),
[](std::pair<std::vector<unsigned int>, unsigned int> &a,
std::pair<std::vector<unsigned int>, unsigned int> &b) {
return b.second > a.second;
});
std::vector< unsigned int > joined_tristrips;
joined_tristrips.reserve(total_indices);
first = true;
for (auto ts : tristrips)
{
if (!first)
{
joined_tristrips.push_back(joined_tristrips.back());
joined_tristrips.push_back(ts.first.front());
}
joined_tristrips.insert(joined_tristrips.end(),
ts.first.begin(), ts.first.end());
first = false;
}
unsigned int max_element =
*std::max_element(joined_tristrips.begin(), joined_tristrips.end());
osg::ref_ptr<osg::DrawElements> new_de;
if (max_element < 256) new_de = new
osg::DrawElementsUByte(osg::PrimitiveSet::TRIANGLE_STRIP,
joined_tristrips.size());
else if (max_element < 65536) new_de = new
osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP,
joined_tristrips.size());
else new_de = new
osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP,
joined_tristrips.size());
for (unsigned int i=0; i < joined_tristrips.size(); i++)
new_de->setElement(i, joined_tristrips[i]);
osg::Geometry::PrimitiveSetList new_psl;
new_psl.push_back(new_de);
// append all non tri strip geometry
for (auto &ps : psl)
{
osg::DrawElements *de =
dynamic_cast<osg::DrawElements*>(ps.get());
if (!(de != NULL && de->getMode() ==
osg::PrimitiveSet::TRIANGLE_STRIP))
new_psl.push_back(ps);
}
geometry.setPrimitiveSetList(new_psl);
}
}
};
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20170103/1b3863e9/attachment-0002.htm>
More information about the osg-users
mailing list