WS30: Improved Atlas encapsulation
This commit is contained in:
parent
2b9a319e76
commit
96a9abfd7a
185
simgear/scene/material/Atlas.cxx
Normal file
185
simgear/scene/material/Atlas.cxx
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
// Atlas.cxx -- class for a material-based texture atlas
|
||||||
|
//
|
||||||
|
// Copyright (C) 2022 Stuart Buchanan
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
#include <osgDB/ReadFile>
|
||||||
|
|
||||||
|
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||||
|
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
||||||
|
|
||||||
|
using namespace simgear;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
Atlas::Atlas(osg::ref_ptr<const SGReaderWriterOptions> options) {
|
||||||
|
|
||||||
|
_options = options;
|
||||||
|
|
||||||
|
_textureLookup1 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_textureLookup1", Atlas::MAX_MATERIALS);
|
||||||
|
_textureLookup2 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_textureLookup2", Atlas::MAX_MATERIALS);
|
||||||
|
_dimensions = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_dimensionsArray", Atlas::MAX_MATERIALS);
|
||||||
|
_ambient = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_ambientArray", Atlas::MAX_MATERIALS);
|
||||||
|
_diffuse = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_diffuseArray", Atlas::MAX_MATERIALS);
|
||||||
|
_specular = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_specularArray", Atlas::MAX_MATERIALS);
|
||||||
|
_materialParams1 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_materialParams1", Atlas::MAX_MATERIALS);
|
||||||
|
_materialParams2 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_materialParams2", Atlas::MAX_MATERIALS);
|
||||||
|
_materialParams3 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_materialParams3", Atlas::MAX_MATERIALS);
|
||||||
|
|
||||||
|
_image = new osg::Texture2DArray();
|
||||||
|
_image->setMaxAnisotropy(SGSceneFeatures::instance()->getTextureFilter());
|
||||||
|
_image->setResizeNonPowerOfTwoHint(false);
|
||||||
|
_image->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT);
|
||||||
|
_image->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT);
|
||||||
|
|
||||||
|
_imageIndex = 0u; // Index into the image
|
||||||
|
_materialLookupIndex = 0u; // Index into the material lookup
|
||||||
|
|
||||||
|
// Add hardcoded atlas images.
|
||||||
|
unsigned int standardTextureCount = size(Atlas::STANDARD_TEXTURES);
|
||||||
|
for (; _imageIndex < standardTextureCount; _imageIndex++) {
|
||||||
|
// Copy the texture into the atlas in the appropriate place
|
||||||
|
osg::ref_ptr<osg::Image> subtexture = osgDB::readRefImageFile(Atlas::STANDARD_TEXTURES[_imageIndex], options);
|
||||||
|
|
||||||
|
if (subtexture && subtexture->valid()) {
|
||||||
|
if ((subtexture->s() != 2048) || (subtexture->t() != 2048)) {
|
||||||
|
subtexture->scaleImage(2048,2048,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_image->setImage(_imageIndex,subtexture);
|
||||||
|
_textureMap[Atlas::STANDARD_TEXTURES[_imageIndex]] = _imageIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Atlas::addMaterial(int landclass, bool isWater, SGMaterial* mat) {
|
||||||
|
|
||||||
|
_index[landclass] = _materialLookupIndex;
|
||||||
|
_waterAtlas[landclass] = isWater;
|
||||||
|
unsigned int textureList[Atlas::MAX_TEXTURES];
|
||||||
|
|
||||||
|
if (mat != NULL) {
|
||||||
|
|
||||||
|
if (mat->get_num_textures(0) > Atlas::MAX_TEXTURES) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Unable to build texture atlas for landclass "
|
||||||
|
<< landclass << " aka " << mat->get_names()[0]
|
||||||
|
<< " too many textures: " << mat->get_num_textures(0)
|
||||||
|
<< " (maximum " << Atlas::MAX_TEXTURES << ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dimensions->setElement(_materialLookupIndex, osg::Vec4f(mat->get_xsize(), mat->get_ysize(), mat->get_shininess(), (double) mat->get_parameter("edge-hardness")));
|
||||||
|
_ambient->setElement(_materialLookupIndex, mat->get_ambient());
|
||||||
|
_diffuse->setElement(_materialLookupIndex, mat->get_diffuse());
|
||||||
|
_specular->setElement(_materialLookupIndex, mat->get_specular());
|
||||||
|
|
||||||
|
// The following are material parameters that are normally built into the Effect as Uniforms. In the WS30
|
||||||
|
// case we need to pass them as an array, indexed against the material.
|
||||||
|
_materialParams1->setElement(_materialLookupIndex, osg::Vec4f(mat->get_parameter("transition_model"), mat->get_parameter("hires_overlay_bias"), mat->get_parameter("grain_strength"), mat->get_parameter("intrinsic_wetness")));
|
||||||
|
_materialParams2->setElement(_materialLookupIndex, osg::Vec4f(mat->get_parameter("dot_density"), mat->get_parameter("dot_size"), mat->get_parameter("dust_resistance"), mat->get_parameter("rock_strata")));
|
||||||
|
|
||||||
|
float water = 0.0;
|
||||||
|
if (_waterAtlas[landclass]) {
|
||||||
|
water = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_materialParams3->setElement(_materialLookupIndex, osg::Vec4f(water, mat->get_parameter("waterline-start"), mat->get_parameter("waterline-end"), 0.0));
|
||||||
|
|
||||||
|
// Similarly, there are specifically 7 textures that are defined in the materials that need to be passed into
|
||||||
|
// the shader as an array based on the material lookup.
|
||||||
|
//
|
||||||
|
// The mapping from terrain-default.eff / terrain-overlay.eff is as follows
|
||||||
|
//
|
||||||
|
// TEXTURE NAME texture-unit Material texture index Default value
|
||||||
|
// Primary texure 0 0 n/a
|
||||||
|
// gradient_texture 2 13 Textures/Terrain/rock_alt.png
|
||||||
|
// dot_texture 3 15 Textures/Terrain/sand6.png
|
||||||
|
// grain_texture 4 14 Textures/Terrain/grain_texture.png
|
||||||
|
// mix_texture 5 12 Textures/Terrain/void.png
|
||||||
|
// detail_texture 7 11 Textures/Terrain/void.png
|
||||||
|
// overlayPrimaryTex 7 20 Textures/Terrain/void.png
|
||||||
|
// overlaySecondaryTex 8 21 Textures/Terrain/void.png
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < Atlas::MAX_TEXTURES; i++) {
|
||||||
|
std::string texture = mat->get_one_texture(0,i);
|
||||||
|
|
||||||
|
if (texture.empty()) {
|
||||||
|
// This is a rather horrible hardcoded mapping of the default textures defined in
|
||||||
|
// terrain-default.eff and terrain-overlay.eff which are in effect defaults to
|
||||||
|
// the material definitions
|
||||||
|
if (i < 13) texture = std::string("Textures/Terrain/void.png");
|
||||||
|
if (i == 13) texture = std::string("Textures/Terrain/rock_alt.png");
|
||||||
|
if (i == 14) texture = std::string("Textures/Terrain/grain_texture.png");
|
||||||
|
if (i == 15) texture = std::string("Textures/Terrain/sand6.png");
|
||||||
|
if (i > 14) texture = std::string("Textures/Terrain/void.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
SGPath texturePath = SGPath("Textures");
|
||||||
|
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");
|
||||||
|
texture = std::string("Textures/Terrain/void.png");
|
||||||
|
fullPath = SGModelLib::findDataFile(texture, _options, texturePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_textureMap.find(fullPath) == _textureMap.end()) {
|
||||||
|
// Add any missing textures into the atlas image
|
||||||
|
// Copy the texture into the atlas in the appropriate place
|
||||||
|
osg::ref_ptr<osg::Image> subtexture = osgDB::readRefImageFile(fullPath, _options);
|
||||||
|
|
||||||
|
if (subtexture && subtexture->valid()) {
|
||||||
|
|
||||||
|
if ((subtexture->s() != 2048) || (subtexture->t() != 2048)) {
|
||||||
|
subtexture->scaleImage(2048,2048,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_image->setImage(_imageIndex,subtexture);
|
||||||
|
_textureMap[fullPath] = _imageIndex;
|
||||||
|
++_imageIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we know that the texture is present in the
|
||||||
|
// atlas and referenced in the textureMap, so add it to the materialLookup
|
||||||
|
textureList[i] = _textureMap[fullPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now have a textureList containing the full set of textures. Pack the relevant ones into the Vec4 of the index Uniform.
|
||||||
|
// This is a bit of a hack to maintain compatibility with the WS2.0 material definitions, as the material definitions use the
|
||||||
|
// 11-15th textures for the various overlay textures for terrain-default.eff, we do the same for ws30.eff
|
||||||
|
_textureLookup1->setElement(_materialLookupIndex, osg::Vec4f( (float) (textureList[0] / 255.0), (float) (textureList[11] / 255.0), (float) (textureList[12] / 255.0), (float) (textureList[13] / 255.0)));
|
||||||
|
_textureLookup2->setElement(_materialLookupIndex, osg::Vec4f( (float) (textureList[14] / 255.0), (float) (textureList[15] / 255.0), (float) (textureList[20] / 255.0), (float) (textureList[21] / 255.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
++_materialLookupIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Atlas::addUniforms(osg::StateSet* stateset) {
|
||||||
|
stateset->addUniform(_dimensions);
|
||||||
|
stateset->addUniform(_ambient);
|
||||||
|
stateset->addUniform(_diffuse);
|
||||||
|
stateset->addUniform(_specular);
|
||||||
|
stateset->addUniform(_textureLookup1);
|
||||||
|
stateset->addUniform(_textureLookup2);
|
||||||
|
stateset->addUniform(_materialParams1);
|
||||||
|
stateset->addUniform(_materialParams2);
|
||||||
|
stateset->addUniform(_materialParams3);
|
||||||
|
}
|
||||||
|
|
114
simgear/scene/material/Atlas.hxx
Normal file
114
simgear/scene/material/Atlas.hxx
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Atlas.hxx -- class for a material-based texture atlas
|
||||||
|
//
|
||||||
|
// Copyright (C) 2022 Stuart Buchanan
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
#include <simgear/scene/material/mat.hxx>
|
||||||
|
#include <osg/Texture2DArray>
|
||||||
|
#include <osg/Texture1D>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string> // Standard C++ string library
|
||||||
|
#include <map> // STL associative "array"
|
||||||
|
#include <vector> // STL "array"
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
|
||||||
|
// Atlas of textures
|
||||||
|
class Atlas : public osg::Referenced
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
Atlas (osg::ref_ptr<const SGReaderWriterOptions> options );
|
||||||
|
|
||||||
|
// Mapping of landclass numbers to indexes within the atlas
|
||||||
|
// materialLookup
|
||||||
|
typedef std::map<int, int> AtlasIndex;
|
||||||
|
|
||||||
|
// Mapping of texture filenames to their index in the Atlas image itself.
|
||||||
|
typedef std::map<std::string, unsigned int> TextureMap;
|
||||||
|
|
||||||
|
// The Texture array itself
|
||||||
|
typedef osg::ref_ptr<osg::Texture2DArray> AtlasImage;
|
||||||
|
typedef std::map<int, bool> WaterAtlas;
|
||||||
|
|
||||||
|
void addUniforms(osg::StateSet* stateset);
|
||||||
|
void addMaterial(int landclass, bool water, SGMaterial* mat);
|
||||||
|
|
||||||
|
// Maximum number of material entries in the atlas
|
||||||
|
static const unsigned int MAX_MATERIALS = 64;
|
||||||
|
|
||||||
|
// Lookups into the Atlas from landclass
|
||||||
|
bool isWater(int landclass) { return _waterAtlas[landclass]; };
|
||||||
|
int getIndex(int landclass) { return _index[landclass]; };
|
||||||
|
|
||||||
|
AtlasImage getImage() { return _image; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
AtlasIndex _index;
|
||||||
|
AtlasImage _image;
|
||||||
|
|
||||||
|
osg::ref_ptr<const SGReaderWriterOptions> _options;
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Uniform> _textureLookup1;
|
||||||
|
osg::ref_ptr<osg::Uniform> _textureLookup2;
|
||||||
|
osg::ref_ptr<osg::Uniform> _dimensions;
|
||||||
|
osg::ref_ptr<osg::Uniform> _ambient;
|
||||||
|
osg::ref_ptr<osg::Uniform> _diffuse;
|
||||||
|
osg::ref_ptr<osg::Uniform> _specular;
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Uniform> _materialParams1;
|
||||||
|
osg::ref_ptr<osg::Uniform> _materialParams2;
|
||||||
|
osg::ref_ptr<osg::Uniform> _materialParams3;
|
||||||
|
|
||||||
|
unsigned int _imageIndex; // Index into the image
|
||||||
|
unsigned int _materialLookupIndex; // Index into the material lookup
|
||||||
|
|
||||||
|
WaterAtlas _waterAtlas;
|
||||||
|
TextureMap _textureMap;
|
||||||
|
|
||||||
|
// Maximum number of textures per texture-set for the Atlas.
|
||||||
|
static const unsigned int MAX_TEXTURES = 22;
|
||||||
|
|
||||||
|
// Standard textures, used by water shader in particular.
|
||||||
|
// Indexes are hardcoded in Shaders/ws30-water.frag
|
||||||
|
inline static const std::string STANDARD_TEXTURES[] = {
|
||||||
|
"Textures/Terrain/water.png",
|
||||||
|
"Textures/Water/water-reflection-ws30.png",
|
||||||
|
"Textures/Water/waves-ver10-nm-ws30.png",
|
||||||
|
"Textures/Water/water_sine_nmap-ws30.png",
|
||||||
|
"Textures/Water/water-reflection-grey-ws30.png",
|
||||||
|
"Textures/Water/sea_foam-ws30.png",
|
||||||
|
"Textures/Water/perlin-noise-nm.png",
|
||||||
|
|
||||||
|
// The following two textures are large and don't have an alpha channel. Ignoring for now.
|
||||||
|
//"Textures/Globe/ocean_depth_1.png",
|
||||||
|
//"Textures/Globe/globe_colors.jpg",
|
||||||
|
"Textures/Terrain/packice-overlay.png"
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
set(HEADERS
|
set(HEADERS
|
||||||
|
Atlas.hxx
|
||||||
Effect.hxx
|
Effect.hxx
|
||||||
EffectBuilder.hxx
|
EffectBuilder.hxx
|
||||||
EffectCullVisitor.hxx
|
EffectCullVisitor.hxx
|
||||||
@ -14,6 +15,7 @@ set(HEADERS
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
|
Atlas.cxx
|
||||||
Effect.cxx
|
Effect.cxx
|
||||||
EffectBuilder.cxx
|
EffectBuilder.cxx
|
||||||
EffectCullVisitor.cxx
|
EffectCullVisitor.cxx
|
||||||
|
@ -246,10 +246,10 @@ SGMaterial *SGMaterialLib::find( int lc, const SGGeod& center ) const
|
|||||||
SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center, const simgear::SGReaderWriterOptions* options)
|
SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center, const simgear::SGReaderWriterOptions* options)
|
||||||
{
|
{
|
||||||
|
|
||||||
SGMaterialCache* newCache = new SGMaterialCache(getMaterialTextureAtlas(center, options));
|
SGMaterialCache* newCache = new SGMaterialCache();
|
||||||
|
newCache->setAtlas(SGMaterialLib::getOrCreateAtlas(landclasslib, center, options));
|
||||||
|
|
||||||
std::lock_guard<std::mutex> g(d->mutex);
|
std::lock_guard<std::mutex> g(d->mutex);
|
||||||
|
|
||||||
material_map::const_reverse_iterator it = matlib.rbegin();
|
material_map::const_reverse_iterator it = matlib.rbegin();
|
||||||
for (; it != matlib.rend(); ++it) {
|
for (; it != matlib.rend(); ++it) {
|
||||||
newCache->insert(it->first, internalFind(it->first, center));
|
newCache->insert(it->first, internalFind(it->first, center));
|
||||||
@ -295,9 +295,8 @@ const SGMaterial *SGMaterialLib::findMaterial(const osg::Geode* geode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGMaterialCache::SGMaterialCache (Atlas atlas)
|
SGMaterialCache::SGMaterialCache ()
|
||||||
{
|
{
|
||||||
_atlas = atlas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertion into the material cache
|
// Insertion into the material cache
|
||||||
@ -326,14 +325,14 @@ SGMaterial *SGMaterialCache::find(int lc) const
|
|||||||
return find(getNameFromLandclass(lc));
|
return find(getNameFromLandclass(lc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a texture atlas for this location
|
osg::ref_ptr<Atlas> SGMaterialLib::getOrCreateAtlas(SGMaterialLib::landclass_map landclasslib, SGVec2f center, const simgear::SGReaderWriterOptions* const_options) {
|
||||||
SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, const simgear::SGReaderWriterOptions* const_options)
|
|
||||||
{
|
osg::ref_ptr<Atlas> atlas;
|
||||||
SGMaterialCache::Atlas atlas;
|
|
||||||
|
|
||||||
// Non-VPB does not use the Atlas, so save some effort and return
|
// Non-VPB does not use the Atlas, so save some effort and return
|
||||||
if (! SGSceneFeatures::instance()->getVPBActive()) return atlas;
|
if (! SGSceneFeatures::instance()->getVPBActive()) return atlas;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> g(SGMaterialLib::_atlasCacheMutex);
|
||||||
|
|
||||||
// A simple key to the atlas is just the list of textures.
|
// A simple key to the atlas is just the list of textures.
|
||||||
std::string id;
|
std::string id;
|
||||||
const_landclass_map_iterator lc_iter = landclasslib.begin();
|
const_landclass_map_iterator lc_iter = landclasslib.begin();
|
||||||
@ -341,12 +340,11 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
|
|||||||
SGMaterial* mat = find(lc_iter->second.first, center);
|
SGMaterial* mat = find(lc_iter->second.first, center);
|
||||||
const std::string texture = mat->get_one_texture(0,0);
|
const std::string texture = mat->get_one_texture(0,0);
|
||||||
id.append(texture);
|
id.append(texture);
|
||||||
id.append(";");
|
id.append(";");
|
||||||
}
|
}
|
||||||
|
|
||||||
SGMaterialLib::atlas_map::iterator atlas_iter = _atlasCache.find(id);
|
atlas_map::iterator atlas_iter = SGMaterialLib::_atlasCache.find(id);
|
||||||
|
if (atlas_iter != SGMaterialLib::_atlasCache.end()) return atlas_iter->second;
|
||||||
if (atlas_iter != _atlasCache.end()) return atlas_iter->second;
|
|
||||||
|
|
||||||
// Cache lookup failure - generate a new atlas, but only if we have a chance of reading any textures
|
// Cache lookup failure - generate a new atlas, but only if we have a chance of reading any textures
|
||||||
if (const_options == 0) {
|
if (const_options == 0) {
|
||||||
@ -355,172 +353,30 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
|
|||||||
|
|
||||||
osg::ref_ptr<SGReaderWriterOptions> options = SGReaderWriterOptions::copyOrCreate(const_options);
|
osg::ref_ptr<SGReaderWriterOptions> options = SGReaderWriterOptions::copyOrCreate(const_options);
|
||||||
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_MATERIAL_ATLAS);
|
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_MATERIAL_ATLAS);
|
||||||
|
|
||||||
atlas.image = new osg::Texture2DArray();
|
|
||||||
|
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Generating atlas of size " << landclasslib.size());
|
SG_LOG(SG_TERRAIN, SG_DEBUG, "Generating atlas " << (SGMaterialLib::_atlasCache.size() +1) << " of size " << landclasslib.size());
|
||||||
if (landclasslib.size() > SGMaterialCache::MAX_MATERIALS) SG_LOG(SG_TERRAIN, SG_ALERT, "Too many landclass entries for uniform arrays: " << landclasslib.size() << " > " << SGMaterialCache::MAX_MATERIALS);
|
if (landclasslib.size() > Atlas::MAX_MATERIALS) SG_LOG(SG_TERRAIN, SG_ALERT, "Too many landclass entries for uniform arrays: " << landclasslib.size() << " > " << Atlas::MAX_MATERIALS);
|
||||||
|
|
||||||
atlas.textureLookup1 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_textureLookup1", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.textureLookup2 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_textureLookup2", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.dimensions = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_dimensionsArray", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.ambient = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_ambientArray", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.diffuse = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_diffuseArray", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.specular = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_specularArray", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.materialParams1 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_materialParams1", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.materialParams2 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_materialParams2", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
atlas.materialParams3 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_materialParams3", SGMaterialCache::MAX_MATERIALS);
|
|
||||||
|
|
||||||
atlas.image->setMaxAnisotropy(SGSceneFeatures::instance()->getTextureFilter());
|
atlas = new Atlas(options);
|
||||||
atlas.image->setResizeNonPowerOfTwoHint(false);
|
|
||||||
|
|
||||||
atlas.image->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT);
|
|
||||||
atlas.image->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT);
|
|
||||||
|
|
||||||
unsigned int imageIndex = 0u; // Index into the image
|
|
||||||
|
|
||||||
// Add hardcoded atlas images first.
|
|
||||||
unsigned int standardTextureCount = size(SGMaterialCache::STANDARD_TEXTURES);
|
|
||||||
for (; imageIndex < standardTextureCount; imageIndex++) {
|
|
||||||
// Copy the texture into the atlas in the appropriate place
|
|
||||||
osg::ref_ptr<osg::Image> subtexture = osgDB::readRefImageFile(SGMaterialCache::STANDARD_TEXTURES[imageIndex], options);
|
|
||||||
|
|
||||||
if (subtexture && subtexture->valid()) {
|
|
||||||
if ((subtexture->s() != 2048) || (subtexture->t() != 2048)) {
|
|
||||||
subtexture->scaleImage(2048,2048,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
atlas.image->setImage(imageIndex,subtexture);
|
|
||||||
atlas.textureMap[SGMaterialCache::STANDARD_TEXTURES[imageIndex]] = imageIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int materialLookupIndex = 0u; // Index into the material lookup
|
|
||||||
lc_iter = landclasslib.begin();
|
lc_iter = landclasslib.begin();
|
||||||
for (; lc_iter != landclasslib.end(); ++lc_iter) {
|
for (; lc_iter != landclasslib.end(); ++lc_iter) {
|
||||||
|
// Add all the materials to the atlas
|
||||||
int landclass = lc_iter->first;
|
int landclass = lc_iter->first;
|
||||||
|
bool water = lc_iter->second.second;
|
||||||
SGMaterial* mat = find(lc_iter->second.first, center);
|
SGMaterial* mat = find(lc_iter->second.first, center);
|
||||||
atlas.index[landclass] = materialLookupIndex;
|
atlas->addMaterial(landclass, water, mat);
|
||||||
atlas.waterAtlas[landclass] = lc_iter->second.second;
|
|
||||||
unsigned int textureList[SGMaterialCache::MAX_TEXTURES];
|
|
||||||
|
|
||||||
if (mat != NULL) {
|
|
||||||
|
|
||||||
if (mat->get_num_textures(0) > SGMaterialCache::MAX_TEXTURES) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Unable to build texture atlas for landclass "
|
|
||||||
<< landclass << " aka " << mat->get_names()[0]
|
|
||||||
<< " too many textures: " << mat->get_num_textures(0)
|
|
||||||
<< " (maximum " << SGMaterialCache::MAX_TEXTURES << ")");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
atlas.dimensions->setElement(materialLookupIndex, osg::Vec4f(mat->get_xsize(), mat->get_ysize(), mat->get_shininess(), (double) mat->get_parameter("edge-hardness")));
|
|
||||||
atlas.ambient->setElement(materialLookupIndex, mat->get_ambient());
|
|
||||||
atlas.diffuse->setElement(materialLookupIndex, mat->get_diffuse());
|
|
||||||
atlas.specular->setElement(materialLookupIndex, mat->get_specular());
|
|
||||||
|
|
||||||
// The following are material parameters that are normally built into the Effect as Uniforms. In the WS30
|
|
||||||
// case we need to pass them as an array, indexed against the material.
|
|
||||||
atlas.materialParams1->setElement(materialLookupIndex, osg::Vec4f(mat->get_parameter("transition_model"), mat->get_parameter("hires_overlay_bias"), mat->get_parameter("grain_strength"), mat->get_parameter("intrinsic_wetness")));
|
|
||||||
atlas.materialParams2->setElement(materialLookupIndex, osg::Vec4f(mat->get_parameter("dot_density"), mat->get_parameter("dot_size"), mat->get_parameter("dust_resistance"), mat->get_parameter("rock_strata")));
|
|
||||||
|
|
||||||
float water = 0.0;
|
|
||||||
if (atlas.waterAtlas[landclass]) {
|
|
||||||
water = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
atlas.materialParams3->setElement(materialLookupIndex, osg::Vec4f(water, mat->get_parameter("waterline-start"), mat->get_parameter("waterline-end"), 0.0));
|
|
||||||
|
|
||||||
// Similarly, there are specifically 7 textures that are defined in the materials that need to be passed into
|
|
||||||
// the shader as an array based on the material lookup.
|
|
||||||
//
|
|
||||||
// The mapping from terrain-default.eff / terrain-overlay.eff is as follows
|
|
||||||
//
|
|
||||||
// TEXTURE NAME texture-unit Material texture index Default value
|
|
||||||
// Primary texure 0 0 n/a
|
|
||||||
// gradient_texture 2 13 Textures/Terrain/rock_alt.png
|
|
||||||
// dot_texture 3 15 Textures/Terrain/sand6.png
|
|
||||||
// grain_texture 4 14 Textures/Terrain/grain_texture.png
|
|
||||||
// mix_texture 5 12 Textures/Terrain/void.png
|
|
||||||
// detail_texture 7 11 Textures/Terrain/void.png
|
|
||||||
// overlayPrimaryTex 7 20 Textures/Terrain/void.png
|
|
||||||
// overlaySecondaryTex 8 21 Textures/Terrain/void.png
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < SGMaterialCache::MAX_TEXTURES; i++) {
|
|
||||||
std::string texture = mat->get_one_texture(0,i);
|
|
||||||
|
|
||||||
if (texture.empty()) {
|
|
||||||
// This is a rather horrible hardcoded mapping of the default textures defined in
|
|
||||||
// terrain-default.eff and terrain-overlay.eff which are in effect defaults to
|
|
||||||
// the material definitions
|
|
||||||
if (i < 13) texture = std::string("Textures/Terrain/void.png");
|
|
||||||
if (i == 13) texture = std::string("Textures/Terrain/rock_alt.png");
|
|
||||||
if (i == 14) texture = std::string("Textures/Terrain/grain_texture.png");
|
|
||||||
if (i == 15) texture = std::string("Textures/Terrain/sand6.png");
|
|
||||||
if (i > 14) texture = std::string("Textures/Terrain/void.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
SGPath texturePath = SGPath("Textures");
|
|
||||||
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");
|
|
||||||
texture = std::string("Textures/Terrain/void.png");
|
|
||||||
fullPath = SGModelLib::findDataFile(texture, options, texturePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atlas.textureMap.find(fullPath) == atlas.textureMap.end()) {
|
|
||||||
// Add any missing textures into the atlas image
|
|
||||||
// Copy the texture into the atlas in the appropriate place
|
|
||||||
osg::ref_ptr<osg::Image> subtexture = osgDB::readRefImageFile(fullPath, options);
|
|
||||||
|
|
||||||
if (subtexture && subtexture->valid()) {
|
|
||||||
|
|
||||||
if ((subtexture->s() != 2048) || (subtexture->t() != 2048)) {
|
|
||||||
subtexture->scaleImage(2048,2048,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
atlas.image->setImage(imageIndex,subtexture);
|
|
||||||
atlas.textureMap[fullPath] = imageIndex;
|
|
||||||
++imageIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point we know that the texture is present in the
|
|
||||||
// atlas and referenced in the textureMap, so add it to the materialLookup
|
|
||||||
textureList[i] = atlas.textureMap[fullPath];
|
|
||||||
}
|
|
||||||
|
|
||||||
// We now have a textureList containing the full set of textures. Pack the relevant ones into the Vec4 of the index Uniform.
|
|
||||||
// This is a bit of a hack to maintain compatibility with the WS2.0 material definitions, as the material definitions use the
|
|
||||||
// 11-15th textures for the various overlay textures for terrain-default.eff, we do the same for ws30.eff
|
|
||||||
atlas.textureLookup1->setElement(materialLookupIndex, osg::Vec4f( (float) (textureList[0] / 255.0), (float) (textureList[11] / 255.0), (float) (textureList[12] / 255.0), (float) (textureList[13] / 255.0)));
|
|
||||||
atlas.textureLookup2->setElement(materialLookupIndex, osg::Vec4f( (float) (textureList[14] / 255.0), (float) (textureList[15] / 255.0), (float) (textureList[20] / 255.0), (float) (textureList[21] / 255.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
++materialLookupIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache for future lookups
|
SGMaterialLib::_atlasCache[id] = atlas;
|
||||||
_atlasCache[id] = atlas;
|
|
||||||
return atlas;
|
return atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGMaterialCache::addAtlasUniforms(osg::StateSet* stateset) {
|
|
||||||
stateset->addUniform(_atlas.dimensions);
|
|
||||||
stateset->addUniform(_atlas.ambient);
|
|
||||||
stateset->addUniform(_atlas.diffuse);
|
|
||||||
stateset->addUniform(_atlas.specular);
|
|
||||||
stateset->addUniform(_atlas.textureLookup1);
|
|
||||||
stateset->addUniform(_atlas.textureLookup2);
|
|
||||||
stateset->addUniform(_atlas.materialParams1);
|
|
||||||
stateset->addUniform(_atlas.materialParams2);
|
|
||||||
stateset->addUniform(_atlas.materialParams3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
SGMaterialCache::~SGMaterialCache ( void ) {
|
SGMaterialCache::~SGMaterialCache ( void ) {
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initalizer
|
||||||
|
SGMaterialLib::atlas_map SGMaterialLib::_atlasCache;
|
||||||
|
std::mutex SGMaterialLib::_atlasCacheMutex;
|
@ -32,6 +32,7 @@
|
|||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
#include <osg/Texture2DArray>
|
#include <osg/Texture2DArray>
|
||||||
#include <osg/Texture1D>
|
#include <osg/Texture1D>
|
||||||
|
#include "Atlas.hxx"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string> // Standard C++ string library
|
#include <string> // Standard C++ string library
|
||||||
@ -57,60 +58,8 @@ public:
|
|||||||
// represent the textures referenced by the texture-set in the material
|
// represent the textures referenced by the texture-set in the material
|
||||||
// - the texture indexes index into the Atlas itself.
|
// - the texture indexes index into the Atlas itself.
|
||||||
|
|
||||||
// Mapping of landclass numbers to indexes within the atlas
|
|
||||||
// materialLookup
|
|
||||||
typedef std::map<int, int> AtlasIndex;
|
|
||||||
|
|
||||||
// Mapping of texture filenames to their index in the Atlas image itself.
|
|
||||||
typedef std::map<std::string, unsigned int> TextureMap;
|
|
||||||
|
|
||||||
// The Texture array itself
|
|
||||||
typedef osg::ref_ptr<osg::Texture2DArray> AtlasImage;
|
|
||||||
typedef std::map<int, bool> WaterAtlas;
|
|
||||||
|
|
||||||
// Maximum number of textures per texture-set for the Atlas.
|
|
||||||
static const unsigned int MAX_TEXTURES = 22;
|
|
||||||
|
|
||||||
// Maximum number of material entries in the atlas
|
|
||||||
static const unsigned int MAX_MATERIALS = 64;
|
|
||||||
|
|
||||||
// Standard textures, used by water shader in particular.
|
|
||||||
// Indexes are hardcoded in Shaders/ws30-water.frag
|
|
||||||
inline static const std::string STANDARD_TEXTURES[] = {
|
|
||||||
"Textures/Terrain/water.png",
|
|
||||||
"Textures/Water/water-reflection-ws30.png",
|
|
||||||
"Textures/Water/waves-ver10-nm-ws30.png",
|
|
||||||
"Textures/Water/water_sine_nmap-ws30.png",
|
|
||||||
"Textures/Water/water-reflection-grey-ws30.png",
|
|
||||||
"Textures/Water/sea_foam-ws30.png",
|
|
||||||
"Textures/Water/perlin-noise-nm.png",
|
|
||||||
|
|
||||||
// The following two textures are large and don't have an alpha channel. Ignoring for now.
|
|
||||||
//"Textures/Globe/ocean_depth_1.png",
|
|
||||||
//"Textures/Globe/globe_colors.jpg",
|
|
||||||
"Textures/Terrain/packice-overlay.png"
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AtlasIndex index;
|
|
||||||
AtlasImage image;
|
|
||||||
osg::ref_ptr<osg::Uniform> textureLookup1;
|
|
||||||
osg::ref_ptr<osg::Uniform> textureLookup2;
|
|
||||||
osg::ref_ptr<osg::Uniform> dimensions;
|
|
||||||
osg::ref_ptr<osg::Uniform> ambient;
|
|
||||||
osg::ref_ptr<osg::Uniform> diffuse;
|
|
||||||
osg::ref_ptr<osg::Uniform> specular;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Uniform> materialParams1;
|
|
||||||
osg::ref_ptr<osg::Uniform> materialParams2;
|
|
||||||
osg::ref_ptr<osg::Uniform> materialParams3;
|
|
||||||
|
|
||||||
WaterAtlas waterAtlas;
|
|
||||||
TextureMap textureMap;
|
|
||||||
} Atlas;
|
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGMaterialCache (Atlas atlas);
|
SGMaterialCache();
|
||||||
|
|
||||||
// Insertion
|
// Insertion
|
||||||
void insert( const std::string& name, SGSharedPtr<SGMaterial> material );
|
void insert( const std::string& name, SGSharedPtr<SGMaterial> material );
|
||||||
@ -120,9 +69,8 @@ public:
|
|||||||
SGMaterial *find( const std::string& material ) const;
|
SGMaterial *find( const std::string& material ) const;
|
||||||
SGMaterial *find( int material ) const;
|
SGMaterial *find( int material ) const;
|
||||||
|
|
||||||
Atlas getAtlas() { return _atlas; };
|
void setAtlas(osg::ref_ptr<simgear::Atlas> atlas) { _atlas = atlas; };
|
||||||
|
osg::ref_ptr<simgear::Atlas> getAtlas() { return _atlas; };
|
||||||
void addAtlasUniforms(osg::StateSet* stateset);
|
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~SGMaterialCache ( void );
|
~SGMaterialCache ( void );
|
||||||
@ -130,7 +78,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
typedef std::map < std::string, SGSharedPtr<SGMaterial> > material_cache;
|
typedef std::map < std::string, SGSharedPtr<SGMaterial> > material_cache;
|
||||||
material_cache cache;
|
material_cache cache;
|
||||||
Atlas _atlas;
|
osg::ref_ptr<simgear::Atlas> _atlas;
|
||||||
|
|
||||||
const std::string getNameFromLandclass(int lc) const {
|
const std::string getNameFromLandclass(int lc) const {
|
||||||
return std::string("WS30_").append(std::to_string(lc));
|
return std::string("WS30_").append(std::to_string(lc));
|
||||||
@ -141,6 +89,10 @@ private:
|
|||||||
class SGMaterialLib : public SGReferenced
|
class SGMaterialLib : public SGReferenced
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef std::map <const std::string, osg::ref_ptr<simgear::Atlas> > atlas_map;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class MatLibPrivate;
|
class MatLibPrivate;
|
||||||
std::unique_ptr<MatLibPrivate> d;
|
std::unique_ptr<MatLibPrivate> d;
|
||||||
@ -160,11 +112,10 @@ private:
|
|||||||
material_map matlib;
|
material_map matlib;
|
||||||
landclass_map landclasslib;
|
landclass_map landclasslib;
|
||||||
|
|
||||||
typedef std::map < std::string, SGMaterialCache::Atlas > atlas_map;
|
|
||||||
atlas_map _atlasCache;
|
|
||||||
|
|
||||||
// Get a (cached) texture atlas for this material cache
|
// Get a (cached) texture atlas for this material cache
|
||||||
SGMaterialCache::Atlas getMaterialTextureAtlas(SGVec2f center, const simgear::SGReaderWriterOptions* options);
|
osg::ref_ptr<simgear::Atlas> getOrCreateAtlas(SGMaterialLib::landclass_map, SGVec2f center, const simgear::SGReaderWriterOptions* const_options);
|
||||||
|
static atlas_map _atlasCache;
|
||||||
|
static std::mutex _atlasCacheMutex;
|
||||||
|
|
||||||
SGMaterial* internalFind(const std::string& material, const SGVec2f center) const;
|
SGMaterial* internalFind(const std::string& material, const SGVec2f center) const;
|
||||||
|
|
||||||
|
@ -759,7 +759,7 @@ void VertexNormalGenerator::computeNormals()
|
|||||||
void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, const osg::Vec3d& centerModel)
|
void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, const osg::Vec3d& centerModel)
|
||||||
{
|
{
|
||||||
osg::Image* landclassImage = 0;
|
osg::Image* landclassImage = 0;
|
||||||
SGMaterialCache::Atlas atlas;
|
osg::ref_ptr<Atlas> atlas;
|
||||||
|
|
||||||
Terrain* terrain = _terrainTile->getTerrain();
|
Terrain* terrain = _terrainTile->getTerrain();
|
||||||
osgTerrain::Layer* elevationLayer = _terrainTile->getElevationLayer();
|
osgTerrain::Layer* elevationLayer = _terrainTile->getElevationLayer();
|
||||||
@ -992,10 +992,10 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator,
|
|||||||
|
|
||||||
if (separateWaterMesh && landclassImage && matlib) {
|
if (separateWaterMesh && landclassImage && matlib) {
|
||||||
// If we are generating a separate water mesh, the work out which of the vertices are in appropriate watery materials.
|
// If we are generating a separate water mesh, the work out which of the vertices are in appropriate watery materials.
|
||||||
if (i00>=0) w00 = atlas.waterAtlas[int(round(landclassImage->getColor((*texcoords)[i00]).r() * 255.0))];
|
if (i00>=0) w00 = atlas->isWater(int(std::round(landclassImage->getColor((*texcoords)[i00]).r() * 255.0)));
|
||||||
if (i01>=0) w01 = atlas.waterAtlas[int(round(landclassImage->getColor((*texcoords)[i01]).r() * 255.0))];
|
if (i01>=0) w01 = atlas->isWater(int(std::round(landclassImage->getColor((*texcoords)[i01]).r() * 255.0)));
|
||||||
if (i10>=0) w10 = atlas.waterAtlas[int(round(landclassImage->getColor((*texcoords)[i10]).r() * 255.0))];
|
if (i10>=0) w10 = atlas->isWater(int(std::round(landclassImage->getColor((*texcoords)[i10]).r() * 255.0)));
|
||||||
if (i11>=0) w11 = atlas.waterAtlas[int(round(landclassImage->getColor((*texcoords)[i11]).r() * 255.0))];
|
if (i11>=0) w11 = atlas->isWater(int(std::round(landclassImage->getColor((*texcoords)[i11]).r() * 255.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int numValid = 0;
|
unsigned int numValid = 0;
|
||||||
@ -1344,15 +1344,14 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
|
|||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc);
|
SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc);
|
||||||
|
|
||||||
SGMaterialCache* matCache = matlib->generateMatCache(loc, _options);
|
SGMaterialCache* matCache = matlib->generateMatCache(loc, _options);
|
||||||
SGMaterialCache::Atlas atlas = matCache->getAtlas();
|
osg::ref_ptr<Atlas> atlas = matCache->getAtlas();
|
||||||
SGMaterialCache::AtlasIndex atlasIndex = atlas.index;
|
|
||||||
|
|
||||||
// Set the "g" color channel to an index into the atlas index.
|
// Set the "g" color channel to an index into the atlas for the landclass.
|
||||||
for (unsigned int s = 0; s < (unsigned int) image->s(); s++) {
|
for (unsigned int s = 0; s < (unsigned int) image->s(); s++) {
|
||||||
for (unsigned int t = 0; t < (unsigned int) image->t(); t++) {
|
for (unsigned int t = 0; t < (unsigned int) image->t(); t++) {
|
||||||
osg::Vec4d c = image->getColor(s, t);
|
osg::Vec4d c = image->getColor(s, t);
|
||||||
int i = int(round(c.x() * 255.0));
|
int i = int(std::round(c.x() * 255.0));
|
||||||
c.set(c.x(), (double) (atlasIndex[i] / 255.0), c.z(), c.w() );
|
c.set(c.x(), (double) (atlas->getIndex(i) / 255.0), c.z(), c.w() );
|
||||||
image->setColor(c, s, t);
|
image->setColor(c, s, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1383,12 +1382,12 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
|
|||||||
|
|
||||||
osg::StateSet* stateset = buffer._landGeode->getOrCreateStateSet();
|
osg::StateSet* stateset = buffer._landGeode->getOrCreateStateSet();
|
||||||
stateset->setTextureAttributeAndModes(0, texture2D, osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(0, texture2D, osg::StateAttribute::ON);
|
||||||
stateset->setTextureAttributeAndModes(1, atlas.image, osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(1, atlas->getImage(), osg::StateAttribute::ON);
|
||||||
stateset->setTextureAttributeAndModes(7, waterTexture, osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(7, waterTexture, osg::StateAttribute::ON);
|
||||||
stateset->addUniform(new osg::Uniform(VPBTechnique::PHOTO_SCENERY, false));
|
stateset->addUniform(new osg::Uniform(VPBTechnique::PHOTO_SCENERY, false));
|
||||||
stateset->addUniform(new osg::Uniform(VPBTechnique::Z_UP_TRANSFORM, osg::Matrixf(osg::Matrix::inverse(makeZUpFrameRelative(loc)))));
|
stateset->addUniform(new osg::Uniform(VPBTechnique::Z_UP_TRANSFORM, osg::Matrixf(osg::Matrix::inverse(makeZUpFrameRelative(loc)))));
|
||||||
stateset->addUniform(new osg::Uniform(VPBTechnique::MODEL_OFFSET, (osg::Vec3f) buffer._transform->getMatrix().getTrans()));
|
stateset->addUniform(new osg::Uniform(VPBTechnique::MODEL_OFFSET, (osg::Vec3f) buffer._transform->getMatrix().getTrans()));
|
||||||
matCache->addAtlasUniforms(stateset);
|
atlas->addUniforms(stateset);
|
||||||
//SG_LOG(SG_TERRAIN, SG_ALERT, "modeOffset:" << buffer._transform->getMatrix().getTrans().length() << " " << buffer._transform->getMatrix().getTrans());
|
//SG_LOG(SG_TERRAIN, SG_ALERT, "modeOffset:" << buffer._transform->getMatrix().getTrans().length() << " " << buffer._transform->getMatrix().getTrans());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1598,7 +1597,7 @@ void VPBTechnique::applyMaterials(BufferData& buffer, Locator* masterLocator)
|
|||||||
unsigned int tx = (unsigned int) (image->s() * t.x()) % image->s();
|
unsigned int tx = (unsigned int) (image->s() * t.x()) % image->s();
|
||||||
unsigned int ty = (unsigned int) (image->t() * t.y()) % image->t();
|
unsigned int ty = (unsigned int) (image->t() * t.y()) % image->t();
|
||||||
const osg::Vec4 tc = image->getColor(tx, ty);
|
const osg::Vec4 tc = image->getColor(tx, ty);
|
||||||
const int land_class = int(round(tc.x() * 255.0));
|
const int land_class = int(std::round(tc.x() * 255.0));
|
||||||
|
|
||||||
if (land_class != current_land_class) {
|
if (land_class != current_land_class) {
|
||||||
// Use temporal locality to reduce material lookup by caching
|
// Use temporal locality to reduce material lookup by caching
|
||||||
|
Loading…
Reference in New Issue
Block a user