Instance-based random buildings
Replace existing random buildings implementation with one using proper instancing. This allows better control of the buildings themselves and allows BUILDING_LIST STG verb to specify individual building dimensions. See README.scenery for details.
This commit is contained in:
@@ -108,7 +108,7 @@ SGMaterial::SGMaterial( const SGReaderWriterOptions* options,
|
||||
}
|
||||
|
||||
SGMaterial::SGMaterial( const osgDB::Options* options,
|
||||
const SGPropertyNode *props,
|
||||
const SGPropertyNode *props,
|
||||
SGPropertyNode *prop_root,
|
||||
AreaList *a,
|
||||
SGSharedPtr<const SGCondition> c)
|
||||
@@ -210,7 +210,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
_internal_state st( NULL, tpath.local8BitStr(), true, options );
|
||||
_status.push_back( st );
|
||||
}
|
||||
|
||||
|
||||
std::vector<SGPropertyNode_ptr> masks = props->getChildren("object-mask");
|
||||
for (unsigned int i = 0; i < masks.size(); i++)
|
||||
{
|
||||
@@ -243,8 +243,8 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
// the object mask, as DDS textures have an origin at the bottom
|
||||
// left rather than top left. Therefore we flip a copy of the image
|
||||
// (otherwise a second reference to the object mask would flip it
|
||||
// back!).
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Flipping object mask" << omname);
|
||||
// back!).
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Flipping object mask" << omname);
|
||||
image = (osg::Image* ) image->clone(osg::CopyOp::SHALLOW_COPY);
|
||||
image->flipVertical();
|
||||
}
|
||||
@@ -271,30 +271,30 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
wrapv = props->getBoolValue("wrapv", true);
|
||||
mipmap = props->getBoolValue("mipmap", true);
|
||||
light_coverage = props->getDoubleValue("light-coverage", 0.0);
|
||||
|
||||
|
||||
// Building properties
|
||||
building_coverage = props->getDoubleValue("building-coverage", 0.0);
|
||||
building_spacing = props->getDoubleValue("building-spacing-m", 5.0);
|
||||
|
||||
|
||||
std::string bt = props->getStringValue( "building-texture",
|
||||
"Textures/buildings.png" );
|
||||
building_texture = SGModelLib::findDataFile(bt, options);
|
||||
|
||||
building_texture = SGModelLib::findDataFile(bt, options);
|
||||
|
||||
if (building_texture.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find texture \"" << bt);
|
||||
}
|
||||
|
||||
|
||||
bt = props->getStringValue("building-lightmap", "Textures/buildings-lightmap.png");
|
||||
building_lightmap = SGModelLib::findDataFile(bt, options);
|
||||
|
||||
building_lightmap = SGModelLib::findDataFile(bt, options);
|
||||
|
||||
if (building_lightmap.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find texture \"" << bt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
building_small_ratio = props->getDoubleValue("building-small-ratio", 0.8);
|
||||
building_medium_ratio = props->getDoubleValue("building-medium-ratio", 0.15);
|
||||
building_large_ratio = props->getDoubleValue("building-large-ratio", 0.05);
|
||||
|
||||
|
||||
building_small_pitch = props->getDoubleValue("building-small-pitch", 0.8);
|
||||
building_medium_pitch = props->getDoubleValue("building-medium-pitch", 0.2);
|
||||
building_large_pitch = props->getDoubleValue("building-large-pitch", 0.1);
|
||||
@@ -305,27 +305,40 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
building_medium_max_floors = props->getIntValue("building-medium-max-floors", 8);
|
||||
building_large_min_floors = props->getIntValue("building-large-min-floors", 5);
|
||||
building_large_max_floors = props->getIntValue("building-large-max-floors", 20);
|
||||
|
||||
|
||||
building_small_min_width = props->getFloatValue("building-small-min-width-m", 15.0);
|
||||
building_small_max_width = props->getFloatValue("building-small-max-width-m", 60.0);
|
||||
building_small_min_depth = props->getFloatValue("building-small-min-depth-m", 10.0);
|
||||
building_small_max_depth = props->getFloatValue("building-small-max-depth-m", 20.0);
|
||||
|
||||
|
||||
building_medium_min_width = props->getFloatValue("building-medium-min-width-m", 25.0);
|
||||
building_medium_max_width = props->getFloatValue("building-medium-max-width-m", 50.0);
|
||||
building_medium_min_depth = props->getFloatValue("building-medium-min-depth-m", 20.0);
|
||||
building_medium_max_depth = props->getFloatValue("building-medium-max-depth-m", 50.0);
|
||||
|
||||
|
||||
building_large_min_width = props->getFloatValue("building-large-min-width-m", 50.0);
|
||||
building_large_max_width = props->getFloatValue("building-large-max-width-m", 75.0);
|
||||
building_large_min_depth = props->getFloatValue("building-large-min-depth-m", 50.0);
|
||||
building_large_max_depth = props->getFloatValue("building-large-max-depth-m", 75.0);
|
||||
|
||||
building_range = props->getDoubleValue("building-range-m", default_object_range);
|
||||
|
||||
|
||||
// There are some constraints on the maximum building size that we can sensibly render.
|
||||
// Using values outside these ranges will result in the texture being stretched to fit,
|
||||
// which may not be desireable. We will allow it, but display warnings.
|
||||
// We do not display warnings for large buildings as we assume the textures are sufficiently
|
||||
// generic to be stretched without problems.
|
||||
if (building_small_max_floors > 3) SG_LOG(SG_GENERAL, SG_ALERT, "building-small-max-floors exceeds maximum (3). Texture will be stretched to fit.");
|
||||
if (building_medium_max_floors > 8) SG_LOG(SG_GENERAL, SG_ALERT, "building-medium-max-floors exceeds maximum (8). Texture will be stretched to fit.");
|
||||
if (building_large_max_floors > 22) SG_LOG(SG_GENERAL, SG_ALERT, "building-large-max-floors exceeds maximum (22). Texture will be stretched to fit.");
|
||||
if (building_small_max_width > 192.0) SG_LOG(SG_GENERAL, SG_ALERT, "building-small-max-width-m exceeds maximum (192). Texture will be stretched to fit.");
|
||||
if (building_small_max_depth > 192.0) SG_LOG(SG_GENERAL, SG_ALERT, "building-small-max-depth-m exceeds maximum (192). Texture will be stretched to fit.");
|
||||
if (building_medium_max_width > 80.0) SG_LOG(SG_GENERAL, SG_ALERT, "building-medium-max-width-m exceeds maximum (80). Texture will be stretched to fit.");
|
||||
if (building_medium_max_depth > 80.0) SG_LOG(SG_GENERAL, SG_ALERT, "building-medium-max-depth-m exceeds maximum (80). Texture will be stretched to fit.");
|
||||
|
||||
cos_object_max_density_slope_angle = cos(props->getFloatValue("object-max-density-angle-deg", 20.0) * osg::PI/180.0);
|
||||
cos_object_zero_density_slope_angle = cos(props->getFloatValue("object-zero-density-angle-deg", 30.0) * osg::PI/180.0);
|
||||
|
||||
|
||||
// Random vegetation properties
|
||||
wood_coverage = props->getDoubleValue("wood-coverage", 0.0);
|
||||
tree_effect = props->getStringValue("tree-effect", "Effects/tree");
|
||||
@@ -337,7 +350,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
cos_tree_zero_density_slope_angle = cos(props->getFloatValue("tree-zero-density-angle-deg", 45.0) * osg::PI/180.0);
|
||||
|
||||
const SGPropertyNode* treeTexNode = props->getChild("tree-texture");
|
||||
|
||||
|
||||
if (treeTexNode) {
|
||||
std::string treeTexPath = props->getStringValue("tree-texture");
|
||||
|
||||
@@ -398,7 +411,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
if (name)
|
||||
glyphs[name] = new SGMaterialGlyph(glyph_nodes[i]);
|
||||
}
|
||||
|
||||
|
||||
// Read parameters entry, which is passed into the effect
|
||||
if (props->hasChild("parameters")) {
|
||||
parameters = props->getChild("parameters");
|
||||
@@ -413,7 +426,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
// Private methods.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
void
|
||||
SGMaterial::init ()
|
||||
{
|
||||
_status.clear();
|
||||
@@ -437,7 +450,7 @@ SGMaterial::init ()
|
||||
}
|
||||
|
||||
Effect* SGMaterial::get_effect(int i)
|
||||
{
|
||||
{
|
||||
if(!_status[i].effect_realized) {
|
||||
if (!_status[i].effect.valid())
|
||||
return 0;
|
||||
@@ -454,7 +467,7 @@ Effect* SGMaterial::get_one_effect(int texIndex)
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "No effect available.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int i = texIndex % _status.size();
|
||||
return get_effect(i);
|
||||
}
|
||||
@@ -472,9 +485,9 @@ osg::Texture2D* SGMaterial::get_one_object_mask(int texIndex)
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "No mask available.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Note that the object mask is closely linked to the texture/effect
|
||||
// so we index based on the texture index,
|
||||
// so we index based on the texture index,
|
||||
unsigned int i = texIndex % _status.size();
|
||||
if (i < _masks.size()) {
|
||||
return _masks[i].get();
|
||||
@@ -489,10 +502,10 @@ void SGMaterial::buildEffectProperties(const SGReaderWriterOptions* options)
|
||||
ref_ptr<SGMaterialUserData> user = new SGMaterialUserData(this);
|
||||
SGPropertyNode_ptr propRoot = new SGPropertyNode();
|
||||
makeChild(propRoot, "inherits-from")->setStringValue(effect);
|
||||
|
||||
|
||||
SGPropertyNode* paramProp = makeChild(propRoot, "parameters");
|
||||
copyProperties(parameters, paramProp);
|
||||
|
||||
|
||||
SGPropertyNode* materialProp = makeChild(paramProp, "material");
|
||||
makeChild(materialProp, "ambient")->setValue(SGVec4d(ambient));
|
||||
makeChild(materialProp, "diffuse")->setValue(SGVec4d(diffuse));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@
|
||||
#include <osg/ShadeModel>
|
||||
#include <osg/Material>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/VertexAttribDivisor>
|
||||
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
#include <simgear/scene/material/mat.hxx>
|
||||
@@ -47,141 +48,120 @@
|
||||
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
||||
#include <simgear/structure/OSGUtils.hxx>
|
||||
|
||||
#define SG_BUILDING_QUAD_TREE_DEPTH 4
|
||||
#define SG_BUILDING_QUAD_TREE_DEPTH 2
|
||||
#define SG_BUILDING_FADE_OUT_LEVELS 4
|
||||
|
||||
// these correspond to building.eff
|
||||
const int BUILDING_POSITION_ATTR = 10; // (x,y,z)
|
||||
const int BUILDING_SCALE_ATTR = 11; // (width, depth, height)
|
||||
const int BUILDING_ROT_PITCH_TEX0X_ATTR = 12; // (rotation, pitch height, texture x offset)
|
||||
const int BUILDING_TEX0Y_TEX1X_TEX1Y_ATTR = 13; // (texture y offset, texture x gain, texture y gain)
|
||||
|
||||
using namespace osg;
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
struct BuildingBoundingBoxCallback : public Drawable::ComputeBoundingBoxCallback
|
||||
{
|
||||
BuildingBoundingBoxCallback() {}
|
||||
BuildingBoundingBoxCallback(const BuildingBoundingBoxCallback&, const CopyOp&) {}
|
||||
META_Object(simgear, BuildingBoundingBoxCallback);
|
||||
virtual BoundingBox computeBound(const Drawable& drawable) const
|
||||
{
|
||||
BoundingBox bb;
|
||||
const Geometry* geom = static_cast<const Geometry*>(&drawable);
|
||||
const Vec3Array* pos = static_cast<const Vec3Array*>(geom->getVertexAttribArray(BUILDING_POSITION_ATTR));
|
||||
|
||||
for (unsigned int v=0; v<pos->size(); ++v) {
|
||||
Vec3 pt = (*pos)[v];
|
||||
bb.expandBy(pt);
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
};
|
||||
|
||||
class SGBuildingBin {
|
||||
public:
|
||||
|
||||
// Number of buildings to auto-generate. Individual
|
||||
// building instances are taken from this set.
|
||||
static const unsigned int BUILDING_SET_SIZE = 200;
|
||||
|
||||
static const unsigned int QUADS_PER_BUILDING = 12;
|
||||
static const unsigned int VERTICES_PER_BUILDING = 4 * QUADS_PER_BUILDING;
|
||||
static const unsigned int VERTICES_PER_BUILDING_SET = BUILDING_SET_SIZE * VERTICES_PER_BUILDING;
|
||||
|
||||
enum BuildingType {
|
||||
SMALL = 0,
|
||||
MEDIUM,
|
||||
LARGE };
|
||||
|
||||
struct BuildingInstance {
|
||||
BuildingInstance(Vec3f p, float w, float d, float h, float ph, float r, Vec2f t0, Vec2f t1) :
|
||||
position(p),
|
||||
width(w),
|
||||
depth(d),
|
||||
height(h),
|
||||
pitch_height(ph),
|
||||
rotation(r),
|
||||
tex0(t0),
|
||||
tex1(t1)
|
||||
{ }
|
||||
|
||||
BuildingInstance(Vec3f p, BuildingInstance b) :
|
||||
position(p),
|
||||
width(b.width),
|
||||
depth(b.depth),
|
||||
height(b.height),
|
||||
pitch_height(b.pitch_height),
|
||||
rotation(b.rotation),
|
||||
tex0(b.tex0),
|
||||
tex1(b.tex1)
|
||||
{ }
|
||||
|
||||
|
||||
Vec3f position;
|
||||
float width;
|
||||
float depth;
|
||||
float height;
|
||||
float pitch_height;
|
||||
float rotation;
|
||||
|
||||
Vec2f tex0;
|
||||
Vec2f tex1;
|
||||
|
||||
// References to allow the QuadTreeBuilder to work
|
||||
//const BuildingList* buildingList;
|
||||
//ref_ptr<Geometry> sharedGeometry;
|
||||
|
||||
Vec3f getPosition() { return position; }
|
||||
float getRotation() { return rotation; }
|
||||
|
||||
float getDistSqr(Vec3f p) {
|
||||
return (p - position) * (p - position);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct Building {
|
||||
Building(BuildingType t, float w, float d, float h, int f, bool pitch) :
|
||||
type(t),
|
||||
width(w),
|
||||
depth(d),
|
||||
height(h),
|
||||
floors(f),
|
||||
pitched(pitch),
|
||||
radius(std::max(d, 0.5f*w))
|
||||
{ }
|
||||
|
||||
BuildingType type;
|
||||
float width;
|
||||
float depth;
|
||||
float height;
|
||||
int floors;
|
||||
bool pitched;
|
||||
float radius;
|
||||
|
||||
float getFootprint() {
|
||||
return radius;
|
||||
}
|
||||
};
|
||||
|
||||
// The set of buildings that are instantiated
|
||||
typedef std::vector<Building> BuildingList;
|
||||
BuildingList smallBuildings;
|
||||
BuildingList mediumBuildings;
|
||||
BuildingList largeBuildings;
|
||||
const SGMaterial *material;
|
||||
|
||||
std::string* material_name;
|
||||
std::string* texture;
|
||||
std::string* lightMap;
|
||||
|
||||
// Fraction of buildings of this type
|
||||
float smallBuildingFraction;
|
||||
float mediumBuildingFraction;
|
||||
|
||||
// The maximum radius of each building type
|
||||
float smallBuildingMaxRadius;
|
||||
float mediumBuildingMaxRadius;
|
||||
float largeBuildingMaxRadius;
|
||||
|
||||
// The maximum depth of each building type
|
||||
float smallBuildingMaxDepth;
|
||||
float mediumBuildingMaxDepth;
|
||||
float largeBuildingMaxDepth;
|
||||
|
||||
// Visibility range for buildings
|
||||
float buildingRange;
|
||||
|
||||
// Shared geometries of the building set
|
||||
ref_ptr<Geometry> smallSharedGeometry;
|
||||
ref_ptr<Geometry> mediumSharedGeometry;
|
||||
ref_ptr<Geometry> largeSharedGeometry;
|
||||
|
||||
struct BuildingInstance {
|
||||
BuildingInstance(SGVec3f p, float r, const BuildingList* bl, ref_ptr<Geometry> sg) :
|
||||
position(p),
|
||||
rotation(r),
|
||||
buildingList(bl),
|
||||
sharedGeometry(sg)
|
||||
{ }
|
||||
|
||||
BuildingInstance(SGVec3f p, BuildingInstance b) :
|
||||
position(p),
|
||||
rotation(b.rotation),
|
||||
buildingList(b.buildingList),
|
||||
sharedGeometry(b.sharedGeometry)
|
||||
{ }
|
||||
|
||||
SGVec3f position;
|
||||
float rotation;
|
||||
|
||||
// References to allow the QuadTreeBuilder to work
|
||||
const BuildingList* buildingList;
|
||||
ref_ptr<Geometry> sharedGeometry;
|
||||
|
||||
SGVec3f getPosition() { return position; }
|
||||
float getRotation() { return rotation; }
|
||||
|
||||
float getDistSqr(SGVec3f p) {
|
||||
return distSqr(p, position);
|
||||
}
|
||||
|
||||
const osg::Vec4f getColorValue() {
|
||||
return osg::Vec4f(toOsg(position), rotation);
|
||||
}
|
||||
};
|
||||
|
||||
// Information for an instance of a building - position and orientation
|
||||
typedef std::vector<BuildingInstance> BuildingInstanceList;
|
||||
BuildingInstanceList smallBuildingLocations;
|
||||
BuildingInstanceList mediumBuildingLocations;
|
||||
BuildingInstanceList largeBuildingLocations;
|
||||
BuildingInstanceList buildingLocations;
|
||||
|
||||
public:
|
||||
|
||||
SGBuildingBin(const SGMaterial *mat, bool useVBOs);
|
||||
SGBuildingBin(const SGPath& absoluteFileName, const SGMaterial *mat, bool useVBOs);
|
||||
|
||||
~SGBuildingBin() {
|
||||
smallBuildings.clear();
|
||||
mediumBuildings.clear();
|
||||
largeBuildings.clear();
|
||||
smallBuildingLocations.clear();
|
||||
mediumBuildingLocations.clear();
|
||||
largeBuildingLocations.clear();
|
||||
}
|
||||
~SGBuildingBin();
|
||||
|
||||
// Generate a building specifying the exact position, dimensions and texture index.
|
||||
void insert(SGVec3f p, float r, BuildingType buildingtype, float width, float depth, float height, float pitch_height, int floors, int tex_index);
|
||||
|
||||
// Generate a building of a given type at a specified position, using the random building material definition to determine the dimensions and texture index.
|
||||
void insert(SGVec3f p, float r, BuildingType type);
|
||||
int getNumBuildings();
|
||||
|
||||
@@ -190,123 +170,9 @@ public:
|
||||
std::string* getMaterialName() { return material_name; }
|
||||
|
||||
BuildingType getBuildingType(float roll);
|
||||
|
||||
float getBuildingMaxRadius(BuildingType);
|
||||
float getBuildingMaxDepth(BuildingType);
|
||||
|
||||
// Helper classes for creating the quad tree
|
||||
struct MakeBuildingLeaf
|
||||
{
|
||||
MakeBuildingLeaf(float range, Effect* effect, bool fade) :
|
||||
_range(range), _effect(effect), _fade_out(fade) {}
|
||||
|
||||
MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
|
||||
_range(rhs._range), _effect(rhs._effect), _fade_out(rhs._fade_out)
|
||||
{}
|
||||
|
||||
LOD* operator() () const
|
||||
{
|
||||
LOD* result = new LOD;
|
||||
|
||||
if (_fade_out) {
|
||||
// Create a series of LOD nodes so building cover decreases
|
||||
// gradually with distance from _range to 2*_range
|
||||
for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
|
||||
{
|
||||
EffectGeode* geode = new EffectGeode;
|
||||
geode->setEffect(_effect.get());
|
||||
result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));
|
||||
}
|
||||
} else {
|
||||
// No fade-out, so all are visible for 2X range
|
||||
EffectGeode* geode = new EffectGeode;
|
||||
geode->setEffect(_effect.get());
|
||||
result->addChild(geode, 0, 2.0 * _range);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float _range;
|
||||
ref_ptr<Effect> _effect;
|
||||
bool _fade_out;
|
||||
};
|
||||
|
||||
struct AddBuildingLeafObject
|
||||
{
|
||||
Geometry* createNewBuildingGeometryInstance(const BuildingInstance& building) const
|
||||
{
|
||||
Geometry* geom = simgear::clone(building.sharedGeometry.get(), CopyOp::SHALLOW_COPY);
|
||||
geom->setColorArray(new Vec4Array, Array::BIND_PER_VERTEX);
|
||||
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS));
|
||||
return geom;
|
||||
}
|
||||
|
||||
void operator() (LOD* lod, const BuildingInstance& building) const
|
||||
{
|
||||
Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
|
||||
unsigned int numDrawables = geode->getNumDrawables();
|
||||
|
||||
// Get the last geometry of to be added and check if there is space for
|
||||
// another building instance within it. This is done by checking
|
||||
// if the number of Color values matches the number of vertices.
|
||||
// The color array is used to store the position of a particular
|
||||
// instance.
|
||||
Geometry* geom;
|
||||
|
||||
if (numDrawables == 0) {
|
||||
// Create a new copy of the shared geometry to instantiate
|
||||
geom = createNewBuildingGeometryInstance(building);
|
||||
geode->addDrawable(geom);
|
||||
} else {
|
||||
geom = static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));
|
||||
}
|
||||
|
||||
// Check if this building is too close to any other others.
|
||||
DrawArrays* primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
|
||||
Vec4Array* posArray = static_cast<Vec4Array*>(geom->getColorArray());
|
||||
|
||||
// Now check if this geometry is full.
|
||||
if (posArray->size() >= static_cast<Vec3Array*>(geom->getVertexArray())->size()) {
|
||||
// This particular geometry is full, so we generate another
|
||||
// by taking a shallow copy of the shared Geomety.
|
||||
geom = createNewBuildingGeometryInstance(building);
|
||||
geode->addDrawable(geom);
|
||||
posArray = static_cast<Vec4Array*>(geom->getColorArray());
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Added new geometry to building geod: " << geode->getNumDrawables());
|
||||
}
|
||||
|
||||
// We now have a geometry with space for this new building.
|
||||
// Set the position and rotation
|
||||
osg::Vec4f c = osg::Vec4f(toOsg(building.position), building.rotation);
|
||||
posArray->insert(posArray->end(), VERTICES_PER_BUILDING, c);
|
||||
size_t numVerts = posArray->size();
|
||||
primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
|
||||
primSet->setCount(numVerts);
|
||||
}
|
||||
};
|
||||
|
||||
struct GetBuildingCoord
|
||||
{
|
||||
Vec3 operator() (const BuildingInstance& building) const
|
||||
{
|
||||
return toOsg(building.position);
|
||||
}
|
||||
};
|
||||
|
||||
typedef QuadTreeBuilder<LOD*, BuildingInstance, MakeBuildingLeaf, AddBuildingLeafObject,
|
||||
GetBuildingCoord> BuildingGeometryQuadtree;
|
||||
|
||||
struct BuildingInstanceTransformer
|
||||
{
|
||||
BuildingInstanceTransformer(Matrix& mat_) : mat(mat_) {}
|
||||
BuildingInstance operator()(const BuildingInstance& buildingInstance) const
|
||||
{
|
||||
Vec3 pos = toOsg(buildingInstance.position) * mat;
|
||||
return BuildingInstance(toSG(pos), buildingInstance);
|
||||
}
|
||||
Matrix mat;
|
||||
};
|
||||
|
||||
ref_ptr<Group> createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options);
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user