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

被折叠的 条评论
为什么被折叠?



