WS30: Improved material atlas

Add
- texture size
- shininess
- diffuse
- specular

from material.xml into the fragment shader via sampler1D.
This commit is contained in:
Stuart Buchanan
2020-12-08 21:12:01 +00:00
parent 915982de85
commit 8954a54e2e
8 changed files with 101 additions and 54 deletions

View File

@@ -45,6 +45,7 @@ class StateSet;
}
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/threads/SGThread.hxx> // for SGMutex
#include <simgear/math/SGLimits.hxx>
#include <simgear/math/SGMisc.hxx>
@@ -326,6 +327,15 @@ public:
*/
inline double get_cos_tree_zero_density_slope_angle () const { return cos_tree_zero_density_slope_angle; }
/**
* Get the various colour attributes
*/
inline osg::Vec4 get_ambient() const { return toOsg(ambient); }
inline osg::Vec4 get_diffuse() const { return toOsg(diffuse); }
inline osg::Vec4 get_specular() const { return toOsg(specular); }
inline osg::Vec4 get_emission() const { return toOsg(emission); }
inline double get_shininess() const { return shininess; }
/**
* Get the list of names for this material
*/

View File

@@ -306,8 +306,7 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
{
SG_LOG(SG_TERRAIN, SG_DEBUG, "Getting Texture Atlas for " << center);
SGMaterialCache::AtlasIndex atlasIndex;
SGMaterialCache::AtlasImage atlasImage;
SGMaterialCache::Atlas atlas;
std::string id;
const_landclass_map_iterator lc_iter = landclasslib.begin();
for (; lc_iter != landclasslib.end(); ++lc_iter) {
@@ -323,19 +322,44 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
// Cache lookup failure - generate a new atlas, but only if we have a change of reading any textures
if (options == 0) {
return SGMaterialCache::Atlas(atlasIndex, atlasImage);
return atlas;
}
atlasImage = new osg::Texture2DArray();
atlas.image = new osg::Texture2DArray();
atlasImage->setMaxAnisotropy(16.0f);
atlasImage->setResizeNonPowerOfTwoHint(false);
osg::ref_ptr<osg::Image> dimensionImage = new osg::Image();
dimensionImage->allocateImage(512, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE);
atlas.dimensions = new osg::Texture1D(dimensionImage.get());
atlas.dimensions->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
atlas.dimensions->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
atlas.dimensions->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP);
atlas.dimensions->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP);
atlasImage->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST);
atlasImage->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST);
atlasImage->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT);
atlasImage->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT);
osg::ref_ptr<osg::Image> diffuseImage = new osg::Image();
diffuseImage->allocateImage(512, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE);
atlas.diffuse = new osg::Texture1D(diffuseImage.get());
atlas.diffuse->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
atlas.diffuse->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
atlas.diffuse->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP);
atlas.diffuse->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP);
osg::ref_ptr<osg::Image> specularImage = new osg::Image();
specularImage->allocateImage(512, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE);
atlas.specular = new osg::Texture1D(specularImage.get());
atlas.specular->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
atlas.specular->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
atlas.specular->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP);
atlas.specular->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP);
atlas.image->setMaxAnisotropy(16.0f);
atlas.image->setResizeNonPowerOfTwoHint(false);
atlas.image->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST);
atlas.image->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST);
atlas.image->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT);
atlas.image->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT);
int index = -1;
lc_iter = landclasslib.begin();
@@ -345,19 +369,13 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
++index;
int i = lc_iter->first;
SGMaterial* mat = find(lc_iter->second, center);
atlasIndex[i] = index;
SG_LOG(SG_TERRAIN, SG_DEBUG, " Lookup " << i << " " << lc_iter->second);
atlas.index[i] = index;
if (mat == NULL) continue;
SG_LOG(SG_TERRAIN, SG_DEBUG, " Found it!");
// Just get the first texture in the first texture-set for the moment.
// Should add some variability in texture-set in the future.
const std::string texture = mat->get_one_texture(0,0);
if (texture.empty()) continue;
SGPath texturePath = SGPath("Textures");
@@ -375,14 +393,24 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
if (subtexture && subtexture->valid()) {
subtexture->scaleImage(2048,2048,1);
SG_LOG(SG_TERRAIN, SG_ALERT, "Adding image " << fullPath << " to texture atlas " << subtexture->getInternalTextureFormat());
atlasImage->setImage(index,subtexture);
// Add other useful information, such as the texture size in m.
// As we pack the texture size into a texture, we need to scale to [0..1.0]
float x_size = (0 < mat->get_xsize()) ? mat->get_xsize()/10000.0 : 0.1f;
float y_size = (0 < mat->get_ysize()) ? mat->get_ysize()/10000.0 : 0.1f;
SG_LOG(SG_TERRAIN, SG_DEBUG, "Adding image " << fullPath << " to texture atlas " << x_size << " " << y_size);
atlas.image->setImage(index,subtexture);
atlas.dimensions->getImage()->setColor(osg::Vec4(x_size, y_size, mat->get_shininess(), 1.0f), index);
atlas.diffuse->getImage()->setColor(mat->get_diffuse(), index);
atlas.specular->getImage()->setColor(mat->get_specular(), index);
}
}
}
// Cache for future lookups
SGMaterialCache::Atlas atlas = SGMaterialCache::Atlas(atlasIndex, atlasImage);
_atlasCache[id] = atlas;
return atlas;
}

View File

@@ -31,6 +31,7 @@
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <osg/Texture2DArray>
#include <osg/Texture1D>
#include <memory>
#include <string> // Standard C++ string library
@@ -49,11 +50,18 @@ class SGMaterialCache : public osg::Referenced
{
public:
// An atlas, consisting of a landclass index and an atlas image
// An atlas, consisting of a landclass index, an atlas image and set
// of texture1D containing further data
typedef std::map<int, int> AtlasIndex;
typedef osg::ref_ptr<osg::Texture2DArray> AtlasImage;
typedef std::pair<AtlasIndex, AtlasImage> Atlas;
typedef struct {
AtlasIndex index;
AtlasImage image;
osg::ref_ptr<osg::Texture1D> dimensions;
osg::ref_ptr<osg::Texture1D> diffuse;
osg::ref_ptr<osg::Texture1D> specular;
} Atlas;
// Constructor
SGMaterialCache (Atlas atlas);
@@ -66,8 +74,7 @@ public:
SGMaterial *find( const std::string& material ) const;
SGMaterial *find( int material ) const;
AtlasIndex getAtlasIndex() { return _atlas.first; };
AtlasImage getAtlasImage() { return _atlas.second; };
Atlas getAtlas() { return _atlas; };
// Destructor
~SGMaterialCache ( void );
@@ -137,8 +144,8 @@ public:
* cache of the valid materials based on the current state and a given position.
*/
SGMaterialCache *generateMatCache( SGVec2f center, const simgear::SGReaderWriterOptions* options=0);
SGMaterialCache *generateMatCache( SGGeod center, const simgear::SGReaderWriterOptions* options=0);
SGMaterialCache *generateMatCache( SGVec2f center, const simgear::SGReaderWriterOptions* options);
SGMaterialCache *generateMatCache( SGGeod center, const simgear::SGReaderWriterOptions* options);
material_map_iterator begin() { return matlib.begin(); }
const_material_map_iterator begin() const { return matlib.begin(); }

View File

@@ -354,7 +354,7 @@ ref_ptr<Node> instantiateMaterialEffects(osg::Node* modelGroup,
if (options->getMaterialLib()) {
const SGGeod loc = SGGeod(options->getLocation());
SGMaterialCache* matcache = options->getMaterialLib()->generateMatCache(loc);
SGMaterialCache* matcache = options->getMaterialLib()->generateMatCache(loc, options);
SGMaterial* mat = matcache->find(options->getMaterialName());
delete matcache;

View File

@@ -279,7 +279,7 @@ osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib, int latPoints,
double tex_width = 1000.0;
// find Ocean material in the properties list
SGMaterialCache* matcache = matlib->generateMatCache(b.get_center());
SGMaterialCache* matcache = matlib->generateMatCache(b.get_center(), 0);
SGMaterial* mat = matcache->find( "Ocean" );
delete matcache;

View File

@@ -114,7 +114,7 @@ public:
matlib = _options->getMaterialLib();
if (matlib) {
SGGeod geodPos = SGGeod::fromCart(_gbs_center);
matcache = matlib->generateMatCache(geodPos);
matcache = matlib->generateMatCache(geodPos, _options);
}
#if 0
@@ -281,7 +281,7 @@ public:
// Generate a materials cache
if (matlib) {
matcache = matlib->generateMatCache(geodPos);
matcache = matlib->generateMatCache(geodPos, _options);
}
// rotate the tiles so that the bounding boxes get nearly axis aligned.

View File

@@ -799,7 +799,7 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator,
const SGVec3d world2 = SGVec3d(world.x(), world.y(), world.z());
const SGGeod loc = SGGeod::fromCart(world2);
SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc);
SGMaterialCache* matcache = _options->getMaterialLib()->generateMatCache(loc);
SGMaterialCache* matcache = _options->getMaterialLib()->generateMatCache(loc, _options);
SGMaterial* mat = matcache->find("ws30");
delete matcache;
@@ -1337,17 +1337,19 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator,
// Tile-specific information for the shaders
osg::StateSet *ss = buffer._geode->getOrCreateStateSet();
osg::ref_ptr<osg::Uniform> level = new osg::Uniform("tile_level", _terrainTile->getTileID().level);
level->setDataVariance(osg::Object::STATIC);
ss->addUniform(level);
// Determine the x and y texture scaling. Has to be performed after we've generated all the vertices.
// Because the earth is round, each tile is not a rectangle. Apart from edge cases like the poles, the
// difference in axis length is < 1%, so we will just take the average.
// Note that we can ignore the actual texture coordinates as we know from above that they are always
// [0..1.0] [0..1.0] across the entire tile.
osg::Vec3f bottom_left, bottom_right, top_left, top_right;
bool got_bl = VNG.vertex(0, 0, bottom_left);
bool got_br = VNG.vertex(0, VNG._numColumns - 1, bottom_right);
bool got_tl = VNG.vertex(VNG._numColumns - 1, 0, top_left);
bool got_tr = VNG.vertex(VNG._numColumns - 1, VNG._numRows -1, top_right);
float tile_width = 1.0;
float tile_height = 1.0;
if (got_bl && got_br && got_tl && got_tr) {
@@ -1359,14 +1361,11 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator,
tile_height = 0.5 * (t.length() + v.length());
}
//SG_LOG(SG_TERRAIN, SG_ALERT, "Tile Level " << _terrainTile->getTileID().level << " width " << tile_width << " height " << tile_height);
SG_LOG(SG_TERRAIN, SG_DEBUG, "Tile Level " << _terrainTile->getTileID().level << " width " << tile_width << " height " << tile_height);
osg::ref_ptr<osg::Uniform> twu = new osg::Uniform("tile_width", tile_width);
twu->setDataVariance(osg::Object::STATIC);
ss->addUniform(twu);
osg::ref_ptr<osg::Uniform> thu = new osg::Uniform("tile_height", tile_height);
thu->setDataVariance(osg::Object::STATIC);
ss->addUniform(thu);
// Force build of KD trees?
@@ -1385,10 +1384,12 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator,
void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
{
typedef std::map<osgTerrain::Layer*, osg::Texture*> LayerToTextureMap;
typedef std::map<osgTerrain::Layer*, osg::Texture2DArray*> LayerToAtlasMap;
LayerToTextureMap layerToTextureMap;
typedef std::map<osgTerrain::Layer*, SGMaterialCache::Atlas> LayerToAtlasMap;
typedef std::map<osgTerrain::Layer*, osg::ref_ptr<osg::Texture2D>> LayerToTexture2DMap;
typedef std::map<osgTerrain::Layer*, osg::ref_ptr<osg::Texture1D>> LayerToTexture1DMap;
LayerToAtlasMap layerToAtlasMap;
LayerToTexture2DMap layerToTextureMap;
LayerToTexture1DMap layerToContourMap;
for(unsigned int layerNum=0; layerNum<_terrainTile->getNumColorLayers(); ++layerNum)
{
@@ -1413,15 +1414,17 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(colorLayer);
osgTerrain::ContourLayer* contourLayer = dynamic_cast<osgTerrain::ContourLayer*>(colorLayer);
SGMaterialCache::Atlas atlas = layerToAtlasMap[colorLayer];
if (imageLayer)
{
osg::StateSet* stateset = buffer._geode->getOrCreateStateSet();
osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(layerToTextureMap[colorLayer]);
osg::Texture2DArray* atlasTexture = dynamic_cast<osg::Texture2DArray*>(layerToAtlasMap[colorLayer]);
osg::ref_ptr<osg::Texture2D> texture2D = layerToTextureMap[colorLayer];
SGMaterialCache::Atlas atlas = layerToAtlasMap[colorLayer];
if (!texture2D)
{
texture2D = new osg::Texture2D;
texture2D = new osg::Texture2D;
// First time generating this texture, so process to change landclass IDs to texure indexes.
SGPropertyNode_ptr effectProp;
@@ -1441,9 +1444,8 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
if (_matcache ==0) _matcache = _options->getMaterialLib()->generateMatCache(loc, _options);
atlasTexture = _matcache->getAtlasImage();
layerToAtlasMap[colorLayer] = atlasTexture;
SGMaterialCache::AtlasIndex atlasIndex = _matcache->getAtlasIndex();
atlas = _matcache->getAtlas();
SGMaterialCache::AtlasIndex atlasIndex = atlas.index;
for (int s = 0; s < image->s(); s++) {
for (int t = 0; t < image->t(); t++) {
@@ -1476,20 +1478,21 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
}
layerToTextureMap[colorLayer] = texture2D;
layerToAtlasMap[colorLayer] = atlas;
}
stateset->setTextureAttributeAndModes(2*layerNum, texture2D, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(2*layerNum +1, atlasTexture, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(5*layerNum, texture2D, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(5*layerNum + 1, atlas.image, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(5*layerNum + 2, atlas.dimensions, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(5*layerNum + 3, atlas.diffuse, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(5*layerNum + 4, atlas.specular, osg::StateAttribute::ON);
}
else if (contourLayer)
{
osg::StateSet* stateset = buffer._geode->getOrCreateStateSet();
osg::Texture1D* texture1D = dynamic_cast<osg::Texture1D*>(layerToTextureMap[colorLayer]);
osg::ref_ptr< osg::Texture1D> texture1D = layerToContourMap[colorLayer];
if (!texture1D)
{
texture1D = new osg::Texture1D;
@@ -1498,11 +1501,10 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter());
layerToTextureMap[colorLayer] = texture1D;
layerToContourMap[colorLayer] = texture1D;
}
stateset->setTextureAttributeAndModes(layerNum, texture1D, osg::StateAttribute::ON);
}
}
}

View File

@@ -85,7 +85,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
SGGeod geodPos = SGGeod::fromCart(center);
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
if (matlib)
matcache = matlib->generateMatCache(geodPos);
matcache = matlib->generateMatCache(geodPos, options);
std::vector<SGVec3d> nodes = tile.get_wgs84_nodes();