<div dir="ltr"><div><div><div><br></div>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.<br><br></div>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.<br><br></div><div>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.<br></div><div><br></div>Christian<br><div><br>/**<br> * A visitor that merges triangle strip drawables by creating some degenerate triangles.<br> */<br>class TriStripMergeVisitor : public osg::NodeVisitor<br>{<br>public:<br><br>    TriStripMergeVisitor():<br>        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}<br><br>    virtual void apply(osg::Node& node)<br>    {<br>        traverse(node);<br>    }<br><br>    virtual void apply(osg::Geode& node)<br>    {<br>        for(unsigned int i=0;i<node.getNumDrawables();++i)<br>        {<br>            osg::Drawable* drawable = node.getDrawable(i);<br>            if (drawable) apply(*drawable);<br>        }<br><br>        traverse(node);<br>    }<br><br>    virtual void apply(osg::Drawable& drawable)<br>    {<br>        osg::Geometry *geo = dynamic_cast<osg::Geometry*>(&drawable);<br>        if (geo != NULL) apply(*geo);<br>    }<br><br>    virtual void apply(osg::Geometry& geometry)<br>    {<br>        osg::Geometry::PrimitiveSetList &psl = geometry.getPrimitiveSetList();<br><br>        // count the number of tri strips<br>        int num_tristrips = 0;<br>        unsigned int total_indices = 0;<br>        std::vector< std::pair<std::vector<unsigned int>, unsigned int> > tristrips;<br>        bool first = true;<br>        for (auto &ps : psl)<br>        {<br>            osg::DrawElements *de = dynamic_cast<osg::DrawElements*>(ps.get());<br>            if (de != NULL)<br>            {<br>                if (de->getMode() == osg::PrimitiveSet::TRIANGLE_STRIP)<br>                {<br>                    num_tristrips++;<br>                    std::vector<unsigned int> indices;<br>                    unsigned int num_indices = de->getNumIndices();<br>                    if (!first) total_indices += 2;<br>                    total_indices += num_indices;<br>                    indices.reserve(num_indices);<br>                    for (unsigned int i=0; i < num_indices; i++) indices.push_back(de->index(i));<br><br>                    std::vector<unsigned int> sorted_indices(indices);<br>                    std::sort(sorted_indices.begin(), sorted_indices.end());<br>                    int median_index = sorted_indices[sorted_indices.size()/2];<br>                    tristrips.emplace_back(indices, median_index);<br>                    first = false;<br>                }<br>            }<br>        }<br><br>        // merge all tri-strips in a cache-friendly manner<br>        if (num_tristrips >= 2)<br>        {<br>            std::sort(tristrips.begin(), tristrips.end(), [](std::pair<std::vector<unsigned int>, unsigned int> &a, std::pair<std::vector<unsigned int>, unsigned int> &b) {<br>                return b.second > a.second;   <br>            });<br><br>            std::vector< unsigned int > joined_tristrips;<br>            joined_tristrips.reserve(total_indices);<br>            first = true;<br>            for (auto ts : tristrips)<br>            {<br>                if (!first)<br>                {<br>                    joined_tristrips.push_back(joined_tristrips.back());<br>                    joined_tristrips.push_back(ts.first.front());<br>                }<br>                joined_tristrips.insert(joined_tristrips.end(), ts.first.begin(), ts.first.end());<br><br>                first = false;<br>            }<br><br>            unsigned int max_element = *std::max_element(joined_tristrips.begin(), joined_tristrips.end());<br>            osg::ref_ptr<osg::DrawElements> new_de;<br>            if (max_element < 256)        new_de = new osg::DrawElementsUByte(osg::PrimitiveSet::TRIANGLE_STRIP, joined_tristrips.size());<br>            else if (max_element < 65536) new_de = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, joined_tristrips.size());<br>            else                          new_de = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP, joined_tristrips.size());<br>            for (unsigned int i=0; i < joined_tristrips.size(); i++)<br>                new_de->setElement(i, joined_tristrips[i]);<br><br>            osg::Geometry::PrimitiveSetList new_psl;<br>            new_psl.push_back(new_de);<br><br>            // append all non tri strip geometry<br>            for (auto &ps : psl)<br>            {<br>                osg::DrawElements *de = dynamic_cast<osg::DrawElements*>(ps.get());<br>                if (!(de != NULL && de->getMode() == osg::PrimitiveSet::TRIANGLE_STRIP))<br>                     new_psl.push_back(ps);<br>            }<br><br>            geometry.setPrimitiveSetList(new_psl);<br>        }<br>    }<br>};<br><br><div><br></div></div></div>