X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Ftgdb%2Fobj.cxx;h=ebcb3167cc8a78acb643cbc9280c83e7f8b0c710;hb=7e7ce2f38e87d6244e05730fa4382da088bb25f1;hp=882751373f32888b0e24e53adc93fa55160c1d95;hpb=0c9013e60e5d7a9762fdd93180d02725d6873e57;p=simgear.git diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 88275137..ebcb3167 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -50,12 +50,11 @@ #include #include #include -#include -#include #include "SGTexturedTriangleBin.hxx" #include "SGLightBin.hxx" #include "SGModelBin.hxx" +#include "TreeBin.hxx" #include "SGDirectionalLightBin.hxx" #include "GroundLightManager.hxx" @@ -73,6 +72,7 @@ struct SGTileGeometryBin { SGMaterialTriangleMap materialTriangleMap; SGLightBin tileLights; SGLightBin randomTileLights; + TreeBin randomForest; SGDirectionalLightBin runwayLights; SGDirectionalLightBin taxiLights; SGDirectionalLightListBin vasiLights; @@ -80,7 +80,7 @@ struct SGTileGeometryBin { SGLightListBin odalLights; SGDirectionalLightListBin reilLights; SGMatModelBin randomModels; - + static SGVec4f getMaterialLightColor(const SGMaterial* material) { @@ -131,7 +131,7 @@ struct SGTileGeometryBin { std::string materialName = obj.get_pt_materials()[grp]; SGMaterial* material = matlib->find(materialName); SGVec4f color = getMaterialLightColor(material); - + if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") { // Just plain lights. Not something for the runway. addPointGeometry(tileLights, obj.get_wgs84_nodes(), color, @@ -368,32 +368,11 @@ struct SGTileGeometryBin { osg::Geode* geode = new osg::Geode; SGMaterialTriangleMap::const_iterator i; for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { - // CHUNCKED (sic) here splits up unconnected triangles parts of - // the mesh into different Geometry sets, presumably for better - // culling. I (timoore) believe it is more performant to build - // the biggest indexed sets possible at the expense of tight - // culling. -//#define CHUNCKED -#ifdef CHUNCKED - SGMaterial *mat = matlib->find(i->first); - - std::list connectSets; - i->second.getConnectedSets(connectSets); - - std::list::iterator j; - for (j = connectSets.begin(); j != connectSets.end(); ++j) { - osg::Geometry* geometry = i->second.buildGeometry(*j); - if (mat) - geometry->setStateSet(mat->get_state()); - geode->addDrawable(geometry); - } -#else osg::Geometry* geometry = i->second.buildGeometry(); SGMaterial *mat = matlib->find(i->first); if (mat) geometry->setStateSet(mat->get_state()); geode->addDrawable(geometry); -#endif } return geode; } @@ -448,37 +427,80 @@ struct SGTileGeometryBin { } } } - + + void computeRandomForest(SGMaterialLib* matlib) + { + SGMaterialTriangleMap::iterator i; + + // generate a repeatable random seed + mt seed; + mt_init(&seed, unsigned(586)); + + for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { + SGMaterial *mat = matlib->find(i->first); + if (!mat) + continue; + + float coverage = mat->get_tree_coverage(); + if (coverage <= 0) + continue; + + // Attributes that don't vary by tree + randomForest.texture = mat->get_tree_texture(); + randomForest.range = mat->get_tree_range(); + randomForest.width = mat->get_tree_width(); + randomForest.height = mat->get_tree_height(); + randomForest.texture_varieties = mat->get_tree_varieties(); + + std::vector randomPoints; + i->second.addRandomSurfacePoints(coverage, 0, randomPoints); + std::vector::iterator j; + for (j = randomPoints.begin(); j != randomPoints.end(); ++j) { + + // Apply a random scaling factor and texture index. + float scale = (mt_rand(&seed) + mt_rand(&seed)) / 2.0f + 0.5f; + int v = (int) (mt_rand(&seed) * mat->get_tree_varieties()); + if (v == mat->get_tree_varieties()) v--; + randomForest.insert(*j, v, scale); + } + } + } + void computeRandomObjects(SGMaterialLib* matlib) { SGMaterialTriangleMap::iterator i; + + // generate a repeatable random seed + mt seed; + mt_init(&seed, unsigned(123)); + for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { SGMaterial *mat = matlib->find(i->first); if (!mat) continue; - + int group_count = mat->get_object_group_count(); - + if (group_count > 0) - { + { for (int j = 0; j < group_count; j++) - { + { SGMatModelGroup *object_group = mat->get_object_group(j); int nObjects = object_group->get_object_count(); - + if (nObjects > 0) { // For each of the random models in the group, determine an appropriate // number of random placements and insert them. for (int k = 0; k < nObjects; k++) { SGMatModel * object = object_group->get_object(k); - + std::vector randomPoints; i->second.addRandomPoints(object->get_coverage_m2(), randomPoints); std::vector::iterator l; for (l = randomPoints.begin(); l != randomPoints.end(); ++l) { - randomModels.insert(*l, object); + randomModels.insert(*l, object, (int)object->get_randomized_range_m(&seed)); } } } @@ -497,81 +519,118 @@ struct SGTileGeometryBin { } }; +typedef std::pair ModelLOD; +struct MakeQuadLeaf { + osg::LOD* operator() () const { return new osg::LOD; } +}; +struct AddModelLOD { + void operator() (osg::LOD* leaf, ModelLOD& mlod) const + { + leaf->addChild(mlod.first, 0, mlod.second); + } +}; +struct GetModelLODCoord { + GetModelLODCoord() {} + GetModelLODCoord(const GetModelLODCoord& rhs) + {} + osg::Vec3 operator() (const ModelLOD& mlod) const + { + return mlod.first->getBound().center(); + } +}; + +typedef QuadTreeBuilder RandomObjectsQuadtree; + osg::Node* -SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects) +SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects, bool use_random_vegetation) { SGBinObject tile; if (!tile.read_bin(path)) return false; + SGVec3d center = tile.get_gbs_center2(); + 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 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 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 false; - SGVec3d center = tile.get_gbs_center2(); - SGGeod geodPos = SGGeod::fromCart(center); - SGQuatd hlOr = SGQuatd::fromLonLat(geodPos); - SGVec3f up = toVec3f(hlOr.backTransform(SGVec3d(0, 0, -1))); - osg::Matrix world2Tile(-hlOr.osg()); + SGVec3f up(0, 0, 1); GroundLightManager* lightManager = GroundLightManager::instance(); osg::ref_ptr lightGroup = new SGOffsetTransform(0.94); osg::ref_ptr randomObjects; + osg::ref_ptr randomForest; osg::Group* terrainGroup = new osg::Group; osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib); if (node) terrainGroup->addChild(node); + + if (use_random_objects || use_random_vegetation) { + if (use_random_objects) { + tileGeometryBin.computeRandomObjects(matlib); - if (use_random_objects) { - tileGeometryBin.computeRandomObjects(matlib); - - if (tileGeometryBin.randomModels.getNumModels() > 0) { - // Generate a repeatable random seed - mt seed; - mt_init(&seed, unsigned(123)); - - // Determine an rotation matrix for the models to place them - // perpendicular to the earth's surface. We use the same matrix, - // based on the centre of the tile, as the small angular differences - // between different points on the tile aren't worth worrying about - // for random objects. We also need to flip the orientation 180 degrees - static const osg::Matrix flip(1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, -1, 0, - 0, 0, 0, 1); - osg::Matrix mAtt = flip * osg::Matrix::rotate(hlOr.osg()); - std::vector > models; - - for (unsigned int i = 0; i < tileGeometryBin.randomModels.getNumModels(); i++) { - SGMatModelBin::MatModel obj = tileGeometryBin.randomModels.getMatModel(i); - osg::Node* node = sgGetRandomModel(obj.model); - - // Create a matrix to place the object in the correct location, and then - // apply the rotation matrix created above, with an additional random - // heading rotation if appropriate. - osg::Matrix mPos = osg::Matrix::translate(obj.position.osg()); - osg::MatrixTransform* position; + if (tileGeometryBin.randomModels.getNumModels() > 0) { + // Generate a repeatable random seed + mt seed; + mt_init(&seed, unsigned(123)); + + std::vector models; + for (unsigned int i = 0; + i < tileGeometryBin.randomModels.getNumModels(); i++) { + SGMatModelBin::MatModel obj + = tileGeometryBin.randomModels.getMatModel(i); + osg::Node* node = sgGetRandomModel(obj.model); - if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) { - // Rotate the object around the z axis. - double hdg = mt_rand(&seed) * M_PI * 2; - osg::Matrix rot(cos(hdg), -sin(hdg), 0, 0, - sin(hdg), cos(hdg), 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - position = new osg::MatrixTransform(rot * mAtt * mPos); - } else { - position = new osg::MatrixTransform(mAtt * mPos); + // Create a matrix to place the object in the correct + // location, and then apply the rotation matrix created + // above, with an additional random heading rotation if appropriate. + osg::Matrix transformMat; + transformMat = osg::Matrix::translate(obj.position.osg()); + if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) { + // Rotate the object around the z axis. + double hdg = mt_rand(&seed) * M_PI * 2; + transformMat.preMult(osg::Matrix::rotate(hdg, + osg::Vec3d(0.0, 0.0, 1.0))); + } + osg::MatrixTransform* position = + new osg::MatrixTransform(transformMat); + position->addChild(node); + models.push_back(ModelLOD(position, obj.lod)); } - - position->addChild(node); - models.push_back(position); - // Add to the leaf of the quadtree based on object location. + RandomObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD())); + quadtree.buildQuadTree(models.begin(), models.end()); + randomObjects = quadtree.getRoot(); + randomObjects->setName("random objects"); } - randomObjects = QuadTreeBuilder::makeQuadTree(models, world2Tile); - randomObjects->setName("random objects"); } + + if (use_random_vegetation) { + // Now add some random forest. + tileGeometryBin.computeRandomForest(matlib); + + if (tileGeometryBin.randomForest.getNumTrees() > 0) { + randomForest = createForest(tileGeometryBin.randomForest, + osg::Matrix::identity()); + randomForest->setName("random trees"); + } + } } if (calc_lights) { @@ -608,6 +667,7 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool } if (!tileGeometryBin.vasiLights.empty()) { + osg::Geode* vasiGeode = new osg::Geode; SGVec4f red(1, 0, 0, 1); SGMaterial* mat = matlib->find("RWY_RED_LIGHTS"); if (mat) @@ -617,17 +677,14 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool if (mat) white = mat->get_light_color(); - osg::Geode* geode = new osg::Geode; SGDirectionalLightListBin::const_iterator i; for (i = tileGeometryBin.vasiLights.begin(); i != tileGeometryBin.vasiLights.end(); ++i) { - geode->addDrawable(SGLightFactory::getVasi(up, *i, red, white)); + vasiGeode->addDrawable(SGLightFactory::getVasi(up, *i, red, white)); } - osg::Group* vasiLights = new osg::Group; - vasiLights->setCullCallback(new SGPointSpriteLightCullCallback(osg::Vec3(1, 0.0001, 0.000001), 6)); - vasiLights->setStateSet(lightManager->getRunwayLightStateSet()); - vasiLights->addChild(geode); - lightGroup->addChild(vasiLights); + vasiGeode->setCullCallback(new SGPointSpriteLightCullCallback(osg::Vec3(1, 0.0001, 0.000001), 6)); + vasiGeode->setStateSet(lightManager->getRunwayLightStateSet()); + lightGroup->addChild(vasiGeode); } if (tileGeometryBin.runwayLights.getNumLights() > 0 @@ -675,27 +732,27 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool // The toplevel transform for that tile. osg::MatrixTransform* transform = new osg::MatrixTransform; transform->setName(path); - transform->setMatrix(osg::Matrix::translate(center.osg())); + transform->setMatrix(osg::Matrix::rotate(hlOr.osg())* + osg::Matrix::translate(center.osg())); transform->addChild(terrainGroup); if (lightGroup->getNumChildren() > 0) { osg::LOD* lightLOD = new osg::LOD; lightLOD->addChild(lightGroup.get(), 0, 30000); - unsigned nodeMask = ~0u; - nodeMask &= ~SG_NODEMASK_CASTSHADOW_BIT; - nodeMask &= ~SG_NODEMASK_RECIEVESHADOW_BIT; - nodeMask &= ~SG_NODEMASK_PICK_BIT; - nodeMask &= ~SG_NODEMASK_TERRAIN_BIT; - lightLOD->setNodeMask(nodeMask); + // VASI is always on, so doesn't use light bits. + lightLOD->setNodeMask(LIGHTS_BITS | MODEL_BIT); transform->addChild(lightLOD); } - if (randomObjects.valid()) { + if (randomObjects.valid() || randomForest.valid()) { // 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; - objectLOD->addChild(randomObjects.get(), 0, 20000); - unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT; + + if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000); + if (randomForest.valid()) objectLOD->addChild(randomForest.get(), 0, 20000); + + unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT; objectLOD->setNodeMask(nodeMask); transform->addChild(objectLOD); }