STG-defined buildings using Random Building shader

Support BUILDING_LIST STG verb which references a file
containing the cartesian coordinates of individual buildings,
to be generated using the random-building shader approach.

BUILDING_LIST buildings.txt OSM_Building -2.72943543 56.00080606 36.1 0

buildings.txt:

0 0 0 0 0
0 100 0 0 0
0 200 0 0 0
0 300 0 0 1
0 400 0 0 1
0 500 0 0 2
100 0 0 0 2
200 0 0 0 2
300 0 0 0 2
400 0 0 15 2
This commit is contained in:
Stuart Buchanan
2018-11-18 21:08:06 +00:00
parent ba9342cd4b
commit 460a666234
4 changed files with 109 additions and 11 deletions

View File

@@ -50,6 +50,8 @@
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/tgdb/apt_signs.hxx>
#include <simgear/scene/tgdb/obj.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/tgdb/SGBuildingBin.hxx>
#include "SGOceanTile.hxx"
@@ -59,6 +61,7 @@
#define ROAD_DETAILED "OBJECT_ROAD_DETAILED"
#define RAILWAY_ROUGH "OBJECT_RAILWAY_ROUGH"
#define RAILWAY_DETAILED "OBJECT_RAILWAY_DETAILED"
#define BUILDING_LIST "BUILDING_LIST"
namespace simgear {
@@ -121,6 +124,12 @@ struct ReaderWriterSTG::_ModelBin {
double _hdg;
int _size;
};
struct _BuildingList {
_BuildingList() : _lon(0), _lat(0), _elev(0) { }
std::string _filename;
std::string _material_name;
double _lon, _lat, _elev;
};
class DelayLoadReadFileCallback : public OptionsReadFileCallback {
@@ -185,8 +194,6 @@ struct ReaderWriterSTG::_ModelBin {
};
typedef QuadTreeBuilder<osg::LOD*, _ObjectStatic, MakeQuadLeaf, AddModelLOD,
GetModelLODCoord> STGObjectsQuadtree;
public:
virtual osgDB::ReaderWriter::ReadResult
readNode(const std::string&, const osgDB::Options*)
@@ -203,12 +210,40 @@ struct ReaderWriterSTG::_ModelBin {
if (signBuilder.getSignsGroup())
group->addChild(signBuilder.getSignsGroup());
if (_buildingList.size() > 0) {
SGMaterialLibPtr matlib = _options->getMaterialLib();
bool useVBOs = (_options->getPluginStringData("SimGear::USE_VBOS") == "ON");
if (!matlib) {
SG_LOG( SG_TERRAIN, SG_ALERT, "Unable to get materials definition for buildings");
} else {
for (std::list<_BuildingList>::iterator i = _buildingList.begin(); i != _buildingList.end(); ++i) {
// Build buildings for each list of buildings
SGGeod geodPos = SGGeod::fromDegM(i->_lon, i->_lat, 0.0);
SGMaterial* mat = matlib->find(i->_material_name, geodPos);
SGPath path = SGPath(i->_filename);
SGBuildingBin* buildingBin = new SGBuildingBin(path, mat, useVBOs);
SGBuildingBinList buildingBinList;
buildingBinList.push_back(buildingBin);
osg::MatrixTransform* matrixTransform;
matrixTransform = new osg::MatrixTransform(makeZUpFrame(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev)));
matrixTransform->setName("rotateBuildings");
matrixTransform->setDataVariance(osg::Object::STATIC);
matrixTransform->addChild(createRandomBuildings(buildingBinList, osg::Matrix::identity(), _options));
group->addChild(matrixTransform);
}
}
}
return group.release();
}
mt _seed;
std::list<_ObjectStatic> _objectStaticList;
std::list<_Sign> _signList;
std::list<_BuildingList> _buildingList;
/// The original options to use for this bunch of models
osg::ref_ptr<SGReaderWriterOptions> _options;
@@ -315,7 +350,6 @@ struct ReaderWriterSTG::_ModelBin {
// starting with 2018.3 we will use deltas rather than absolutes as it is more intuitive for the user
// and somewhat easier to visualise
double detailedRange = atof(options->getPluginStringData("SimGear::LOD_RANGE_DETAILED").c_str());
double bareRangeDelta = atof(options->getPluginStringData("SimGear::LOD_RANGE_BARE").c_str());
double roughRangeDelta = atof(options->getPluginStringData("SimGear::LOD_RANGE_ROUGH").c_str());
@@ -490,6 +524,13 @@ struct ReaderWriterSTG::_ModelBin {
obj._options = opt;
checkInsideBucket(absoluteFileName, obj._lon, obj._lat);
_objectStaticList.push_back(obj);
} else if (token == BUILDING_LIST) {
_BuildingList buildinglist;
buildinglist._filename = path.local8BitStr();
in >> buildinglist._material_name >> buildinglist._lon >> buildinglist._lat >> buildinglist._elev;
checkInsideBucket(absoluteFileName, buildinglist._lon, buildinglist._lat);
_buildingListList.push_back(buildinglist);
//SG_LOG(SG_TERRAIN, SG_ALERT, "Building list: " << buildinglist._filename << " " << buildinglist._material_name << " " << buildinglist._lon << " " << buildinglist._lat);
} else {
SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName
<< ": Unknown token '" << token << "'" );
@@ -560,6 +601,7 @@ struct ReaderWriterSTG::_ModelBin {
// we just need to know about the read file callback that itself holds the data
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
readFileCallback->_objectStaticList = _objectStaticList;
readFileCallback->_buildingList = _buildingListList;
readFileCallback->_signList = _signList;
readFileCallback->_options = options;
readFileCallback->_bucket = bucket;
@@ -584,6 +626,7 @@ struct ReaderWriterSTG::_ModelBin {
std::list<_Object> _objectList;
std::list<_ObjectStatic> _objectStaticList;
std::list<_Sign> _signList;
std::list<_BuildingList> _buildingListList;
};
ReaderWriterSTG::ReaderWriterSTG()

View File

@@ -44,12 +44,11 @@
#include <osgDB/FileUtils>
#include <simgear/debug/logstream.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/math/SGLimits.hxx>
#include <simgear/math/SGMisc.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/misc/sg_path.hxx>
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/model/model.hxx>
#include <simgear/props/props.hxx>
@@ -107,6 +106,59 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
return bb;
}
// Set up a BuildingBin from a file containing a list of individual building
// positions.
SGBuildingBin::SGBuildingBin(const SGPath& absoluteFileName, const SGMaterial *mat, bool useVBOs) :
SGBuildingBin::SGBuildingBin(mat, useVBOs)
{
if (!absoluteFileName.exists()) {
SG_LOG(SG_TERRAIN, SG_ALERT, "Building list file " << absoluteFileName << " does not exist.");
return;
}
sg_gzifstream stream(absoluteFileName);
if (!stream.is_open()) {
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to open " << absoluteFileName << " does not exist.");
return;
}
while (!stream.eof()) {
// read a line. Each line defines a single builing position, and may have
// a comment, starting with #
std::string line;
std::getline(stream, line);
// strip comments
std::string::size_type hash_pos = line.find('#');
if (hash_pos != std::string::npos)
line.resize(hash_pos);
// and process further
std::stringstream in(line);
// Line format is X Y Z R T
// where:
// X,Y,Z are the cartesian coordinates of the bottom SW corner of the building. +X is East, +Y is North
// R is the building rotation in degrees centered on the SW corner
// T is the building type [0, 1, 2] for SMALL, MEDIUM, LARGE
float x, y, z, r;
int t;
in >> x >> y >> z >> r >> t;
//SG_LOG(SG_TERRAIN, SG_ALERT, "Building entry " << x << " " << y << " " << z << " " << t );
SGVec3f p = SGVec3f(x,y,z);
BuildingType type = BuildingType::SMALL;
if (t == 1) type = BuildingType::MEDIUM;
if (t == 2) type = BuildingType::LARGE;
// Rotation is in the file as degrees, but in the datastructure normalized
// to 0.0 - 1.0
insert(p, (float) (r / 360.0f), type);
}
stream.close();
};
// Set up the building set based on the material definitions
SGBuildingBin::SGBuildingBin(const SGMaterial *mat, bool useVBOs) {
@@ -165,7 +217,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
if (useVBOs) {
sharedGeometry->setUseVertexBufferObjects(true);
}
for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) {
float width;
float depth;
@@ -820,8 +872,8 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
};
// This actually returns a MatrixTransform node. If we rotate the whole
// forest into the local Z-up coordinate system we can reuse the
// primitive building geometry for all the forests of the same type.
// set of buildings into the local Z-up coordinate system we can reuse the
// primitive building geometry for all the buildings of the same type.
osg::Group* createRandomBuildings(SGBuildingBinList& buildings, const osg::Matrix& transform,
const SGReaderWriterOptions* options)
{

View File

@@ -36,10 +36,12 @@
#include <osg/Material>
#include <osg/CullFace>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/util/QuadTreeBuilder.hxx>
#include <simgear/scene/util/RenderConstants.hxx>
#include <simgear/scene/util/StateAttributeFactory.hxx>
@@ -169,6 +171,7 @@ private:
public:
SGBuildingBin(const SGMaterial *mat, bool useVBOs);
SGBuildingBin(const SGPath& absoluteFileName, const SGMaterial *mat, bool useVBOs);
~SGBuildingBin() {
smallBuildings.clear();

View File

@@ -230,9 +230,9 @@ void addTreeToLeafGeode(Geode* geode, const SGVec3f& p, const SGVec3f& t)
posArray->insert(posArray->end(), 4, pos);
size_t numVerts = posArray->size();
int imax = 2;
unsigned int imax = 2;
if (use_tree_shadows) { imax = 3; }
for (int i = 0; i < imax; ++i) {
for (unsigned int i = 0; i < imax; ++i) {
if (i < geom->getNumPrimitiveSets()) {
DrawArrays* primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(i));
if (primSet != nullptr)