osg--提高效率

本文介绍了如何使用OpenThreads进行多线程管理和渲染,包括线程的启动、状态检查以及多线程渲染的设置。同时,探讨了OpenSceneGraph(OSG)中的剔除技术,如背面剔除、视锥剔除和遮挡剔除,以及纹理共享的实现。此外,还提到了osgUtil::Optimizer优化工具和动态加载四叉树技术,如osg::HeightField和osg::PagedLOD的应用。

多线程

  • OpenThreads::Thread
    • 虚函数
      • cancel()
      • run()
  • OpenThreads::Mutex
  • OpenThreads::Barrier
  • OpenThreads::Condition

线程管理

  • GetNumberOfProcessors() 处理器数目获取
  • SetProcessorAffinityOfCurrentThread() 当前线程使用处理器设置
  • CurrentThread()
  • YieldCurrentThread() 让出处理器给其它线程
  • microSleep() 当前线程休息毫秒
  • isRunning() 线程运行状态
  • startThread()开启线程

多线程渲染

注意:update过程不参与多线程渲染

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • setThreadingModel() 设置渲染模式
    • AutomaticSelection
    • SingleThreaded
    • ThreadPerContext
    • ThreadPerCamera

示例–多线程数据接收

#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <iostream>
#include <io.h>
class DataReceiverThread : public OpenThreads::Thread
{
public:
	static DataReceiverThread* instance()
	{
		static DataReceiverThread s_thread;
		return &s_thread;
	}


	virtual int cancel();
	virtual void run();

	void addToContent(int ch);
	bool getContent(std::string& str);


protected:
	OpenThreads::Mutex _mutex;
	std::string _content;
	bool _done;
	bool _dirty;
};
int DataReceiverThread::cancel()
{
	_done = true;
	while (isRunning()) 
		YieldCurrentThread();
	return 0;
}
void DataReceiverThread::run()
{
	_done = false;
	_dirty = true;
	do
	{
		YieldCurrentThread();
		char ch = 0;
		std::cin.get(ch);
		switch (ch)
		{
		case 0: 
			break;  // We don't want '\0' to be added
		case 9: 
			_done = true; 
			break;  // ASCII code of Tab = 9
		default: 
			addToContent(ch); 
			break;
		}
	} while (!_done);
}
void DataReceiverThread::addToContent(int ch)
{
	OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
	_content += ch;
	_dirty = true;
}
bool DataReceiverThread::getContent(std::string& str)
{
	OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
	if (_dirty)
	{
		str += _content;
		_dirty = false;
		return true;
	}
	return false;
}
class UpdateTextCallback : public osg::Drawable::UpdateCallback
{
public:
	virtual void update(osg::NodeVisitor* nv,osg::Drawable* drawable)
	{
		osgText::Text* text = static_cast<osgText::Text*>(drawable);
		if (text)
		{
			std::string str("# ");
			if (DataReceiverThread::instance()->getContent(str))
				text->setText(str);
		}
	}
};
int main(int argc, char** argv)
{
	osg::ref_ptr<osgText::Text> text = new osgText::Text;
	text->setFont("fonts/arial.ttf");
	text->setAxisAlignment(osgText::TextBase::SCREEN);
	text->setDataVariance(osg::Object::DYNAMIC);
	text->setInitialBound(osg::BoundingBox(osg::Vec3(), osg::Vec3(400.0f, 20.0f, 20.0f)));
	text->setUpdateCallback(new UpdateTextCallback);

	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	geode->addDrawable(text.get());
	geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
	osgViewer::Viewer viewer;
	viewer.setSceneData(geode.get());
	viewer.setUpViewInWindow(50, 50, 640, 480);

	DataReceiverThread::instance()->startThread();
	viewer.run();
	DataReceiverThread::instance()->cancel();
	return 0;
}

示例–多线程渲染

#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/CompositeViewer>
#define RAND(min, max) ((min) + (float)rand()/(RAND_MAX+1) * ((max)-(min)))
osg::Geode* createMassiveQuads(unsigned int number)
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	for (unsigned int i = 0; i<number; ++i)
	{
		osg::Vec3 randomCenter;
		randomCenter.x() = RAND(-100.0f, 100.0f);
		randomCenter.y() = RAND(1.0f, 100.0f);
		randomCenter.z() = RAND(-100.0f, 100.0f);

		osg::ref_ptr<osg::Drawable> quad =
			osg::createTexturedQuadGeometry(
				randomCenter,
				osg::Vec3(1.0f, 0.0f, 0.0f),
				osg::Vec3(0.0f, 0.0f, 1.0f)
			);
		geode->addDrawable(quad.get());
	}
	return geode.release();
}
osgViewer::View* createView(int x, int y, int w, int h,osg::Node* scene)
{
	osg::ref_ptr<osgViewer::View> view = new osgViewer::View;
	view->setSceneData(scene);
	view->setUpViewInWindow(x, y, w, h);
	return view.release();
}
int main(int argc, char** argv)
{
	osg::ArgumentParser arguments(&argc, argv);

	osgViewer::ViewerBase::ThreadingModel th =
		osgViewer::ViewerBase::AutomaticSelection;
	if (arguments.read("--single")) th =
		osgViewer::ViewerBase::SingleThreaded;
	else if (arguments.read("--useContext")) th =
		osgViewer::ViewerBase::ThreadPerContext;
	else if (arguments.read("--useCamera")) th =
		osgViewer::ViewerBase::ThreadPerCamera;

	osgViewer::View* view1 = createView(50, 50, 640, 480,
		createMassiveQuads(10000));
	osgViewer::View* view2 = createView(50, 550, 320, 240,
		createMassiveQuads(5000));
	osgViewer::View* view3 = createView(370, 550, 320, 240,
		createMassiveQuads(5000));
	view1->addEventHandler(new osgViewer::StatsHandler);

	osgViewer::CompositeViewer viewer;
	viewer.setThreadingModel(th);
	viewer.addView(view1);
	viewer.addView(view2);
	viewer.addView(view3);
	return viewer.run();
}

culll

  • Back face culling 排除背面
    • osg::CullFace
  • Small feature culling 小于像素阈值
  • View-frustum culling 视角外
  • Occlusion culling 被遮挡
    • osg::OccluderNode 继承osg::Group,子节点不被遮挡,兄弟节点进行比较
    • setOccluder()
      • osg::ConvexPlanarOccluder
        • getOccluder()
          • add()
          • addHole()

关闭Small feature culling

camera->setCullingMode(camera->getCullingMode() & ~osg::Camera::SMALL_FEATURE_CULLING );

示例–Occlusion culling

#include <osg/Geometry>
#include <osg/Geode>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Viewer>
#define RAND(min, max) \
        ((min) + (float)rand()/(RAND_MAX+1) * ((max)-(min)))
osg::Geode* createMassiveQuads(unsigned int number)
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	for (unsigned int i = 0; i<number; ++i)
	{
		osg::Vec3 randomCenter;
		randomCenter.x() = RAND(-100.0f, 100.0f);
		randomCenter.y() = RAND(1.0f, 100.0f);
		randomCenter.z() = RAND(-100.0f, 100.0f);

		osg::ref_ptr<osg::Drawable> quad =
			osg::createTexturedQuadGeometry(
				randomCenter,
				osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 0.0f, 1.0f)
			);
		geode->addDrawable(quad.get());
	}
	return geode.release();
}

int main(int argc, char** argv)
{
	osg::ref_ptr<osg::OccluderNode> occluderNode = new
		osg::OccluderNode;

	osg::ref_ptr<osg::ConvexPlanarOccluder> cpo = new
		osg::ConvexPlanarOccluder;
	cpo->getOccluder().add(osg::Vec3(-120.0f, 0.0f, -120.0f));
	cpo->getOccluder().add(osg::Vec3(120.0f, 0.0f, -120.0f));
	cpo->getOccluder().add(osg::Vec3(120.0f, 0.0f, 120.0f));
	cpo->getOccluder().add(osg::Vec3(-120.0f, 0.0f, 120.0f));
	occluderNode->setOccluder(cpo.get());

	osg::ref_ptr<osg::Geode> occluderGeode = new osg::Geode;
	occluderGeode->addDrawable(osg::createTexturedQuadGeometry(
		osg::Vec3(-120.0f, 0.0f, -120.0f),
		osg::Vec3(240.0f, 0.0f, 0.0f),
		osg::Vec3(0.0f, 0.0f, 240.0f))
	);
	occluderNode->addChild(occluderGeode.get());

	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(createMassiveQuads(100000));
	root->addChild(occluderNode.get());
	root->getOrCreateStateSet()->setMode(
		GL_LIGHTING, osg::StateAttribute::OFF);
	osgViewer::Viewer viewer;
	viewer.addEventHandler(new osgViewer::StatsHandler);
	viewer.setSceneData(root.get());
	return viewer.run();
}

纹理共享

osgDB::SharedStateManager 比较子节点属性,如果相同进行合并

osgDB::Registry::instance()->getOrCreateSharedStateManager();

osgDB::SharedStateManager* ssm = osgDB::Registry::instance()->getSharedStateManager();
if ( ssm ) 
	ssm->share( root.get() );

SharedStateManager记录第一个属性和纹理,对于后续的属性和纹理,进行比较,如果一致,进行合并。

对于纹理,检查data()指向(也就是image)是否一致

osgDB::DatabasePager利用了osgDB::SharedStateManager

示例

#include <osg/Texture2D>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#define RAND(min, max) \
        ((min) + (float)rand()/(RAND_MAX+1) * ((max)-(min)))
osg::Geode* createMassiveQuads(unsigned int number,
	const std::string& imageFile)
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	for (unsigned int i = 0; i<number; ++i)
	{
		osg::Vec3 randomCenter;
		randomCenter.x() = RAND(-100.0f, 100.0f);
		randomCenter.y() = RAND(1.0f, 100.0f);
		randomCenter.z() = RAND(-100.0f, 100.0f);

		osg::ref_ptr<osg::Drawable> quad =
			osg::createTexturedQuadGeometry(
				randomCenter,
				osg::Vec3(1.0f, 0.0f, 0.0f),
				osg::Vec3(0.0f, 0.0f, 1.0f)
			);

		osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
		texture->setImage(osgDB::readImageFile(imageFile));
		quad->getOrCreateStateSet()->setTextureAttributeAndModes(
			0, texture.get()); 
		geode->addDrawable(quad.get());
	}
	return geode.release();
}
class ReadAndShareImageCallback : public osgDB::ReadFileCallback
{
public:
	virtual osgDB::ReaderWriter::ReadResult readImage(
		const std::string& filename, const osgDB::Options* options
	);

protected:
	osg::Image* getImageByName(const std::string& filename)
	{
		ImageMap::iterator itr = _imageMap.find(filename);
		if (itr != _imageMap.end()) 
			return itr->second.get();
		return NULL;
	}

	typedef std::map<std::string, osg::ref_ptr<osg::Image> > ImageMap;
	ImageMap _imageMap;
};
osgDB::ReaderWriter::ReadResult ReadAndShareImageCallback::readImage(
	const std::string& filename, const osgDB::Options* options)
{
	osg::Image* image = getImageByName(filename);
	if (!image)
	{
		osgDB::ReaderWriter::ReadResult rr;
		rr = osgDB::Registry::instance()->readImageImplementation(filename, options);
		if (rr.success()) 
			_imageMap[filename] = rr.getImage();
		return rr;
	}
	return image;
}
int main(int argc, char** argv)
{
	osgDB::Registry::instance()->setReadFileCallback(
		new ReadAndShareImageCallback);
	osgDB::Registry::instance()->getOrCreateSharedStateManager();

	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(createMassiveQuads(500, "Images/lz.rgb"));
	root->addChild(createMassiveQuads(500, "Images/osg64.png"));

	osgDB::SharedStateManager* ssm =
		osgDB::Registry::instance()->getSharedStateManager();
	if (ssm) 
		ssm->share(root.get());

	osgViewer::Viewer viewer;
	viewer.setSceneData(root.get());
	return viewer.run();
}

常见效率问题

在这里插入图片描述

osgUtil::Optimizer用于移除冗余节点、共享状态机属性、检查合并几何体、优化纹理设置等

osgUtil::Optimizer optimizer;
optimizer.optimize( node );

动态加载-四叉树

多用于地图数据

osg::HeightField

继承osg::Shape,用于osg::ShapeDrawable

  • setSkirtHeight
  • setOrigin
  • allocate
  • setXInterval
  • setYInterval
  • setHeight

osg::PagedLOD

  • setCenterMode
  • setCenter
  • setRadius
  • setRange

示例

#include <osg/ShapeDrawable>
#include <osg/PagedLOD>
#include <osgDB/WriteFile>
#include <sstream>

float* g_data = NULL;
float g_dx = 1.0f;
float g_dy = 1.0f;
unsigned int g_minCols = 64;
unsigned int g_minRows = 64;
unsigned int g_numCols = 1024;
unsigned int g_numRows = 1024;

#define RAND(min, max) ((min) + (float)rand()/(RAND_MAX+1) * ((max)-(min)))
void createMassiveData()
{
	g_data = new float[g_numCols * g_numRows]; 
	for (unsigned int i = 0; i<g_numRows; ++i)
	{
		for (unsigned int j = 0; j<g_numCols; ++j)
			g_data[i*g_numCols + j] = RAND(0.5f, 0.0f);
	}
}
float getOneData(unsigned int c, unsigned int r)
{
	return g_data[osg::minimum(r, g_numRows - 1) * g_numCols +
		osg::minimum(c, g_numCols - 1)];
}
std::string createFileName(unsigned int lv,unsigned int x, unsigned int y)
{
	std::stringstream sstream;
	sstream << "quadtree_L" << lv << "_X" << x << "_Y" << y <<
		".osg";
	return sstream.str();
}
osg::Node* outputSubScene(unsigned int lv,unsigned int x, unsigned int y,const osg::Vec4& color)
{
	unsigned int numInUnitCol = g_numCols / (int)powf(2.0f,(float)lv);
	unsigned int numInUnitRow = g_numRows / (int)powf(2.0f,(float)lv);
	unsigned int xDataStart = x * numInUnitCol,xDataEnd = (x + 1) * numInUnitCol;
	unsigned int yDataStart = y * numInUnitRow,yDataEnd = (y + 1) * numInUnitRow;
	bool stopAtLeafNode = false;

	osg::ref_ptr<osg::HeightField> grid = new osg::HeightField;
	grid->setSkirtHeight(1.0f);
	grid->setOrigin(osg::Vec3(g_dx*(float)xDataStart,g_dy*(float)yDataStart, 0.0f));

	if (xDataEnd - xDataStart <= g_minCols &&
		yDataEnd - yDataStart <= g_minRows)
	{
		grid->allocate(xDataEnd - xDataStart + 1, yDataEnd - yDataStart + 1);
		grid->setXInterval(g_dx);
		grid->setYInterval(g_dy);
		for (unsigned int i = yDataStart; i <= yDataEnd; ++i) {
			for (unsigned int j = xDataStart; j <= xDataEnd; ++j)
			{
				grid->setHeight(j - xDataStart, i - yDataStart,
					getOneData(j, i));
			}
		}
		stopAtLeafNode = true;
	}
	else
	{
		unsigned int jStep = (unsigned int)ceilf((float)(xDataEnd - xDataStart) / (float)g_minCols);
		unsigned int iStep = (unsigned int)ceilf((float)(yDataEnd - yDataStart) / (float)g_minRows);


		grid->allocate(g_minCols + 1, g_minRows + 1);
		grid->setXInterval(g_dx * jStep);
		grid->setYInterval(g_dy * iStep);
		for (unsigned int i = yDataStart, ii = 0; i <= yDataEnd;i += iStep, ++ii)
		{
			for (unsigned int j = xDataStart, jj = 0; j <= xDataEnd;j += jStep, ++jj)
			{
				grid->setHeight(jj, ii, getOneData(j, i));
			}
		}
	}
	osg::ref_ptr<osg::ShapeDrawable> shape =new osg::ShapeDrawable(grid.get());
	shape->setColor(color);
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	geode->addDrawable(shape.get());
	if (stopAtLeafNode) 
		return geode.release();

	osg::ref_ptr<osg::Group> group = new osg::Group;
	group->addChild(outputSubScene(lv + 1, x * 2, y * 2, osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)));
	group->addChild(outputSubScene(lv + 1, x * 2, y * 2 + 1, osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)));
	group->addChild(outputSubScene(lv + 1, x * 2 + 1, y * 2 + 1,osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)));
	group->addChild(outputSubScene(lv + 1, x * 2 + 1, y * 2, osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)));

	osg::ref_ptr<osg::PagedLOD> plod = new osg::PagedLOD;
	std::string filename = createFileName(lv, x, y);
	plod->insertChild(0, geode.get());
	plod->setFileName(1, filename);
	osgDB::writeNodeFile(*group, filename);

	plod->setCenterMode(osg::PagedLOD::USER_DEFINED_CENTER);
	plod->setCenter(geode->getBound().center());
	plod->setRadius(geode->getBound().radius());
	float cutoff = geode->getBound().radius() * 5.0f;
	plod->setRange(0, cutoff, FLT_MAX);
	plod->setRange(1, 0.0f, cutoff);
	return plod.release();
}
int main(int argc, char** argv)
{
	createMassiveData();
	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(outputSubScene(0, 0, 0, osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)));
	osgDB::writeNodeFile(*root, "quadtree.osg");
	delete g_data;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值