WS30: Texture array texture lookup for landclass
- Create a Texture2DArray for a MaterialCache - Adjust the landclass image to index into the above array - Add the array to as a Uniform for rendering.
This commit is contained in:
parent
02cf42359d
commit
8641d3616a
@ -496,6 +496,28 @@ osg::Texture2D* SGMaterial::get_one_object_mask(int texIndex)
|
||||
}
|
||||
}
|
||||
|
||||
std::string SGMaterial::get_one_texture(int setIndex, int texIndex)
|
||||
{
|
||||
if (_status.empty()) {
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "No material available.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int i = setIndex % _status.size();
|
||||
|
||||
SGMaterial::_internal_state st = _status[i];
|
||||
//if (st == NULL) return 0;
|
||||
|
||||
std::string texturePath = "";
|
||||
|
||||
auto iter = st.texture_paths.begin();
|
||||
for (; iter != st.texture_paths.end(); ++iter) {
|
||||
if (iter->second == texIndex) texturePath = iter->first;
|
||||
}
|
||||
|
||||
return texturePath;
|
||||
}
|
||||
|
||||
void SGMaterial::buildEffectProperties(const SGReaderWriterOptions* options)
|
||||
{
|
||||
using namespace osg;
|
||||
|
@ -141,6 +141,11 @@ public:
|
||||
*/
|
||||
osg::Texture2D* get_one_object_mask(int texIndex);
|
||||
|
||||
/**
|
||||
* Get the textured state.
|
||||
*/
|
||||
std::string get_one_texture(int setIndex, int texIndex);
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of textures assigned to this material.
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
@ -41,7 +41,9 @@
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/scene/model/modellib.hxx>
|
||||
#include <simgear/scene/tgdb/userdata.hxx>
|
||||
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||
|
||||
#include "mat.hxx"
|
||||
|
||||
@ -50,6 +52,7 @@
|
||||
#include "matlib.hxx"
|
||||
|
||||
using std::string;
|
||||
using namespace simgear;
|
||||
|
||||
class SGMaterialLib::MatLibPrivate
|
||||
{
|
||||
@ -217,9 +220,11 @@ SGMaterial *SGMaterialLib::find( int lc, const SGGeod& center ) const
|
||||
}
|
||||
}
|
||||
|
||||
SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center)
|
||||
SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center, const simgear::SGReaderWriterOptions* options)
|
||||
{
|
||||
SGMaterialCache* newCache = new SGMaterialCache();
|
||||
|
||||
|
||||
SGMaterialCache* newCache = new SGMaterialCache(getMaterialTextureAtlas(center, options));
|
||||
material_map::const_reverse_iterator it = matlib.rbegin();
|
||||
for (; it != matlib.rend(); ++it) {
|
||||
newCache->insert(it->first, find(it->first, center));
|
||||
@ -234,10 +239,10 @@ SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center)
|
||||
return newCache;
|
||||
}
|
||||
|
||||
SGMaterialCache *SGMaterialLib::generateMatCache(SGGeod center)
|
||||
SGMaterialCache *SGMaterialLib::generateMatCache(SGGeod center, const simgear::SGReaderWriterOptions* options)
|
||||
{
|
||||
SGVec2f c = SGVec2f(center.getLongitudeDeg(), center.getLatitudeDeg());
|
||||
return SGMaterialLib::generateMatCache(c);
|
||||
return SGMaterialLib::generateMatCache(c, options);
|
||||
}
|
||||
|
||||
|
||||
@ -265,8 +270,9 @@ const SGMaterial *SGMaterialLib::findMaterial(const osg::Geode* geode)
|
||||
}
|
||||
|
||||
// Constructor
|
||||
SGMaterialCache::SGMaterialCache ( void )
|
||||
SGMaterialCache::SGMaterialCache (Atlas atlas)
|
||||
{
|
||||
_atlas = atlas;
|
||||
}
|
||||
|
||||
// Insertion into the material cache
|
||||
@ -295,6 +301,92 @@ SGMaterial *SGMaterialCache::find(int lc) const
|
||||
return find(getNameFromLandclass(lc));
|
||||
}
|
||||
|
||||
// Generate a texture atlas for this location
|
||||
SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, const simgear::SGReaderWriterOptions* options)
|
||||
{
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Getting Texture Atlas for " << center);
|
||||
|
||||
SGMaterialCache::AtlasIndex atlasIndex;
|
||||
SGMaterialCache::AtlasImage atlasImage;
|
||||
std::string id;
|
||||
const_landclass_map_iterator lc_iter = landclasslib.begin();
|
||||
for (; lc_iter != landclasslib.end(); ++lc_iter) {
|
||||
SGMaterial* mat = find(lc_iter->second, center);
|
||||
const std::string texture = mat->get_one_texture(0,0);
|
||||
id.append(texture);
|
||||
id.append(";");
|
||||
}
|
||||
|
||||
SGMaterialLib::atlas_map::iterator atlas_iter = _atlasCache.find(id);
|
||||
|
||||
if (atlas_iter != _atlasCache.end()) return atlas_iter->second;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
atlasImage = new osg::Texture2DArray();
|
||||
|
||||
atlasImage->setMaxAnisotropy(16.0f);
|
||||
atlasImage->setResizeNonPowerOfTwoHint(false);
|
||||
|
||||
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);
|
||||
|
||||
int index = -1;
|
||||
lc_iter = landclasslib.begin();
|
||||
for (; lc_iter != landclasslib.end(); ++lc_iter) {
|
||||
// index is incremented at the start of the loop so that we have a valid
|
||||
// mapping based on the lanclassList, even if we fail to process the texture.
|
||||
++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);
|
||||
|
||||
|
||||
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");
|
||||
//texturePath.append(texture);
|
||||
std::string fullPath = SGModelLib::findDataFile(texture, options, texturePath);
|
||||
|
||||
if (fullPath.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find texture \""
|
||||
<< texture << "\" in Textures folders when creating texture atlas");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the texture into the atlas in the appropriate place
|
||||
osg::ref_ptr<osg::Image> subtexture = osgDB::readRefImageFile(fullPath, options);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache for future lookups
|
||||
SGMaterialCache::Atlas atlas = SGMaterialCache::Atlas(atlasIndex, atlasImage);
|
||||
_atlasCache[id] = atlas;
|
||||
return atlas;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
SGMaterialCache::~SGMaterialCache ( void ) {
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
|
||||
|
@ -27,9 +27,10 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <osg/Texture2DArray>
|
||||
|
||||
#include <memory>
|
||||
#include <string> // Standard C++ string library
|
||||
@ -40,23 +41,22 @@ class SGMaterial;
|
||||
class SGPropertyNode;
|
||||
class SGPath;
|
||||
|
||||
namespace simgear { class Effect; }
|
||||
namespace simgear { class Effect; class SGReaderWriterOptions; }
|
||||
namespace osg { class Geode; }
|
||||
|
||||
// Material cache class
|
||||
class SGMaterialCache : public osg::Referenced
|
||||
{
|
||||
private:
|
||||
typedef std::map < std::string, SGSharedPtr<SGMaterial> > material_cache;
|
||||
material_cache cache;
|
||||
|
||||
const std::string getNameFromLandclass(int lc) const {
|
||||
return std::string("WS30_").append(std::to_string(lc));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// An atlas, consisting of a landclass index and an atlas image
|
||||
typedef std::map<int, int> AtlasIndex;
|
||||
typedef osg::ref_ptr<osg::Texture2DArray> AtlasImage;
|
||||
|
||||
typedef std::pair<AtlasIndex, AtlasImage> Atlas;
|
||||
|
||||
// Constructor
|
||||
SGMaterialCache ( void );
|
||||
SGMaterialCache (Atlas atlas);
|
||||
|
||||
// Insertion
|
||||
void insert( const std::string& name, SGSharedPtr<SGMaterial> material );
|
||||
@ -66,8 +66,20 @@ public:
|
||||
SGMaterial *find( const std::string& material ) const;
|
||||
SGMaterial *find( int material ) const;
|
||||
|
||||
AtlasIndex getAtlasIndex() { return _atlas.first; };
|
||||
AtlasImage getAtlasImage() { return _atlas.second; };
|
||||
|
||||
// Destructor
|
||||
~SGMaterialCache ( void );
|
||||
|
||||
private:
|
||||
typedef std::map < std::string, SGSharedPtr<SGMaterial> > material_cache;
|
||||
material_cache cache;
|
||||
Atlas _atlas;
|
||||
|
||||
const std::string getNameFromLandclass(int lc) const {
|
||||
return std::string("WS30_").append(std::to_string(lc));
|
||||
}
|
||||
};
|
||||
|
||||
// Material management class
|
||||
@ -92,7 +104,13 @@ private:
|
||||
|
||||
material_map matlib;
|
||||
landclass_map landclasslib;
|
||||
|
||||
typedef std::map < std::string, SGMaterialCache::Atlas > atlas_map;
|
||||
atlas_map _atlasCache;
|
||||
|
||||
// Get a (cached) texture atlas for this material cache
|
||||
SGMaterialCache::Atlas getMaterialTextureAtlas(SGVec2f center, const simgear::SGReaderWriterOptions* options);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
@ -119,8 +137,8 @@ public:
|
||||
* cache of the valid materials based on the current state and a given position.
|
||||
*/
|
||||
|
||||
SGMaterialCache *generateMatCache( SGVec2f center);
|
||||
SGMaterialCache *generateMatCache( SGGeod center);
|
||||
SGMaterialCache *generateMatCache( SGVec2f center, const simgear::SGReaderWriterOptions* options=0);
|
||||
SGMaterialCache *generateMatCache( SGGeod center, const simgear::SGReaderWriterOptions* options=0);
|
||||
|
||||
material_map_iterator begin() { return matlib.begin(); }
|
||||
const_material_map_iterator begin() const { return matlib.begin(); }
|
||||
|
@ -55,7 +55,6 @@ typedef std::list<SGDirectionalLightBin> SGDirectionalLightListBin;
|
||||
#define SG_SIMPLIFIER_RATIO (0.001)
|
||||
#define SG_SIMPLIFIER_MAX_LENGTH (1000.0)
|
||||
#define SG_SIMPLIFIER_MAX_ERROR (2000.0)
|
||||
#define SG_TILE_MIN_EXPIRY (180.0)
|
||||
using namespace simgear;
|
||||
|
||||
// QuadTreeBuilder is used by Random Objects Generator
|
||||
|
@ -16,6 +16,8 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <osgTerrain/TerrainTile>
|
||||
#include <osgTerrain/Terrain>
|
||||
|
||||
@ -25,6 +27,7 @@
|
||||
|
||||
#include <osg/io_utils>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/Texture2DArray>
|
||||
#include <osg/Texture1D>
|
||||
#include <osg/Program>
|
||||
#include <osg/Math>
|
||||
@ -151,14 +154,14 @@ void VPBTechnique::init(int dirtyMask, bool assumeMultiThreaded)
|
||||
}
|
||||
else
|
||||
{
|
||||
applyColorLayers(*buffer);
|
||||
applyColorLayers(*buffer, masterLocator);
|
||||
applyTransparency(*buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
generateGeometry(*buffer, masterLocator, centerModel);
|
||||
applyColorLayers(*buffer);
|
||||
applyColorLayers(*buffer, masterLocator);
|
||||
applyTransparency(*buffer);
|
||||
}
|
||||
|
||||
@ -1356,7 +1359,7 @@ 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_ALERT, "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);
|
||||
@ -1380,10 +1383,12 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator,
|
||||
}
|
||||
}
|
||||
|
||||
void VPBTechnique::applyColorLayers(BufferData& buffer)
|
||||
{
|
||||
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;
|
||||
LayerToAtlasMap layerToAtlasMap;
|
||||
|
||||
for(unsigned int layerNum=0; layerNum<_terrainTile->getNumColorLayers(); ++layerNum)
|
||||
{
|
||||
@ -1413,15 +1418,50 @@ void VPBTechnique::applyColorLayers(BufferData& buffer)
|
||||
osg::StateSet* stateset = buffer._geode->getOrCreateStateSet();
|
||||
|
||||
osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(layerToTextureMap[colorLayer]);
|
||||
osg::Texture2DArray* atlasTexture = dynamic_cast<osg::Texture2DArray*>(layerToAtlasMap[colorLayer]);
|
||||
if (!texture2D)
|
||||
{
|
||||
texture2D = new osg::Texture2D;
|
||||
|
||||
// First time generating this texture, so process to change landclass IDs to texure indexes.
|
||||
SGPropertyNode_ptr effectProp;
|
||||
SGMaterialLibPtr matlib = _options->getMaterialLib();
|
||||
osg::Vec3d world;
|
||||
SGGeod loc;
|
||||
|
||||
if (matlib)
|
||||
{
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Generating texture atlas for " << image->getName());
|
||||
// Determine the center of the tile, sadly non-trivial.
|
||||
osg::Vec3d tileloc = computeCenter(buffer, masterLocator);
|
||||
masterLocator->convertLocalToModel(tileloc, world);
|
||||
const SGVec3d world2 = SGVec3d(world.x(), world.y(), world.z());
|
||||
loc = SGGeod::fromCart(world2);
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc);
|
||||
|
||||
if (_matcache ==0) _matcache = _options->getMaterialLib()->generateMatCache(loc, _options);
|
||||
|
||||
atlasTexture = _matcache->getAtlasImage();
|
||||
layerToAtlasMap[colorLayer] = atlasTexture;
|
||||
SGMaterialCache::AtlasIndex atlasIndex = _matcache->getAtlasIndex();
|
||||
|
||||
for (int s = 0; s < image->s(); s++) {
|
||||
for (int t = 0; t < image->t(); t++) {
|
||||
osg::Vec4 c = image->getColor(s, t);
|
||||
int i = int(round(c.x() * 255.0));
|
||||
c.set(c.x(), (float) (atlasIndex[i] / 255.0), c.z(), c.w() );
|
||||
image->setColor(c, s, t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
texture2D->setImage(image);
|
||||
texture2D->setMaxAnisotropy(16.0f);
|
||||
texture2D->setResizeNonPowerOfTwoHint(false);
|
||||
|
||||
texture2D->setFilter(osg::Texture::MIN_FILTER, colorLayer->getMinFilter());
|
||||
texture2D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter());
|
||||
texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
|
||||
texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
|
||||
|
||||
texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
|
||||
texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);
|
||||
@ -1432,7 +1472,7 @@ void VPBTechnique::applyColorLayers(BufferData& buffer)
|
||||
|
||||
if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo))
|
||||
{
|
||||
OSG_INFO<<"Disabling mipmapping for non power of two tile size("<<image->s()<<", "<<image->t()<<")"<<std::endl;
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Disabling mipmapping for non power of two tile size("<<image->s()<<", "<<image->t()<<")");
|
||||
texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
}
|
||||
|
||||
@ -1441,7 +1481,8 @@ void VPBTechnique::applyColorLayers(BufferData& buffer)
|
||||
|
||||
}
|
||||
|
||||
stateset->setTextureAttributeAndModes(layerNum, texture2D, osg::StateAttribute::ON);
|
||||
stateset->setTextureAttributeAndModes(2*layerNum, texture2D, osg::StateAttribute::ON);
|
||||
stateset->setTextureAttributeAndModes(2*layerNum +1, atlasTexture, osg::StateAttribute::ON);
|
||||
|
||||
}
|
||||
else if (contourLayer)
|
||||
|
@ -107,7 +107,7 @@ class VPBTechnique : public TerrainTechnique
|
||||
|
||||
virtual void generateGeometry(BufferData& buffer, Locator* masterLocator, const osg::Vec3d& centerModel);
|
||||
|
||||
virtual void applyColorLayers(BufferData& buffer);
|
||||
virtual void applyColorLayers(BufferData& buffer, Locator* masterLocator);
|
||||
|
||||
virtual void applyTransparency(BufferData& buffer);
|
||||
|
||||
@ -123,6 +123,8 @@ class VPBTechnique : public TerrainTechnique
|
||||
osg::Matrix3 _filterMatrix;
|
||||
osg::ref_ptr<osg::Uniform> _filterMatrixUniform;
|
||||
osg::ref_ptr<SGReaderWriterOptions> _options;
|
||||
osg::ref_ptr<osg::Image> _atlas;
|
||||
osg::ref_ptr<SGMaterialCache> _matcache;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user