现在看下cookbook中的lod示例。
那么
一,lod和pagedlod有什么异同呢?
1,只考虑按视点远近进行判断。
Pagedlod是根据视点远近按需加载或者卸载场景的文件。
lod把场景中的精模简模都加载进来,按视点远近显隐。
lod->setCenter(center);
lod->setRange(0, radius * 5.0f, FLT_MAX);
lod->setRange(1, 0.0f, radius * 5.0f);
level->insertChild(0, createBoxForDebug(total._max, total._min));
level->insertChild(1, group.get());
根据远处是简模,近处是精模,可以知道,盒子是简模,一系列group是精模
2,每级的group节点组成相同
(1)叶子节点
for (unsigned int i = 0; i < childData.size(); i++)
{
const ElementInfo& obj = childData[i];
osg::Vec3 center = (obj.second._max + obj.second._min) * 0.5;
float radius = (obj.second._max - obj.second._min).length() * 0.5f;
group->addChild(createElement(obj.first, center, radius));
}
(2)lod节点(或者PagedLod)
(3)lod节点(或者PagedLod)及叶子节点的混合
childNodes[id] = build(depth + 1, osg::BoundingBox(min, max), childData);
for (unsigned int i = 0; i < 8; i++)
{
if (childNodes[i] && childNodes[i]->getNumChildren())
{
group->addChild(childNodes[i]);
}
}
而build函数返回的是lod节点
osg::LOD* level = createNewLevel(depth, center, radius);
level->insertChild(0, createBoxForDebug(total._max, total._min));
level->insertChild(1, group.get());
return level;
二,八叉树是什么呢?
我个人理解是将整个包围盒所在的元素,按照空间划分下去,直到叶子节点。xyz的维度是2X2X2(八叉树)
当然,也可以是其他任何一种维度相乘的空间划分,不一定是八叉树。比如四叉树。
那么什么时候才能到叶子节点呢?也就是递归结束呢?
答案是,该空间元素足够少,或者层级足够深
if ((int) childData.size()<= _maxChildNumber|| depth > _maxTreeDepth)
{
isLeafNode = true;
}
运行结果如下:




代码如下:
common.h
#pragma once
#include
#include <osg/Vec3>
#include <osg/PolygonMode>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/PrintVisitor>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Viewer>
#include
#include
#include
float randomValue(float minValue, float maxValue);
osg::Vec3 randomVector(float minValue, float maxValue);
common.cpp
#include "common.h"
float randomValue(float minValue, float maxValue)
{
return minValue + (float)rand() / (RAND_MAX + 1.0f) * (maxValue - minValue);
}
osg::Vec3 randomVector(float minValue, float maxValue)
{
return osg::Vec3(
randomValue(minValue, maxValue),
randomValue(minValue, maxValue),
randomValue(minValue, maxValue));
}
OctreeBuilder.h
#pragma once
#include "common.h"
class OctreeBuilder
{
protected:
osg::LOD* createNewLevel(int level, const osg::Vec3& center, float radius);
osg::Node* createElement(const std::string& od, const osg::Vec3& center, float radius);
osg::Geode* createBoxForDebug(const osg::Vec3& maxValue, const osg::Vec3& minValue);
int _maxChildNumber;
int _maxTreeDepth;
int _maxLevel;
public:
OctreeBuilder()
{
_maxChildNumber = 16;
_maxTreeDepth = 32;
_maxLevel = 0;
}
int getMaxLevel() const
{
return _maxLevel;
}
void setMaxChildNumber(int maxValue)
{
_maxChildNumber = maxValue;
}
int getMaxChildNumber()
{
return _maxChildNumber;
}
void setMaxTreeDepth(int maxValue)
{
_maxTreeDepth = maxValue;
}
int getMaxTreeDepth() const
{
return _maxTreeDepth;
}
typedef std::pair<std::string, osg::BoundingBox> ElementInfo;
osg::Group* build(int depth, const osg::BoundingBox& total, std::vector& elements);
};
OctreeBuilder.cpp
#include "OctreeBuilder.h"
osg::LOD* OctreeBuilder::createNewLevel(int level, const osg::Vec3& center, float radius)
{
osg::ref_ptrosg::LOD lod = new osg::LOD;
lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER);
lod->setCenter(center);
lod->setRadius(radius);
lod->setRange(0, radius * 5.0f, FLT_MAX);
lod->setRange(1, 0.0f, radius * 5.0f);
if (_maxLevel < level)
{
_maxLevel = level;
}
return lod.release();
}
osg::Node* OctreeBuilder::createElement(const std::string& id, const osg::Vec3& center, float radius)
{
osg::ref_ptrosg::Geode geode = new osg::Geode;
geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(center, radius)));
geode->setName(id);
return geode.release();
}
osg::Geode* OctreeBuilder::createBoxForDebug(const osg::Vec3& maxValue, const osg::Vec3& minValue)
{
osg::ref_ptrosg::Geode geode = new osg::Geode;
osg::Vec3 center = (maxValue + minValue) / 2.0;
float width = (maxValue - minValue).length() * 0.5;
//float width = 100;
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(center, width)));
return geode.release();
}
osg::Group* OctreeBuilder::build(int depth, const osg::BoundingBox& total, std::vector& elements)
{
int s[3];
osg::Vec3 extentSet[3] =
{
total._min,
(total._max + total._min) * 0.5f,
total._max
};
std::vector childData;
for (unsigned int i = 0; i < elements.size(); i++)
{
const ElementInfo& obj = elements[i];
if (total.contains(obj.second._min) && total.contains(obj.second._max))
{
childData.push_back(obj);
}
else if (total.intersects(obj.second))
{
osg::Vec3 center = (obj.second._max + obj.second._min) * 0.5f;
if (total.contains(center))
{
childData.push_back(obj);
}
}
}
bool isLeafNode = false;
if ((int) childData.size()<= _maxChildNumber|| depth > _maxTreeDepth)
{
isLeafNode = true;
}
osg::ref_ptr<osg::Group> group = new osg::Group;
if (!isLeafNode)
{
osg::ref_ptr<osg::Group> childNodes[8];
for (s[0] = 0; s[0] < 2; s[0]++ )
{
for (s[1] = 0; s[1] < 2; s[1]++)
{
for (s[2] = 0; s[2] < 2; s[2]++)
{
osg::Vec3 min, max;
for (int a = 0; a < 3; a++)
{
min[a] = (extentSet[s[a] + 0])[a];
max[a] = (extentSet[s[a] + 1])[a];
}
int id = s[0] + (2 * s[1]) + 4 * s[2];
childNodes[id] = build(depth + 1, osg::BoundingBox(min, max), childData);
}
}
}
for (unsigned int i = 0; i < 8; i++)
{
if (childNodes[i] && childNodes[i]->getNumChildren())
{
group->addChild(childNodes[i]);
}
}
}
else
{
for (unsigned int i = 0; i < childData.size(); i++)
{
const ElementInfo& obj = childData[i];
osg::Vec3 center = (obj.second._max + obj.second._min) * 0.5;
float radius = (obj.second._max - obj.second._min).length() * 0.5f;
group->addChild(createElement(obj.first, center, radius));
}
}
osg::Vec3 center = (total._max + total._min) * 0.5;
float radius = (total._max - total._min).length() * 0.5f;
osg::LOD* level = createNewLevel(depth, center, radius);
level->insertChild(0, createBoxForDebug(total._max, total._min));
level->insertChild(1, group.get());
return level;
}
main.cpp
#include "OctreeBuilder.h"
int main()
{
osg::BoundingBox globalBound;
std::vectorOctreeBuilder::ElementInfo globalElements;
for (unsigned int i = 0; i < 5000; i++)
{
osg::Vec3 pos = randomVector(-500.0f, 500.0f);
float radius = randomValue(0.2f, 0.5f);
osg::Vec3 minValue = pos - osg::Vec3(radius, radius, radius);
osg::Vec3 maxValue = pos + osg::Vec3(radius, radius, radius);
osg::BoundingBox region(minValue, maxValue);
globalBound.expandBy(region);
std::string str = "Ball-" + std::to_string(i);
globalElements.push_back(OctreeBuilder::ElementInfo(str, region));
}
OctreeBuilder octree;
osg::ref_ptrosg::Group root = octree.build(0, globalBound, globalElements);
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
viewer->setSceneData(root);
return viewer->run();
}