PagedLOD for random trees, buildings and objects.
This commit is contained in:
parent
3ec9c7ae6e
commit
5bc535a8d2
@ -110,10 +110,10 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
|||||||
// Set up the building set based on the material definitions
|
// Set up the building set based on the material definitions
|
||||||
SGBuildingBin::SGBuildingBin(const SGMaterial *mat) {
|
SGBuildingBin::SGBuildingBin(const SGMaterial *mat) {
|
||||||
|
|
||||||
material_name = mat->get_names()[0];
|
material_name = new std::string(mat->get_names()[0]);
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Building material " << material_name);
|
SG_LOG(SG_TERRAIN, SG_DEBUG, "Building material " << material_name);
|
||||||
texture = mat->get_building_texture();
|
texture = new std::string(mat->get_building_texture());
|
||||||
lightMap = mat->get_building_lightmap();
|
lightMap = new std::string(mat->get_building_lightmap());
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Building texture " << texture);
|
SG_LOG(SG_TERRAIN, SG_DEBUG, "Building texture " << texture);
|
||||||
|
|
||||||
// Generate a random seed for the building generation.
|
// Generate a random seed for the building generation.
|
||||||
@ -721,7 +721,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
|||||||
ref_ptr<Group> SGBuildingBin::createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options)
|
ref_ptr<Group> SGBuildingBin::createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options)
|
||||||
{
|
{
|
||||||
ref_ptr<Effect> effect;
|
ref_ptr<Effect> effect;
|
||||||
EffectMap::iterator iter = buildingEffectMap.find(texture);
|
EffectMap::iterator iter = buildingEffectMap.find(*texture);
|
||||||
|
|
||||||
if ((iter == buildingEffectMap.end())||
|
if ((iter == buildingEffectMap.end())||
|
||||||
(!iter->second.lock(effect)))
|
(!iter->second.lock(effect)))
|
||||||
@ -731,15 +731,15 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
|||||||
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
||||||
// Main texture - n=0
|
// Main texture - n=0
|
||||||
params->getChild("texture", 0, true)->getChild("image", 0, true)
|
params->getChild("texture", 0, true)->getChild("image", 0, true)
|
||||||
->setStringValue(texture);
|
->setStringValue(*texture);
|
||||||
|
|
||||||
// Light map - n=3
|
// Light map - n=3
|
||||||
params->getChild("texture", 3, true)->getChild("image", 0, true)
|
params->getChild("texture", 3, true)->getChild("image", 0, true)
|
||||||
->setStringValue(lightMap);
|
->setStringValue(*lightMap);
|
||||||
|
|
||||||
effect = makeEffect(effectProp, true, options);
|
effect = makeEffect(effectProp, true, options);
|
||||||
if (iter == buildingEffectMap.end())
|
if (iter == buildingEffectMap.end())
|
||||||
buildingEffectMap.insert(EffectMap::value_type(texture, effect));
|
buildingEffectMap.insert(EffectMap::value_type(*texture, effect));
|
||||||
else
|
else
|
||||||
iter->second = effect; // update existing, but empty observer
|
iter->second = effect; // update existing, but empty observer
|
||||||
}
|
}
|
||||||
@ -819,27 +819,28 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
|||||||
// This actually returns a MatrixTransform node. If we rotate the whole
|
// This actually returns a MatrixTransform node. If we rotate the whole
|
||||||
// forest into the local Z-up coordinate system we can reuse the
|
// forest into the local Z-up coordinate system we can reuse the
|
||||||
// primitive building geometry for all the forests of the same type.
|
// primitive building geometry for all the forests of the same type.
|
||||||
osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform,
|
osg::Group* createRandomBuildings(SGBuildingBinList& buildings, const osg::Matrix& transform,
|
||||||
const SGReaderWriterOptions* options)
|
const SGReaderWriterOptions* options)
|
||||||
{
|
{
|
||||||
Matrix transInv = Matrix::inverse(transform);
|
Matrix transInv = Matrix::inverse(transform);
|
||||||
static Matrix ident;
|
static Matrix ident;
|
||||||
// Set up some shared structures.
|
// Set up some shared structures.
|
||||||
MatrixTransform* mt = new MatrixTransform(transform);
|
MatrixTransform* mt = new MatrixTransform(transform);
|
||||||
|
SGBuildingBinList::iterator i;
|
||||||
|
|
||||||
SGBuildingBin* bin = NULL;
|
for (i = buildings.begin(); i != buildings.end(); ++i) {
|
||||||
|
SGBuildingBin* bin = *i;
|
||||||
BOOST_FOREACH(bin, buildings)
|
|
||||||
{
|
|
||||||
ref_ptr<Group> group = bin->createBuildingsGroup(transInv, options);
|
ref_ptr<Group> group = bin->createBuildingsGroup(transInv, options);
|
||||||
|
|
||||||
for (size_t i = 0; i < group->getNumChildren(); ++i)
|
for (size_t j = 0; j < group->getNumChildren(); ++j) {
|
||||||
mt->addChild(group->getChild(i));
|
mt->addChild(group->getChild(j));
|
||||||
|
}
|
||||||
|
|
||||||
delete bin;
|
delete bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildings.clear();
|
buildings.clear();
|
||||||
|
|
||||||
QuadTreeCleaner cleaner;
|
QuadTreeCleaner cleaner;
|
||||||
mt->accept(cleaner);
|
mt->accept(cleaner);
|
||||||
return mt;
|
return mt;
|
||||||
|
@ -100,9 +100,9 @@ private:
|
|||||||
BuildingList mediumBuildings;
|
BuildingList mediumBuildings;
|
||||||
BuildingList largeBuildings;
|
BuildingList largeBuildings;
|
||||||
|
|
||||||
std::string material_name;
|
std::string* material_name;
|
||||||
std::string texture;
|
std::string* texture;
|
||||||
std::string lightMap;
|
std::string* lightMap;
|
||||||
|
|
||||||
// Fraction of buildings of this type
|
// Fraction of buildings of this type
|
||||||
float smallBuildingFraction;
|
float smallBuildingFraction;
|
||||||
@ -184,7 +184,7 @@ public:
|
|||||||
|
|
||||||
bool checkMinDist (SGVec3f p, float radius);
|
bool checkMinDist (SGVec3f p, float radius);
|
||||||
|
|
||||||
std::string getMaterialName() { return material_name; }
|
std::string* getMaterialName() { return material_name; }
|
||||||
|
|
||||||
BuildingType getBuildingType(float roll);
|
BuildingType getBuildingType(float roll);
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ public:
|
|||||||
typedef std::list<SGBuildingBin*> SGBuildingBinList;
|
typedef std::list<SGBuildingBin*> SGBuildingBinList;
|
||||||
|
|
||||||
|
|
||||||
osg::Group* createRandomBuildings(SGBuildingBinList buildinglist, const osg::Matrix& transform,
|
osg::Group* createRandomBuildings(SGBuildingBinList& buildinglist, const osg::Matrix& transform,
|
||||||
const SGReaderWriterOptions* options);
|
const SGReaderWriterOptions* options);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <osg/LOD>
|
#include <osg/LOD>
|
||||||
#include <osg/MatrixTransform>
|
#include <osg/MatrixTransform>
|
||||||
#include <osg/Point>
|
#include <osg/Point>
|
||||||
|
#include <osg/Referenced>
|
||||||
#include <osg/StateSet>
|
#include <osg/StateSet>
|
||||||
#include <osg/Switch>
|
#include <osg/Switch>
|
||||||
|
|
||||||
@ -59,6 +60,7 @@
|
|||||||
#include <simgear/scene/util/SGNodeMasks.hxx>
|
#include <simgear/scene/util/SGNodeMasks.hxx>
|
||||||
#include <simgear/scene/util/QuadTreeBuilder.hxx>
|
#include <simgear/scene/util/QuadTreeBuilder.hxx>
|
||||||
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||||
|
#include <simgear/scene/util/OptionsReadFileCallback.hxx>
|
||||||
|
|
||||||
#include "SGTexturedTriangleBin.hxx"
|
#include "SGTexturedTriangleBin.hxx"
|
||||||
#include "SGLightBin.hxx"
|
#include "SGLightBin.hxx"
|
||||||
@ -77,7 +79,8 @@ typedef std::map<std::string,SGTexturedTriangleBin> SGMaterialTriangleMap;
|
|||||||
typedef std::list<SGLightBin> SGLightListBin;
|
typedef std::list<SGLightBin> SGLightListBin;
|
||||||
typedef std::list<SGDirectionalLightBin> SGDirectionalLightListBin;
|
typedef std::list<SGDirectionalLightBin> SGDirectionalLightListBin;
|
||||||
|
|
||||||
struct SGTileGeometryBin {
|
class SGTileGeometryBin : public osg::Referenced {
|
||||||
|
public:
|
||||||
SGMaterialTriangleMap materialTriangleMap;
|
SGMaterialTriangleMap materialTriangleMap;
|
||||||
SGLightBin tileLights;
|
SGLightBin tileLights;
|
||||||
SGLightBin randomTileLights;
|
SGLightBin randomTileLights;
|
||||||
@ -486,28 +489,25 @@ struct SGTileGeometryBin {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
osg::Texture2D* object_mask = mat->get_object_mask(triangleBin);
|
osg::Texture2D* object_mask = mat->get_object_mask(triangleBin);
|
||||||
|
osg::Image* img;
|
||||||
|
if (object_mask != NULL) {
|
||||||
|
img = object_mask->getImage();
|
||||||
|
}
|
||||||
|
|
||||||
int group_count = mat->get_object_group_count();
|
int group_count = mat->get_object_group_count();
|
||||||
float building_coverage = mat->get_building_coverage();
|
float building_coverage = mat->get_building_coverage();
|
||||||
float cos_zero_density_angle = mat->get_cos_object_zero_density_slope_angle();
|
float cos_zero_density_angle = mat->get_cos_object_zero_density_slope_angle();
|
||||||
float cos_max_density_angle = mat->get_cos_object_max_density_slope_angle();
|
float cos_max_density_angle = mat->get_cos_object_max_density_slope_angle();
|
||||||
|
|
||||||
bool found = false;
|
if (building_coverage == 0)
|
||||||
SGBuildingBin* bin = NULL;
|
continue;
|
||||||
|
|
||||||
|
SGBuildingBin* bin;
|
||||||
|
|
||||||
if (building_coverage > 0) {
|
if (building_coverage > 0) {
|
||||||
BOOST_FOREACH(bin, randomBuildings)
|
|
||||||
{
|
|
||||||
if (bin->getMaterialName() == mat->get_names()[0]) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
bin = new SGBuildingBin(mat);
|
bin = new SGBuildingBin(mat);
|
||||||
randomBuildings.push_back(bin);
|
randomBuildings.push_back(bin);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsigned num = i->second.getNumTriangles();
|
unsigned num = i->second.getNumTriangles();
|
||||||
int random_dropped = 0;
|
int random_dropped = 0;
|
||||||
@ -638,8 +638,6 @@ struct SGTileGeometryBin {
|
|||||||
(int)object->get_randomized_range_m(&seed),
|
(int)object->get_randomized_range_m(&seed),
|
||||||
rotation);
|
rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
n -= 1.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -678,6 +676,7 @@ struct SGTileGeometryBin {
|
|||||||
|
|
||||||
// Place an object each unit of area
|
// Place an object each unit of area
|
||||||
while (num > 1.0) {
|
while (num > 1.0) {
|
||||||
|
num -= 1.0;
|
||||||
|
|
||||||
// Set the next location to place a building
|
// Set the next location to place a building
|
||||||
a += stepv0;
|
a += stepv0;
|
||||||
@ -721,7 +720,6 @@ struct SGTileGeometryBin {
|
|||||||
} else {
|
} else {
|
||||||
// Fails mask test - try again.
|
// Fails mask test - try again.
|
||||||
mask_dropped++;
|
mask_dropped++;
|
||||||
num -= 1.0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -744,7 +742,6 @@ struct SGTileGeometryBin {
|
|||||||
float edge_dist = *std::min_element(edges, edges + 3);
|
float edge_dist = *std::min_element(edges, edges + 3);
|
||||||
|
|
||||||
if (edge_dist < radius) {
|
if (edge_dist < radius) {
|
||||||
num -= 1.0;
|
|
||||||
triangle_dropped++;
|
triangle_dropped++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -762,7 +759,6 @@ struct SGTileGeometryBin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (close) {
|
if (close) {
|
||||||
num -= 1.0;
|
|
||||||
building_dropped++;
|
building_dropped++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -776,7 +772,6 @@ struct SGTileGeometryBin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (close) {
|
if (close) {
|
||||||
num -= 1.0;
|
|
||||||
random_dropped++;
|
random_dropped++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -784,7 +779,6 @@ struct SGTileGeometryBin {
|
|||||||
std::pair<SGVec3f, float> pt = std::make_pair(buildingCenter, radius);
|
std::pair<SGVec3f, float> pt = std::make_pair(buildingCenter, radius);
|
||||||
triangleBuildingList.push_back(pt);
|
triangleBuildingList.push_back(pt);
|
||||||
bin->insert(randomPoint, rotation, buildingtype);
|
bin->insert(randomPoint, rotation, buildingtype);
|
||||||
num -= 1.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -892,22 +886,184 @@ struct GetModelLODCoord {
|
|||||||
typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
|
typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
|
||||||
GetModelLODCoord> RandomObjectsQuadtree;
|
GetModelLODCoord> RandomObjectsQuadtree;
|
||||||
|
|
||||||
osg::Node*
|
class RandomObjectCallback : public OptionsReadFileCallback {
|
||||||
SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options)
|
public:
|
||||||
{
|
virtual osgDB::ReaderWriter::ReadResult
|
||||||
SGBinObject tile;
|
readNode(const std::string&, const osgDB::Options*)
|
||||||
if (!tile.read_bin(path))
|
{
|
||||||
return NULL;
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||||
|
group->setName("Random Object and Lighting Group");
|
||||||
|
group->setDataVariance(osg::Object::STATIC);
|
||||||
|
|
||||||
SGMaterialLib* matlib = 0;
|
osg::LOD* lightLOD = generateLightingTileObjects();
|
||||||
|
if (lightLOD)
|
||||||
|
group->addChild(lightLOD);
|
||||||
|
|
||||||
|
osg::LOD* objectLOD = generateRandomTileObjects();
|
||||||
|
if (objectLOD)
|
||||||
|
group->addChild(objectLOD);
|
||||||
|
|
||||||
|
return group.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate all the lighting objects for the tile.
|
||||||
|
osg::LOD* generateLightingTileObjects()
|
||||||
|
{
|
||||||
|
SGMaterialLib* matlib;
|
||||||
|
|
||||||
|
if (_options)
|
||||||
|
matlib = _options->getMaterialLib();
|
||||||
|
|
||||||
|
// FIXME: ugly, has a side effect
|
||||||
|
if (matlib)
|
||||||
|
_tileGeometryBin->computeRandomSurfaceLights(matlib);
|
||||||
|
|
||||||
|
GroundLightManager* lightManager = GroundLightManager::instance();
|
||||||
|
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
|
||||||
|
SGVec3f up(0, 0, 1);
|
||||||
|
|
||||||
|
if (_tileGeometryBin->tileLights.getNumLights() > 0
|
||||||
|
|| _tileGeometryBin->randomTileLights.getNumLights() > 0) {
|
||||||
|
osg::Group* groundLights0 = new osg::Group;
|
||||||
|
groundLights0->setStateSet(lightManager->getGroundLightStateSet());
|
||||||
|
groundLights0->setNodeMask(GROUNDLIGHTS0_BIT);
|
||||||
|
osg::Geode* geode = new osg::Geode;
|
||||||
|
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->tileLights));
|
||||||
|
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights, 4, -0.3f));
|
||||||
|
groundLights0->addChild(geode);
|
||||||
|
lightGroup->addChild(groundLights0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_tileGeometryBin->randomTileLights.getNumLights() > 0) {
|
||||||
|
osg::Group* groundLights1 = new osg::Group;
|
||||||
|
groundLights1->setStateSet(lightManager->getGroundLightStateSet());
|
||||||
|
groundLights1->setNodeMask(GROUNDLIGHTS1_BIT);
|
||||||
|
osg::Group* groundLights2 = new osg::Group;
|
||||||
|
groundLights2->setStateSet(lightManager->getGroundLightStateSet());
|
||||||
|
groundLights2->setNodeMask(GROUNDLIGHTS2_BIT);
|
||||||
|
osg::Geode* geode = new osg::Geode;
|
||||||
|
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights, 2, -0.15f));
|
||||||
|
groundLights1->addChild(geode);
|
||||||
|
lightGroup->addChild(groundLights1);
|
||||||
|
geode = new osg::Geode;
|
||||||
|
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights));
|
||||||
|
groundLights2->addChild(geode);
|
||||||
|
lightGroup->addChild(groundLights2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_tileGeometryBin->vasiLights.empty()) {
|
||||||
|
EffectGeode* vasiGeode = new EffectGeode;
|
||||||
|
Effect* vasiEffect
|
||||||
|
= getLightEffect(24, osg::Vec3(1, 0.0001, 0.000001), 1, 24, true);
|
||||||
|
vasiGeode->setEffect(vasiEffect);
|
||||||
|
SGVec4f red(1, 0, 0, 1);
|
||||||
|
SGMaterial* mat = 0;
|
||||||
|
if (matlib)
|
||||||
|
mat = matlib->find("RWY_RED_LIGHTS");
|
||||||
|
if (mat)
|
||||||
|
red = mat->get_light_color();
|
||||||
|
SGVec4f white(1, 1, 1, 1);
|
||||||
|
mat = 0;
|
||||||
|
if (matlib)
|
||||||
|
mat = matlib->find("RWY_WHITE_LIGHTS");
|
||||||
|
if (mat)
|
||||||
|
white = mat->get_light_color();
|
||||||
|
SGDirectionalLightListBin::const_iterator i;
|
||||||
|
for (i = _tileGeometryBin->vasiLights.begin();
|
||||||
|
i != _tileGeometryBin->vasiLights.end(); ++i) {
|
||||||
|
vasiGeode->addDrawable(SGLightFactory::getVasi(up, *i, red, white));
|
||||||
|
}
|
||||||
|
vasiGeode->setStateSet(lightManager->getRunwayLightStateSet());
|
||||||
|
lightGroup->addChild(vasiGeode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Effect* runwayEffect = 0;
|
||||||
|
if (_tileGeometryBin->runwayLights.getNumLights() > 0
|
||||||
|
|| !_tileGeometryBin->rabitLights.empty()
|
||||||
|
|| !_tileGeometryBin->reilLights.empty()
|
||||||
|
|| !_tileGeometryBin->odalLights.empty()
|
||||||
|
|| _tileGeometryBin->taxiLights.getNumLights() > 0)
|
||||||
|
runwayEffect = getLightEffect(16, osg::Vec3(1, 0.001, 0.0002), 1, 16, true);
|
||||||
|
if (_tileGeometryBin->runwayLights.getNumLights() > 0
|
||||||
|
|| !_tileGeometryBin->rabitLights.empty()
|
||||||
|
|| !_tileGeometryBin->reilLights.empty()
|
||||||
|
|| !_tileGeometryBin->odalLights.empty()
|
||||||
|
|| !_tileGeometryBin->holdshortLights.empty()
|
||||||
|
|| !_tileGeometryBin->guardLights.empty()) {
|
||||||
|
osg::Group* rwyLights = new osg::Group;
|
||||||
|
rwyLights->setStateSet(lightManager->getRunwayLightStateSet());
|
||||||
|
rwyLights->setNodeMask(RUNWAYLIGHTS_BIT);
|
||||||
|
if (_tileGeometryBin->runwayLights.getNumLights() != 0) {
|
||||||
|
EffectGeode* geode = new EffectGeode;
|
||||||
|
geode->setEffect(runwayEffect);
|
||||||
|
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->runwayLights));
|
||||||
|
rwyLights->addChild(geode);
|
||||||
|
}
|
||||||
|
SGDirectionalLightListBin::const_iterator i;
|
||||||
|
for (i = _tileGeometryBin->rabitLights.begin();
|
||||||
|
i != _tileGeometryBin->rabitLights.end(); ++i) {
|
||||||
|
rwyLights->addChild(SGLightFactory::getSequenced(*i));
|
||||||
|
}
|
||||||
|
for (i = _tileGeometryBin->reilLights.begin();
|
||||||
|
i != _tileGeometryBin->reilLights.end(); ++i) {
|
||||||
|
rwyLights->addChild(SGLightFactory::getSequenced(*i));
|
||||||
|
}
|
||||||
|
for (i = _tileGeometryBin->holdshortLights.begin();
|
||||||
|
i != _tileGeometryBin->holdshortLights.end(); ++i) {
|
||||||
|
rwyLights->addChild(SGLightFactory::getHoldShort(*i));
|
||||||
|
}
|
||||||
|
for (i = _tileGeometryBin->guardLights.begin();
|
||||||
|
i != _tileGeometryBin->guardLights.end(); ++i) {
|
||||||
|
rwyLights->addChild(SGLightFactory::getGuard(*i));
|
||||||
|
}
|
||||||
|
SGLightListBin::const_iterator j;
|
||||||
|
for (j = _tileGeometryBin->odalLights.begin();
|
||||||
|
j != _tileGeometryBin->odalLights.end(); ++j) {
|
||||||
|
rwyLights->addChild(SGLightFactory::getOdal(*j));
|
||||||
|
}
|
||||||
|
lightGroup->addChild(rwyLights);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_tileGeometryBin->taxiLights.getNumLights() > 0) {
|
||||||
|
osg::Group* taxiLights = new osg::Group;
|
||||||
|
taxiLights->setStateSet(lightManager->getTaxiLightStateSet());
|
||||||
|
taxiLights->setNodeMask(RUNWAYLIGHTS_BIT);
|
||||||
|
EffectGeode* geode = new EffectGeode;
|
||||||
|
geode->setEffect(runwayEffect);
|
||||||
|
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->taxiLights));
|
||||||
|
taxiLights->addChild(geode);
|
||||||
|
lightGroup->addChild(taxiLights);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::LOD* lightLOD = NULL;
|
||||||
|
|
||||||
|
if (lightGroup->getNumChildren() > 0) {
|
||||||
|
lightLOD = new osg::LOD;
|
||||||
|
lightLOD->addChild(lightGroup.get(), 0, 60000);
|
||||||
|
// VASI is always on, so doesn't use light bits.
|
||||||
|
lightLOD->setNodeMask(LIGHTS_BITS | MODEL_BIT | PERMANENTLIGHT_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lightLOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate all the random forest, objects and buildings for the tile
|
||||||
|
osg::LOD* generateRandomTileObjects()
|
||||||
|
{
|
||||||
|
SGMaterialLib* matlib;
|
||||||
bool use_random_objects = false;
|
bool use_random_objects = false;
|
||||||
bool use_random_vegetation = false;
|
bool use_random_vegetation = false;
|
||||||
bool use_random_buildings = false;
|
bool use_random_buildings = false;
|
||||||
float vegetation_density = 1.0f;
|
float vegetation_density = 1.0f;
|
||||||
float building_density = 1.0f;
|
float building_density = 1.0f;
|
||||||
if (options) {
|
|
||||||
matlib = options->getMaterialLib();
|
osg::ref_ptr<osg::Group> randomObjects;
|
||||||
SGPropertyNode* propertyNode = options->getPropertyNode().get();
|
osg::ref_ptr<osg::Group> forestNode;
|
||||||
|
osg::ref_ptr<osg::Group> buildingNode;
|
||||||
|
|
||||||
|
if (_options) {
|
||||||
|
matlib = _options->getMaterialLib();
|
||||||
|
SGPropertyNode* propertyNode = _options->getPropertyNode().get();
|
||||||
if (propertyNode) {
|
if (propertyNode) {
|
||||||
use_random_objects
|
use_random_objects
|
||||||
= propertyNode->getBoolValue("/sim/rendering/random-objects",
|
= propertyNode->getBoolValue("/sim/rendering/random-objects",
|
||||||
@ -927,60 +1083,28 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SGVec3d center = tile.get_gbs_center();
|
|
||||||
SGGeod geodPos = SGGeod::fromCart(center);
|
|
||||||
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
|
|
||||||
|
|
||||||
// rotate the tiles so that the bounding boxes get nearly axis aligned.
|
|
||||||
// this will help the collision tree's bounding boxes a bit ...
|
|
||||||
std::vector<SGVec3d> nodes = tile.get_wgs84_nodes();
|
|
||||||
for (unsigned i = 0; i < nodes.size(); ++i)
|
|
||||||
nodes[i] = hlOr.transform(nodes[i]);
|
|
||||||
tile.set_wgs84_nodes(nodes);
|
|
||||||
|
|
||||||
SGQuatf hlOrf(hlOr[0], hlOr[1], hlOr[2], hlOr[3]);
|
|
||||||
std::vector<SGVec3f> normals = tile.get_normals();
|
|
||||||
for (unsigned i = 0; i < normals.size(); ++i)
|
|
||||||
normals[i] = hlOrf.transform(normals[i]);
|
|
||||||
tile.set_normals(normals);
|
|
||||||
|
|
||||||
SGTileGeometryBin tileGeometryBin;
|
|
||||||
if (!tileGeometryBin.insertBinObj(tile, matlib))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
SGVec3f up(0, 0, 1);
|
|
||||||
GroundLightManager* lightManager = GroundLightManager::instance();
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
|
|
||||||
osg::ref_ptr<osg::Group> randomObjects;
|
|
||||||
osg::ref_ptr<osg::Group> forestNode;
|
|
||||||
osg::ref_ptr<osg::Group> buildingNode;
|
|
||||||
osg::Group* terrainGroup = new osg::Group;
|
|
||||||
terrainGroup->setName("BTGTerrainGroup");
|
|
||||||
|
|
||||||
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
|
|
||||||
if (node)
|
|
||||||
terrainGroup->addChild(node);
|
|
||||||
|
|
||||||
if (matlib && (use_random_objects || use_random_buildings)) {
|
if (matlib && (use_random_objects || use_random_buildings)) {
|
||||||
tileGeometryBin.computeRandomObjectsAndBuildings(matlib,
|
_tileGeometryBin->computeRandomObjectsAndBuildings(matlib,
|
||||||
building_density,
|
building_density,
|
||||||
use_random_objects,
|
use_random_objects,
|
||||||
use_random_buildings);
|
use_random_buildings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tileGeometryBin.randomModels.getNumModels() > 0) {
|
|
||||||
|
if (_tileGeometryBin->randomModels.getNumModels() > 0) {
|
||||||
// Generate a repeatable random seed
|
// Generate a repeatable random seed
|
||||||
mt seed;
|
mt seed;
|
||||||
mt_init(&seed, unsigned(123));
|
mt_init(&seed, unsigned(123));
|
||||||
|
|
||||||
std::vector<ModelLOD> models;
|
std::vector<ModelLOD> models;
|
||||||
for (unsigned int i = 0;
|
for (unsigned int i = 0;
|
||||||
i < tileGeometryBin.randomModels.getNumModels(); i++) {
|
i < _tileGeometryBin->randomModels.getNumModels(); i++) {
|
||||||
SGMatModelBin::MatModel obj
|
SGMatModelBin::MatModel obj
|
||||||
= tileGeometryBin.randomModels.getMatModel(i);
|
= _tileGeometryBin->randomModels.getMatModel(i);
|
||||||
|
|
||||||
SGPropertyNode* root = options->getPropertyNode()->getRootNode();
|
SGPropertyNode* root = _options->getPropertyNode()->getRootNode();
|
||||||
osg::Node* node = obj.model->get_random_model(root, &seed);
|
osg::Node* node = obj.model->get_random_model(root, &seed);
|
||||||
|
|
||||||
// Create a matrix to place the object in the correct
|
// Create a matrix to place the object in the correct
|
||||||
@ -1005,7 +1129,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
|
|
||||||
osg::MatrixTransform* position =
|
osg::MatrixTransform* position =
|
||||||
new osg::MatrixTransform(transformMat);
|
new osg::MatrixTransform(transformMat);
|
||||||
position->setName("positionRandomeModel");
|
position->setName("positionRandomModel");
|
||||||
position->addChild(node);
|
position->addChild(node);
|
||||||
models.push_back(ModelLOD(position, obj.lod));
|
models.push_back(ModelLOD(position, obj.lod));
|
||||||
}
|
}
|
||||||
@ -1015,160 +1139,28 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
randomObjects->setName("Random objects");
|
randomObjects->setName("Random objects");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! tileGeometryBin.randomBuildings.empty()) {
|
if (! _tileGeometryBin->randomBuildings.empty()) {
|
||||||
buildingNode = createRandomBuildings(tileGeometryBin.randomBuildings, osg::Matrix::identity(),
|
buildingNode = createRandomBuildings(_tileGeometryBin->randomBuildings, osg::Matrix::identity(),
|
||||||
options);
|
_options);
|
||||||
buildingNode->setName("Random buildings");
|
buildingNode->setName("Random buildings");
|
||||||
|
_tileGeometryBin->randomBuildings.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_random_vegetation && matlib) {
|
if (use_random_vegetation && matlib) {
|
||||||
// Now add some random forest.
|
// Now add some random forest.
|
||||||
tileGeometryBin.computeRandomForest(matlib, vegetation_density);
|
_tileGeometryBin->computeRandomForest(matlib, vegetation_density);
|
||||||
|
|
||||||
if (! tileGeometryBin.randomForest.empty()) {
|
if (! _tileGeometryBin->randomForest.empty()) {
|
||||||
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity(),
|
forestNode = createForest(_tileGeometryBin->randomForest, osg::Matrix::identity(),
|
||||||
options);
|
_options);
|
||||||
forestNode->setName("Random trees");
|
forestNode->setName("Random trees");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: ugly, has a side effect
|
osg::LOD* objectLOD = NULL;
|
||||||
if (matlib)
|
|
||||||
tileGeometryBin.computeRandomSurfaceLights(matlib);
|
|
||||||
|
|
||||||
if (tileGeometryBin.tileLights.getNumLights() > 0
|
|
||||||
|| tileGeometryBin.randomTileLights.getNumLights() > 0) {
|
|
||||||
osg::Group* groundLights0 = new osg::Group;
|
|
||||||
groundLights0->setStateSet(lightManager->getGroundLightStateSet());
|
|
||||||
groundLights0->setNodeMask(GROUNDLIGHTS0_BIT);
|
|
||||||
osg::Geode* geode = new osg::Geode;
|
|
||||||
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.tileLights));
|
|
||||||
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 4, -0.3f));
|
|
||||||
groundLights0->addChild(geode);
|
|
||||||
lightGroup->addChild(groundLights0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tileGeometryBin.randomTileLights.getNumLights() > 0) {
|
|
||||||
osg::Group* groundLights1 = new osg::Group;
|
|
||||||
groundLights1->setStateSet(lightManager->getGroundLightStateSet());
|
|
||||||
groundLights1->setNodeMask(GROUNDLIGHTS1_BIT);
|
|
||||||
osg::Group* groundLights2 = new osg::Group;
|
|
||||||
groundLights2->setStateSet(lightManager->getGroundLightStateSet());
|
|
||||||
groundLights2->setNodeMask(GROUNDLIGHTS2_BIT);
|
|
||||||
osg::Geode* geode = new osg::Geode;
|
|
||||||
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 2, -0.15f));
|
|
||||||
groundLights1->addChild(geode);
|
|
||||||
lightGroup->addChild(groundLights1);
|
|
||||||
geode = new osg::Geode;
|
|
||||||
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights));
|
|
||||||
groundLights2->addChild(geode);
|
|
||||||
lightGroup->addChild(groundLights2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tileGeometryBin.vasiLights.empty()) {
|
|
||||||
EffectGeode* vasiGeode = new EffectGeode;
|
|
||||||
Effect* vasiEffect
|
|
||||||
= getLightEffect(24, osg::Vec3(1, 0.0001, 0.000001), 1, 24, true);
|
|
||||||
vasiGeode->setEffect(vasiEffect);
|
|
||||||
SGVec4f red(1, 0, 0, 1);
|
|
||||||
SGMaterial* mat = 0;
|
|
||||||
if (matlib)
|
|
||||||
mat = matlib->find("RWY_RED_LIGHTS");
|
|
||||||
if (mat)
|
|
||||||
red = mat->get_light_color();
|
|
||||||
SGVec4f white(1, 1, 1, 1);
|
|
||||||
mat = 0;
|
|
||||||
if (matlib)
|
|
||||||
mat = matlib->find("RWY_WHITE_LIGHTS");
|
|
||||||
if (mat)
|
|
||||||
white = mat->get_light_color();
|
|
||||||
SGDirectionalLightListBin::const_iterator i;
|
|
||||||
for (i = tileGeometryBin.vasiLights.begin();
|
|
||||||
i != tileGeometryBin.vasiLights.end(); ++i) {
|
|
||||||
vasiGeode->addDrawable(SGLightFactory::getVasi(up, *i, red, white));
|
|
||||||
}
|
|
||||||
vasiGeode->setStateSet(lightManager->getRunwayLightStateSet());
|
|
||||||
lightGroup->addChild(vasiGeode);
|
|
||||||
}
|
|
||||||
|
|
||||||
Effect* runwayEffect = 0;
|
|
||||||
if (tileGeometryBin.runwayLights.getNumLights() > 0
|
|
||||||
|| !tileGeometryBin.rabitLights.empty()
|
|
||||||
|| !tileGeometryBin.reilLights.empty()
|
|
||||||
|| !tileGeometryBin.odalLights.empty()
|
|
||||||
|| tileGeometryBin.taxiLights.getNumLights() > 0)
|
|
||||||
runwayEffect = getLightEffect(16, osg::Vec3(1, 0.001, 0.0002), 1, 16, true);
|
|
||||||
if (tileGeometryBin.runwayLights.getNumLights() > 0
|
|
||||||
|| !tileGeometryBin.rabitLights.empty()
|
|
||||||
|| !tileGeometryBin.reilLights.empty()
|
|
||||||
|| !tileGeometryBin.odalLights.empty()
|
|
||||||
|| !tileGeometryBin.holdshortLights.empty()
|
|
||||||
|| !tileGeometryBin.guardLights.empty()) {
|
|
||||||
osg::Group* rwyLights = new osg::Group;
|
|
||||||
rwyLights->setStateSet(lightManager->getRunwayLightStateSet());
|
|
||||||
rwyLights->setNodeMask(RUNWAYLIGHTS_BIT);
|
|
||||||
if (tileGeometryBin.runwayLights.getNumLights() != 0) {
|
|
||||||
EffectGeode* geode = new EffectGeode;
|
|
||||||
geode->setEffect(runwayEffect);
|
|
||||||
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin
|
|
||||||
.runwayLights));
|
|
||||||
rwyLights->addChild(geode);
|
|
||||||
}
|
|
||||||
SGDirectionalLightListBin::const_iterator i;
|
|
||||||
for (i = tileGeometryBin.rabitLights.begin();
|
|
||||||
i != tileGeometryBin.rabitLights.end(); ++i) {
|
|
||||||
rwyLights->addChild(SGLightFactory::getSequenced(*i));
|
|
||||||
}
|
|
||||||
for (i = tileGeometryBin.reilLights.begin();
|
|
||||||
i != tileGeometryBin.reilLights.end(); ++i) {
|
|
||||||
rwyLights->addChild(SGLightFactory::getSequenced(*i));
|
|
||||||
}
|
|
||||||
for (i = tileGeometryBin.holdshortLights.begin();
|
|
||||||
i != tileGeometryBin.holdshortLights.end(); ++i) {
|
|
||||||
rwyLights->addChild(SGLightFactory::getHoldShort(*i));
|
|
||||||
}
|
|
||||||
for (i = tileGeometryBin.guardLights.begin();
|
|
||||||
i != tileGeometryBin.guardLights.end(); ++i) {
|
|
||||||
rwyLights->addChild(SGLightFactory::getGuard(*i));
|
|
||||||
}
|
|
||||||
SGLightListBin::const_iterator j;
|
|
||||||
for (j = tileGeometryBin.odalLights.begin();
|
|
||||||
j != tileGeometryBin.odalLights.end(); ++j) {
|
|
||||||
rwyLights->addChild(SGLightFactory::getOdal(*j));
|
|
||||||
}
|
|
||||||
lightGroup->addChild(rwyLights);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tileGeometryBin.taxiLights.getNumLights() > 0) {
|
|
||||||
osg::Group* taxiLights = new osg::Group;
|
|
||||||
taxiLights->setStateSet(lightManager->getTaxiLightStateSet());
|
|
||||||
taxiLights->setNodeMask(RUNWAYLIGHTS_BIT);
|
|
||||||
EffectGeode* geode = new EffectGeode;
|
|
||||||
geode->setEffect(runwayEffect);
|
|
||||||
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.taxiLights));
|
|
||||||
taxiLights->addChild(geode);
|
|
||||||
lightGroup->addChild(taxiLights);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The toplevel transform for that tile.
|
|
||||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
|
||||||
transform->setName(path);
|
|
||||||
transform->setMatrix(osg::Matrix::rotate(toOsg(hlOr))*
|
|
||||||
osg::Matrix::translate(toOsg(center)));
|
|
||||||
transform->addChild(terrainGroup);
|
|
||||||
if (lightGroup->getNumChildren() > 0) {
|
|
||||||
osg::LOD* lightLOD = new osg::LOD;
|
|
||||||
lightLOD->addChild(lightGroup.get(), 0, 60000);
|
|
||||||
// VASI is always on, so doesn't use light bits.
|
|
||||||
lightLOD->setNodeMask(LIGHTS_BITS | MODEL_BIT | PERMANENTLIGHT_BIT);
|
|
||||||
transform->addChild(lightLOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (randomObjects.valid() || forestNode.valid() || buildingNode.valid()) {
|
if (randomObjects.valid() || forestNode.valid() || buildingNode.valid()) {
|
||||||
|
objectLOD = new osg::LOD;
|
||||||
// Add a LoD node, so we don't try to display anything when the tile center
|
|
||||||
// is more than 20km away.
|
|
||||||
osg::LOD* objectLOD = new osg::LOD;
|
|
||||||
|
|
||||||
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
|
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
|
||||||
if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
|
if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
|
||||||
@ -1176,8 +1168,83 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
|
|
||||||
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
|
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
|
||||||
objectLOD->setNodeMask(nodeMask);
|
objectLOD->setNodeMask(nodeMask);
|
||||||
transform->addChild(objectLOD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return objectLOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The original options to use for this bunch of models
|
||||||
|
osg::ref_ptr<SGReaderWriterOptions> _options;
|
||||||
|
osg::ref_ptr<SGTileGeometryBin> _tileGeometryBin;
|
||||||
|
};
|
||||||
|
|
||||||
|
osg::Node*
|
||||||
|
SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options)
|
||||||
|
{
|
||||||
|
SGBinObject tile;
|
||||||
|
if (!tile.read_bin(path))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
SGMaterialLib* matlib = 0;
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
matlib = options->getMaterialLib();
|
||||||
|
}
|
||||||
|
|
||||||
|
SGVec3d center = tile.get_gbs_center();
|
||||||
|
SGGeod geodPos = SGGeod::fromCart(center);
|
||||||
|
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
|
||||||
|
|
||||||
|
// rotate the tiles so that the bounding boxes get nearly axis aligned.
|
||||||
|
// this will help the collision tree's bounding boxes a bit ...
|
||||||
|
std::vector<SGVec3d> nodes = tile.get_wgs84_nodes();
|
||||||
|
for (unsigned i = 0; i < nodes.size(); ++i)
|
||||||
|
nodes[i] = hlOr.transform(nodes[i]);
|
||||||
|
tile.set_wgs84_nodes(nodes);
|
||||||
|
|
||||||
|
SGQuatf hlOrf(hlOr[0], hlOr[1], hlOr[2], hlOr[3]);
|
||||||
|
std::vector<SGVec3f> normals = tile.get_normals();
|
||||||
|
for (unsigned i = 0; i < normals.size(); ++i)
|
||||||
|
normals[i] = hlOrf.transform(normals[i]);
|
||||||
|
tile.set_normals(normals);
|
||||||
|
|
||||||
|
osg::ref_ptr<SGTileGeometryBin> tileGeometryBin = new SGTileGeometryBin;
|
||||||
|
|
||||||
|
if (!tileGeometryBin->insertBinObj(tile, matlib))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
osg::Group* terrainGroup = new osg::Group;
|
||||||
|
terrainGroup->setName("BTGTerrainGroup");
|
||||||
|
|
||||||
|
osg::Node* node = tileGeometryBin->getSurfaceGeometry(matlib);
|
||||||
|
if (node)
|
||||||
|
terrainGroup->addChild(node);
|
||||||
|
|
||||||
|
// The toplevel transform for that tile.
|
||||||
|
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||||
|
transform->setName(path);
|
||||||
|
transform->setMatrix(osg::Matrix::rotate(toOsg(hlOr))*
|
||||||
|
osg::Matrix::translate(toOsg(center)));
|
||||||
|
transform->addChild(terrainGroup);
|
||||||
|
|
||||||
|
// PagedLOD for the random objects so we don't need to generate
|
||||||
|
// them all on tile loading.
|
||||||
|
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
||||||
|
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
||||||
|
pagedLOD->setName("pagedObjectLOD");
|
||||||
|
|
||||||
|
// we just need to know about the read file callback that itself holds the data
|
||||||
|
osg::ref_ptr<RandomObjectCallback> randomObjectCallback = new RandomObjectCallback;
|
||||||
|
randomObjectCallback->_options = SGReaderWriterOptions::copyOrCreate(options);
|
||||||
|
randomObjectCallback->_tileGeometryBin = tileGeometryBin;
|
||||||
|
|
||||||
|
osg::ref_ptr<osgDB::Options> callbackOptions = new osgDB::Options;
|
||||||
|
callbackOptions->setReadFileCallback(randomObjectCallback.get());
|
||||||
|
pagedLOD->setDatabaseOptions(callbackOptions.get());
|
||||||
|
|
||||||
|
pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy name - use the stored data in the read file callback");
|
||||||
|
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 35000);
|
||||||
|
transform->addChild(pagedLOD);
|
||||||
transform->setNodeMask( ~simgear::MODELLIGHT_BIT );
|
transform->setNodeMask( ~simgear::MODELLIGHT_BIT );
|
||||||
|
|
||||||
return transform;
|
return transform;
|
||||||
|
Loading…
Reference in New Issue
Block a user