前言

当我使用osg绘制场景的时候,绘制大量相同图元的时候时候,如果不设置背面剔除的话,当顶点数量达到上百万个很多显卡都吃不消,帧率会掉的很快,我的显卡是NVIDIA GeForce GTX 1660 Ti

osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;提高帧率_智能指针

运行下面一段代码

//Geometry->Drawable->Node->Object->Referenced
//AlphaFunc->StateAttribute->Object->Referenced
//StateAttributeCallback->Callback->Object->Referenced
//ClearNode->Group->Node->Object->Referenced
//CoordinateSystemNode->Group->Node->Object->Referenced
//Billboard->Geode->Group->Node->Object->Referenced
//Image->BufferData->Object->Referenced
//Texture1D/Texture2D/Texture2DArray/Texture3D->Texture->TextureAttribute->StateAttribute->Object->Referenced

//Group->Node->Object->Referenced
//Geode->Group->Node->Object->Referenced
//Geometry->Drawable->Node->Object->Referenced
//AlphaFunc->StateAttribute->Object->Referenced
//StateAttributeCallback->Callback->Object->Referenced
//ClearNode->Group->Node->Object->Referenced
//CoordinateSystemNode->Group->Node->Object->Referenced
//Billboard->Geode->Group->Node->Object->Referenced
//Image->BufferData->Object->Referenced
//Texture1D/Texture2D/Texture2DArray/Texture3D->Texture->TextureAttribute->StateAttribute->Object->Referenced
//DrawArrays->PrimitiveSet->BufferData->Object->Object->Referenced
//MatrixTransform->Transform->Group->Node->Object->Referenced
//StateSet->Object

//StateAttribute->Object
//hadeModel->StateAttribute->Object
//CullFace->StateAttribute->Object
//PolygonMode->StateAttribute->Object

#include "osg/Group"
#include "osg/Geode"
#include "osg/Geometry"
#include "osg/Point"
#include "osg/Drawable"
#include "osg/StateAttribute"
#include "osg/StateSet"
#include "osg/Material"
#include "osg/MatrixTransform"
#include "osg/Matrix"
#include "osg/LightSource"
#include "osg/Light"
#include "osgDB/ReadFile"
#include "osgDB/WriteFile"
#include "osg/Notify"
#include "osg/CullFace"
#include "osgViewer/Viewer"
#include "osgUtil/Optimizer"

using namespace osg;
using namespace std;

osg::ref_ptr<osg::Geode> createLightPoint()
{
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();

// Don't throw away single-vertex primitives.
//边界盒
osg::BoundingBox bBox(-.1f, -.1f, -.1f, .1f, .1f, .1f);
geom->setInitialBound(bBox);

osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();
geom->setVertexArray(v.get());
v->push_back(osg::Vec3f(0.f, 0.f, 0.f));

osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array();
geom->setColorArray(c.get());
geom->setColorBinding(osg::Geometry::BIND_OVERALL); //BIND_OVERALL:这个光源都是颜色绑定方式对应唯一的颜色:红色
c->push_back(osg::Vec4f(1.f, 0.f, 0.f, 1.f));

geom->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, 1)); //基本图元是绘制点

//Geode是叶子节点,把Geometry加入到叶子节点中
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(geom.get());

//设置状态属性
osg::ref_ptr<StateSet> state = geode->getOrCreateStateSet();
state->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
osg::ref_ptr<osg::Point> pt = new osg::Point();
pt->setSize(10.f);
state->setAttribute(pt.get());

return (geode.release());
//return (geode);
}

osg::ref_ptr<osg::Drawable> createPlane()
{
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();

//顶点
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();
geom->setVertexArray(v.get());
int x, y;
for (y = -10; y <= 10; y++)
{
for (x = -10; x <= 10; x++)
{
v->push_back(osg::Vec3((float)x * .5f, (float)y * .5f, 0.f));
}
}

//法线
osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array();
geom->setNormalArray(n.get());
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
n->push_back(osg::Vec3(0.f, 0.f, 1.f));

//颜色
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array();
geom->setColorArray(c.get());
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
c->push_back(osg::Vec4(1.f, 1.f, 1.f, 1.f));

const int len(21);
int idx(0);
int numStrips(len - 1);
while (numStrips--)
{
GLushort indices[len + len];
int vert(0);
while (vert < len)
{
indices[2 * vert + 0] = idx + len;
indices[2 * vert + 1] = idx;
vert++;
idx++;
}
//geom->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::QUADS, len + len, indices));
geom->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP, len + len, indices));
}

return (geom.release());
}


//1.指定几何体法线
//2.允许光照并设置光照状态
//3.指定光源属性并关联到场景图形
//4.指定物体表面材质属性
//5.只有光源并没有阴影,阴影需要sogShadow来创建
osg::ref_ptr<osg::Node> createSceneGraph()
{
// Create the root node and set state for the entire subgraph.
osg::ref_ptr<osg::Group> group = new osg::Group();
osg::ref_ptr<osg::Node> root = new osg::Node();
{
osg::ref_ptr<osg::StateSet> state = group->getOrCreateStateSet();
state->setMode(GL_LIGHTING, osg::StateAttribute::ON);
state->setMode(GL_LIGHT0, osg::StateAttribute::ON);
state->setMode(GL_LIGHT1, osg::StateAttribute::ON);
}
// Represent the two light sources with a shared point.
// Each light's position is 0,0,0 in object coordinates. The
// two parent MatrixTransforms translate the lights, and the
// shared point, to their actual positions.
//osg::ref_ptr<osg::Geode> lightPoint = new osg::Geode;
osg::ref_ptr<osg::Geode> lightPoint = createLightPoint();
{


osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
//osg::Matrix 没有继承Referenced 所以不能用智能指针
osg::Matrix m;
osg::ref_ptr<RefMatrix> refM = new osg::RefMatrix;

refM->makeTranslate(osg::Vec3(-3.f, 2.f, 5.f));
mt->setMatrix(*refM);

// Create a mostly red light
osg::ref_ptr<osg::Light> light = new osg::Light;
light->setLightNum(0);
light->setPosition(osg::Vec4(0.f, 0.f, 0.f, 1.f));
light->setDiffuse(osg::Vec4(1.f, .5f, .5f, 1.f));
light->setSpecular(osg::Vec4(1.f, .8f, .8f, 1.f));

//设置光源:第一个光源
osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
group->addChild(mt.get());
//mt->setMatrix(*m);
mt->addChild(ls.get());
ls->setLight(light.get());
ls->addChild(lightPoint.get());
}

{
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
osg::ref_ptr<osg::RefMatrix> refM = new osg::RefMatrix;
refM->makeTranslate(osg::Vec3(3.f, -2.f, 3.f));
mt->setMatrix(*refM);

// Create a mostly blue light
osg::ref_ptr<osg::Light> light = new osg::Light;
light->setLightNum(1);
light->setPosition(osg::Vec4(0.f, 0.f, 0.f, 1.f));
light->setDiffuse(osg::Vec4(.5f, .5f, 1.f, 1.f));
light->setSpecular(osg::Vec4(.8f, .8f, 1.f, 1.f));

//设置光源:第二个光源
osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
group->addChild(mt.get());
mt->addChild(ls.get());
ls->setLight(light.get());
ls->addChild(lightPoint.get());
}

// Create a single instance of the lozenge geometry (read from disk).
// Multiply parent it to six MatrixTransform nodes, each with their
// own StateSet to change the material properties of the lozenge.
osg::ref_ptr<osg::Node> lozenge = osgDB::readNodeFile("lozenge.osg");
if (!lozenge.valid())
{
osg::notify(osg::FATAL) << "Unload to load date file. Exiting." << std::endl;
return nullptr;
}

{
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
//osg::Matrix 没有继承Referenced 所以不能用智能指针
osg::Matrix m;
osg::ref_ptr<osg::RefMatrix> refM = new osg::RefMatrix;
refM->makeTranslate(osg::Vec3(-1.f, -1.f, 1.f));
mt->setMatrix(*refM);

//设置属性
osg::ref_ptr<osg::StateSet> state = new osg::StateSet;
state = mt->getOrCreateStateSet();
//背面剔除
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(0.f, 0.f, 0.f, 1.f));
mat->setSpecular(osg::Material::FRONT, osg::Vec4(1.f, 1.f, 1.f, 1.f));
mat->setShininess(osg::Material::FRONT, 128.f);
state->setAttribute(mat.get());

mt->addChild(lozenge.get());
group->addChild(mt.get());
}
{
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
//osg::Matrix 没有继承Referenced 所以不能用智能指针
osg::Matrix m;
osg::ref_ptr<osg::RefMatrix> refM = new osg::RefMatrix;
refM->makeTranslate(osg::Vec3(1.f, -1.f, 1.f));
mt->setMatrix(*refM);

//设置属性
osg::ref_ptr<StateSet> state = mt->getOrCreateStateSet();
//背面剔除
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());
osg::ref_ptr<osg::Material> mat = new osg::Material;
// Just use the object's primary color for ambient and
// diffuse (uses the OpenGL color material feature).
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
state->setAttribute(mat.get());
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(.4f, .3f, 0.f, 1.f));
mat->setSpecular(osg::Material::FRONT, osg::Vec4(.8f, .8f, .1f, 1.f));
mat->setShininess(osg::Material::FRONT, 20.f);
state->setAttribute(mat.get());

mt->addChild(lozenge.get());
group->addChild(mt.get());
}

{
osg::ref_ptr<MatrixTransform> mt = new osg::MatrixTransform;
//osg::Matrix 没有继承Referenced 所以不能用智能指针
osg::Matrix m;
osg::ref_ptr<osg::RefMatrix> refM = new osg::RefMatrix;
refM->makeTranslate(osg::Vec3(-1.f, 0.f, 1.f));
mt->setMatrix(*refM);

osg::ref_ptr<osg::StateSet> state = mt->getOrCreateStateSet();
//背面剔除
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(.4f, .3f, 0.f, 1.f));
mat->setSpecular(osg::Material::FRONT, osg::Vec4(.8f, .8f, 1.f, 1.f));
mat->setShininess(osg::Material::FRONT, 20.f);
state->setAttribute(mat.get());

mt->addChild(lozenge.get());
group->addChild(mt.get());
}

{
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
//osg::Matrix 没有继承Referenced 所以不能用智能指针
osg::Matrix m;
osg::ref_ptr<osg::RefMatrix> refM = new osg::RefMatrix;
refM->makeTranslate(osg::Vec3(1.f, 0.f, 1.f));
mt->setMatrix(*refM);

//设置属性
osg::ref_ptr<osg::StateSet> state = mt->getOrCreateStateSet();
//背面剔除
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(.1f, .2f, .5f, 1.f));
mat->setSpecular(osg::Material::FRONT, osg::Vec4(.9f, .9f, 1.f, 1.f));
mat->setShininess(osg::Material::FRONT, 10.f);
state->setAttribute(mat.get());

mt->addChild(lozenge.get());
group->addChild(mt.get());
}

{
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
//osg::Matrix 没有继承Referenced 所以不能用智能指针
osg::Matrix m;
osg::ref_ptr<osg::RefMatrix> refM = new osg::RefMatrix;
refM->makeTranslate(osg::Vec3(-1.f, 1.f, 1.f));
mt->setMatrix(*refM);

osg::ref_ptr<osg::StateSet> state = mt->getOrCreateStateSet();
//背面剔除
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(.2f, .9f, .9f, 1.f));
mat->setSpecular(osg::Material::FRONT, osg::Vec4(1.f, 1.f, 1.f, 1.f));
mat->setShininess(osg::Material::FRONT, 96.f);
state->setAttribute(mat.get());

mt->addChild(lozenge.get());
group->addChild(mt.get());
}

{
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
osg::ref_ptr<osg::RefMatrix> refM = new osg::RefMatrix;
refM->makeTranslate(osg::Vec3(1.f, 1.f, 1.f));
mt->setMatrix(*refM);

osg::ref_ptr<osg::StateSet> state = mt->getOrCreateStateSet();
//背面剔除
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(1.f, 1.f, 1.f, 1.f));
mat->setSpecular(osg::Material::FRONT, osg::Vec4(0.f, 0.f, 0.f, 1.f));
mat->setShininess(Material::FRONT, 0.f);
state->setAttribute(mat.get());

mt->addChild(lozenge.get());
group->addChild(mt.get());

}


osg::ref_ptr<osg::Geode> planeGeode = new osg::Geode;
planeGeode->addDrawable(createPlane());
{
osg::ref_ptr<osg::StateSet> state = new osg::StateSet;
state = planeGeode->getOrCreateStateSet();
//背面剔除
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(.6f, .5f, .2f, 1.f));
mat->setSpecular(osg::Material::FRONT, osg::Vec4(.4f, .4f, .4f, 1.f));
mat->setShininess(osg::Material::FRONT, 128.f);
state->setAttribute(mat.get());

/*osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
state->setAttributeAndModes(cf.get());*/
}

group->addChild(planeGeode.get());

return group.release();
}

int main(int argc, char** argv)
{
osg::ref_ptr<osg::Node> root = createSceneGraph();
if (!root.valid())
{
osg::notify(osg::FATAL) << "Failed in createSceneGraph()." << std::endl;
return (1);
}



//每次执行writeNodeFile都会往lozenge.osg文件中写入顶点,默认是追加写入,所以lozenge.osg文件会越来越大,直到显卡崩溃
std::string out("lozenge.osg");
if (!(osgDB::writeNodeFile(*(root.get()), out)))
{
osg::notify(osg::FATAL) << "Failed in osgDB::writeNodeFile()." << std::endl;
return (1);
}

osg::notify(osg::ALWAYS) << "Successfully wrote \"" << out << "\". Execute \"osgviewer " << out << "\" to view." << endl;

osgViewer::Viewer viewer;
auto node = osgDB::readNodeFile("lozenge.osg");
osgUtil::Optimizer opt;
opt.optimize(node);
//node->setUseDisplayList(false);
auto geom = node->asGeometry();
//geom->setUseVertexArrayObject(true);



viewer.setSceneData(node);

return viewer.run();
}

使用window PowerShell 运行osgviewer.exe lozenge.osg
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;提高帧率_osg背面剔除_02
当达到400多万个顶点,帧率只有不到30帧,这还是使用了osg::CullFace,如果不用背面剔除,帧率变下降到原来的五分之一左右,大概6帧的样子
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;提高帧率_osg背面剔除_03

osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;提高帧率_osg背面剔除_04

工程源码

工程源码下载地址