WS30: Improved material atlas
Add - texture size - shininess - diffuse - specular from material.xml into the fragment shader via sampler1D.
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user