Hackathon Proposal: WS3.0 Effects
|Title:||WS 3.0 Effects |
|Background:||Currently we have some of the pieces required for WS3.0:
... but the WS3.0 scenery in FG is basically a dark gray blob. The bit that's missing is having the scenery pick up material definitions and therefore Effects and shaders.
This hackathon idea is to apply material definitions to that scenery and perhaps develop a shader that will use the landclass texture to generate some plausible texturing.
|Learning Opportunities:||* Materials
- Virtual Planet Builder
- World Scenery 3.0 roadmap
- How the VPB is rendered in FlightGear: https://sourceforge.net/p/flightgear/simgear/ci/cbd8e3acc4eab6724b5be32f64eeeb0530e207ed/
- How trees are created at the moment:
- Runtime Airport building
- add a line to the STG file - [ICAO].icao
Details of sub-project to add trees to WS3.0.
- FG has the concept of a Material - how a particular type of land (a landclass) is rendered by the simulator (e.g. texture, Effect, tree density, roughness).
- The materials are defined in a set of XML files in fgdata/Materials. Different regions (defined by lon/lat) can define different materials. So a forest in Norway contains different trees than one in Brazil.
- See fgdata/Docs/README.materials for the XML format information
- See Howto:Editing tile textures and materials
- See Materials/default/global-summer.xml for a good rundown of the different landclasses.
- The materials are built into a SGMaterialLibrary (simgear/simgear/scene/material/matlib.cxx).
- In the old scenery, the terrain consists of a triangular mesh that describes both the shape (elevation) of the terrain and the landclass of the terrain. Each triangle of the terrain mesh as a single landclass (e.g. "EvergreenBroadCover").
- In the WS3.0 scenery, the terrain mesh only contains shape (elevation) information, and is created at runtime from a heightmap. The landclass of the terrain is provided by the texture. Each triangle can contain bits of multiple landclasses.
How Trees are grown - old scenery
Trees are generated in the Old scenery as follows:
- simgear/simgear/scene/tgdb/obj.cxx SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options) loads a "BTG" file.
- line 113 created a SGTileDetailsCallback. This is a callback that will generate more detail for the tile when the viewpoint gets within range. This avoid having to create trees for tiles that might be 100km away and which we never get any closer to.
- line 118 creates a PagedLOD which will call the FGTileDetailsCallback when the viewer gets within range.
- simgear/simgear/scene/tgdb/SGTileDetailsCallback.hxx readNode(const std::string&, const osgDB::Options*) does the actual work to generate the details for a tile such as forests, random objects, lights, and it called by the PagedLOD object above.
- line 138 calls generateRandomTileObjects to create the forest, buildings and buildings
- generateRandomTileObjects (line 976) builds a set of OSG nodes and makes various calls to generate the random features.
- line 1086 calls computeRandomForest to create a list of the random trees based on the terrain triangles and their landclasses. computeRa
- computeRandomForest considers each terrain triangle in turn and...
- looks up the landclass in the materials library to determine if this landclass (and therefore triangle) contains any trees
- assuming it does, gets a TreeBin to put these trees (based on having the same settings as an existing tree definitions), then
- generates a series of random points across the triangle, each of which will be rendered into a tree.
- line 1089 converts that intermediate datastructure into the OSG code to actually render the trees.
How to grow trees in WS3.0
As noted above, one of the key differences between the old scenery and WS3.0 is that a given triangle in the terrain mesh doesn't have a single landclass. Instead we need to look it up.
- simgear/simgear/scene/tgdb/VPBTechnique.cxx is used to create the mesh from the heightmap.
- The key function is VPBTechnique::init. At present this creates a BufferData containing an EffectGeode.
- We (probably?) want to change that so it creates an osg::Group node, which contains both the EffectGeode, plus some other nodes containing the trees and other random objects.
- Because this is already loaded in a PagedLOD, provided we generate this at the right LOD Level (_terrainTile->getTileID().level==6 perhaps? or configurable), we don't need to mess around with any callbacks.
- The landclass information is stored in the first texture, assigned by applyColorLayers().
- It should be possible to interpolate between the texture coordinates of the generated mesh and lookup the landclass of the texture. (osg::Texture2D.getImage()->getColor(const Vec2 &texcoord).
- We could extend the MaterialLibrary to include lookup via landclass code. The simplest way would be to add new <name> values that match the values from the landclass texture as integers. For the hackathon, I suggest just adding landclasses 22-24 to the "EvergreenForest" material.
So the pseudo-code might look like this:
- IF (_terrainTile->getTileID().level==6) THEN
- FOREACH triangle (geometry) :
- Generate a set of random points on the triangle
- FOREACH point (random points) :
- Determine the texture coordinate of the point
- Determine the landclass of the point in the texture
- Lookup the landclass in the MaterialsLibrary
- IF the landclass has mat->get_wood_coverage() > 0 THEN add the point to an appropriate TreeBin in an SGTreeBinList
- use the SGTileDetailsCallback::createForest() method to create the appropriate forest in OSG