[osg-users] osgUtil::Tessellator issues

OpenSceneGraph Users osg-users at lists.openscenegraph.org
Thu Apr 16 05:36:45 PDT 2020


Hi Community,

I am struggling with the Tessellator to make it work. I tried to consult
the OpenGL spec for the winding types and I tried all of them without
success :/. It is simple case where I have polygon with two wholes. The
contour generation seams to be ok, like in the attached picture, just the
tesselation is make it wrong, or I am using the Tessellator wrong. I am
attaching the source too - it requires boost 69 or later - used for the
union of the triangles.

Any hint is highly appreciated as always!
And thanks a bunch!

-- 
trajce nikolov nick

-- 
You received this message because you are subscribed to the Google Groups "OpenSceneGraph Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to osg-users+unsubscribe at googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osg-users/CAO-%2Bzi%3DbFEYKMhyLVO%2BkqKhMLZa8Yg33ohiW02p0MQf8Kqt3iw%40mail.gmail.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20200416/470e92d1/attachment-0001.html>
-------------- next part --------------
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commercial and non commercial applications,
 * as long as this copyright notice is maintained.
 *
 * This application is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <osg/CoordinateSystemNode>
#include <osg/CullFace>
#include <osg/LineWidth>

#include <osgUtil/DelaunayTriangulator>
#include <osg/Switch>
#include <osg/Types>
#include <osgText/Text>

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/SphericalManipulator>
#include <osgUtil/Tessellator>
#include <deque>
#include <osg/io_utils>

#if 1
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

#include <boost/foreach.hpp>

typedef boost::geometry::model::d2::point_xy<double> point;
typedef boost::geometry::model::polygon<point> polygon;
#endif

#include <osgGA/Device>

#include <iostream>



void createPerfectConstraint(osg::Geometry* dc)
{
	typedef boost::geometry::model::multi_polygon<polygon> mpolygon;
	mpolygon mp;
	polygon p;

	std::vector< polygon > polygons;

	osg::ref_ptr<osg::Vec3Array> vertices = dynamic_cast<osg::Vec3Array*>(dc->getVertexArray());

	for (size_t i = 0; i < dc->getNumPrimitiveSets(); ++i)
	{
		osg::ref_ptr<osg::DrawArrays> da = dynamic_cast<osg::DrawArrays*>(dc->getPrimitiveSet(i));
		if (!da.valid()) continue;

		size_t start = da->getFirst();
		size_t count = da->getCount();

		size_t cnt = 0;
		while (cnt < count)
		{
			p.clear();

			const osg::Vec3& v1 = vertices->at(start + cnt++);
			const osg::Vec3& v3 = vertices->at(start + cnt++);
			const osg::Vec3& v2 = vertices->at(start + cnt++);

			boost::geometry::append(p, point(v1.x(), v1.y()));
			boost::geometry::append(p, point(v2.x(), v2.y()));
			boost::geometry::append(p, point(v3.x(), v3.y()));
			boost::geometry::append(p, point(v1.x(), v1.y()));

			std::string reason;
			if (!boost::geometry::is_valid(p, reason))
			{
				std::cout << "Correcting data: " << reason << "\n";
				boost::geometry::correct(p);

				std::cout << v1 << v2 << v3 << std::endl;
			}

			polygons.push_back(p);
		}
	}
	mpolygon border;   // the unioned polygons

	for (polygon p : polygons)
	{
		// add another polygon each iteration
		mpolygon tmp_poly;
		boost::geometry::union_(border, p, tmp_poly);
		border = tmp_poly;
	}

	mp = border;

	if (mp.size() < 1) return;
	
	p = mp.at(mp.size() - 1);

	std::string reason;
	if (!boost::geometry::is_valid(p, reason))
	{
		std::cout << "Correcting data: " << reason << "\n";
		boost::geometry::correct(p);
	}

	std::vector< osg::ref_ptr<osg::Vec3Array> > contours;

	osg::Vec3Array* out = new osg::Vec3Array;
	contours.push_back(out);

	for (int i = 0; i < p.outer().size(); ++i) 
	{
		double x = boost::geometry::get<0>(p.outer()[i]);
		double y = boost::geometry::get<1>(p.outer()[i]);
		std::cout << " " << x;
		std::cout << " " << y;

		out->push_back(osg::Vec3(x, y, 0));
	}

#if 1
	dc->removePrimitiveSet(0, dc->getNumPrimitiveSets());
	dc->setVertexArray(out);
	dc->addPrimitiveSet(new osg::DrawArrays(GL_LINE_LOOP, 0, out->size()));
#endif
	for (unsigned i = 0; i < p.inners().size(); ++i)
	{
		const boost::geometry::model::ring<point>& inner = p.inners()[i];

		size_t start = out->size();
		osg::Vec3Array* contour = new osg::Vec3Array;
		for (int j = 0; j < inner.size(); ++j)
		{
			double x = boost::geometry::get<0>(inner[j]);
			double y = boost::geometry::get<1>(inner[j]);
			std::cout << " " << x;
			std::cout << " " << y;

			out->push_back(osg::Vec3(x, y, 0));
			contour->push_back(osg::Vec3(x, y, 0));
		}
		contours.push_back(contour);
		dc->addPrimitiveSet(new osg::DrawArrays(GL_LINE_LOOP, start, out->size()-start));
	}
	return;

	osgUtil::Tessellator t;
#if 1
	
	
	t.beginTessellation();
	
	for (size_t i = 0; i < contours.size(); ++i)
	{
		t.beginContour();
		osg::Vec3Array* vxs = contours.at(i);
		
		for (size_t j = 0; j < vxs->size(); ++j)
		{
			osg::Vec3* v = &vxs->at(j);
			t.addVertex(v);
		}
		t.endContour();
	}
	
	t.endTessellation();
#else
	t.retessellatePolygons(*dc);
#endif

#if 1
	dc->removePrimitiveSet(0, dc->getNumPrimitiveSets());

	osg::ref_ptr<osg::Vec3Array> resultVertices = new osg::Vec3Array;
	dc->setVertexArray(resultVertices);

	osgUtil::Tessellator::PrimList& primitives = t.getPrimList();
	for (size_t i = 0; i < primitives.size(); ++i)
	{
		osg::ref_ptr<osgUtil::Tessellator::Prim>& primitive = primitives.at(i);

		size_t start = resultVertices->size();
		for (size_t k = 0; k < primitive->_vertices.size(); ++k)
		{
			osg::Vec3* v = primitive->_vertices.at(k);
			resultVertices->push_back(*v);
		}

		dc->addPrimitiveSet(new osg::DrawArrays(primitive->_mode, start, resultVertices->size() - start));
	}
#endif

#if 0
	osg::ref_ptr<osg::Geode> tempGeode = new osg::Geode;
	tempGeode->addDrawable(dc);

	UnrollGeometryVisitor nv;
	tempGeode->accept(nv);
	nv.finalize();

	osg::ref_ptr<osg::Vec3Array> finalVertices = dynamic_cast<osg::Vec3Array*>(nv.geometryAsTriangles->getVertexArray());
	dc->setVertexArray(finalVertices);
	
	dc->removePrimitiveSet(0, dc->getNumPrimitiveSets());

	size_t cnt = 0;
	while (cnt < finalVertices->size())
	{
		polygon p;

		const osg::Vec3& v1 = finalVertices->at(cnt++);
		const osg::Vec3& v2 = finalVertices->at(cnt++);
		const osg::Vec3& v3 = finalVertices->at(cnt++);

		dc->addPrimitiveSet(new osg::DrawArrays(GL_LINE_LOOP,cnt-3, 3));
	}
#endif
}
	

osg::Node* createScene()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;

	osg::ref_ptr<osg::Vec3Array> points = new osg::Vec3Array;

	
	osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
	geometry->setVertexArray(points);
	geode->addDrawable(geometry);

	size_t start = 0;
	points->push_back(osg::Vec3(3, -10, 0));
	points->push_back(osg::Vec3(10, -10, 0));
	points->push_back(osg::Vec3(10, 30, 0));
	points->push_back(osg::Vec3(10, 30, 0));
	points->push_back(osg::Vec3(3, 30, 0));
	points->push_back(osg::Vec3(3, -10, 0));

	//geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, start, points->size()-start));

	start = points->size();
	points->push_back(osg::Vec3(-10, -10, 0));
	points->push_back(osg::Vec3(-3, -10, 0));
	points->push_back(osg::Vec3(-3, 30, 0));
	points->push_back(osg::Vec3(-3, 30, 0));
	points->push_back(osg::Vec3(-10,30, 0));
	points->push_back(osg::Vec3(-10, -10, 0));

	//geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, start, points->size()-start));

	start = points->size();
	points->push_back(osg::Vec3(-15, 25, 0));
	points->push_back(osg::Vec3(15, 25, 0));
	points->push_back(osg::Vec3(15, 45, 0));
	points->push_back(osg::Vec3(15, 45, 0));
	points->push_back(osg::Vec3(-15, 45, 0));
	points->push_back(osg::Vec3(-15, 25, 0));

	points->push_back(osg::Vec3(-15, -5, 0));
	points->push_back(osg::Vec3(15, -5, 0));
	points->push_back(osg::Vec3(15, 15, 0));
	points->push_back(osg::Vec3(15, 15, 0));
	points->push_back(osg::Vec3(-15, 15, 0));
	points->push_back(osg::Vec3(-15, -5, 0));

	//geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, start, points->size() - start));

	start = points->size();
	points->push_back(osg::Vec3(-15, -7, 0));
	points->push_back(osg::Vec3(15, -7, 0));
	points->push_back(osg::Vec3(15, -15, 0));
	points->push_back(osg::Vec3(15, -15, 0));
	points->push_back(osg::Vec3(-15, -15, 0));
	points->push_back(osg::Vec3(-15, -7, 0));

	geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, points->size()));

	createPerfectConstraint(geometry);

	return geode.release();
}

int main(int argc, char** argv)
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad");
    arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField");
    arguments.getApplicationUsage()->addCommandLineOption("--login <url> <username> <password>","Provide authentication information for http file access.");
    arguments.getApplicationUsage()->addCommandLineOption("-p <filename>","Play specified camera path animation file, previously saved with 'z' key.");
    arguments.getApplicationUsage()->addCommandLineOption("--speed <factor>","Speed factor for animation playing (1 == normal speed).");
    arguments.getApplicationUsage()->addCommandLineOption("--device <device-name>","add named device to the viewer");
    arguments.getApplicationUsage()->addCommandLineOption("--stats","print out load and compile timing stats");

    osgViewer::Viewer viewer(arguments);

    unsigned int helpType = 0;
    if ((helpType = arguments.readHelpType()))
    {
        arguments.getApplicationUsage()->write(std::cout, helpType);
        //return 1;
    }

    // report any errors if they have occurred when parsing the program arguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        //return 1;
    }

    if (arguments.argc()<=1)
    {
        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
        //return 1;
    }

    bool printStats = arguments.read("--stats");

    std::string url, username, password;
    while(arguments.read("--login",url, username, password))
    {
        osgDB::Registry::instance()->getOrCreateAuthenticationMap()->addAuthenticationDetails(
            url,
            new osgDB::AuthenticationDetails(username, password)
        );
    }

    std::string device;
    while(arguments.read("--device", device))
    {
        osg::ref_ptr<osgGA::Device> dev = osgDB::readRefFile<osgGA::Device>(device);
        if (dev.valid())
        {
            viewer.addDevice(dev);
        }
    }

    // set up the camera manipulators.
    {
        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;

        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
        keyswitchManipulator->addMatrixManipulator( '5', "Orbit", new osgGA::OrbitManipulator() );
        keyswitchManipulator->addMatrixManipulator( '6', "FirstPerson", new osgGA::FirstPersonManipulator() );
        keyswitchManipulator->addMatrixManipulator( '7', "Spherical", new osgGA::SphericalManipulator() );

        std::string pathfile;
        double animationSpeed = 1.0;
        while(arguments.read("--speed",animationSpeed) ) {}
        char keyForAnimationPath = '8';
        while (arguments.read("-p",pathfile))
        {
            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
            if (apm && !apm->getAnimationPath()->empty())
            {
                apm->setTimeScale(animationSpeed);

                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
                keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
                keyswitchManipulator->selectMatrixManipulator(num);
                ++keyForAnimationPath;
            }
        }

        viewer.setCameraManipulator( keyswitchManipulator.get() );
    }

    // add the state manipulator
    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );

    // add the thread model handler
    viewer.addEventHandler(new osgViewer::ThreadingHandler);

    // add the window size toggle handler
    viewer.addEventHandler(new osgViewer::WindowSizeHandler);

    // add the stats handler
    viewer.addEventHandler(new osgViewer::StatsHandler);

    // add the help handler
    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));

    // add the record camera path handler
    viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);

    // add the LOD Scale handler
	osgViewer::LODScaleHandler* lsh;
    viewer.addEventHandler(lsh = new osgViewer::LODScaleHandler);

	lsh->setKeyEventIncreaseLODScale('+');
	lsh->setKeyEventDecreaseLODScale('-');


    // add the screen capture handler
    viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);


    osg::ElapsedTime elapsedTime;

    // load the data
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readRefNodeFiles(arguments);
    if (!loadedModel)
    {
        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
        //return 1;
    }

    if (printStats)
    {
        double loadTime = elapsedTime.elapsedTime_m();
        std::cout<<"Load time "<<loadTime<<"ms"<<std::endl;

        viewer.getStats()->collectStats("compile", true);
    }


    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occurred when parsing the program arguments.
    if (arguments.errors())
    {
        //arguments.writeErrorMessages(std::cout);
        return 1;
    }


    // optimize the scene graph, remove redundant nodes and state etc.
    osgUtil::Optimizer optimizer;
    //optimizer.optimize(loadedModel);

	size_t numBlades = 2;

	osg::ref_ptr<osg::Group> scene = new osg::Group;
	scene->addChild(loadedModel);

#if 1
	scene->addChild(createScene());
#endif

	viewer.setSceneData(scene);

	scene->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::FRONT_AND_BACK), osg::StateAttribute::OFF);

	std::cout << "Model radius: " << scene->getBound().radius() << std::endl;

    viewer.realize();

    return viewer.run();

}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: contours.jpg
Type: image/jpeg
Size: 25172 bytes
Desc: not available
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20200416/470e92d1/attachment-0002.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: tesselated.jpg
Type: image/jpeg
Size: 46768 bytes
Desc: not available
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20200416/470e92d1/attachment-0003.jpg>


More information about the osg-users mailing list