WS30: Improved material Uniforms

This commit is contained in:
Stuart Buchanan 2021-12-05 13:45:01 +00:00
parent 922ad8d2e7
commit 0e13e48123
4 changed files with 98 additions and 54 deletions

View File

@ -403,6 +403,11 @@ public:
(0 < tex_height) ? 1000.0f/tex_height : 1.0f); (0 < tex_height) ? 1000.0f/tex_height : 1.0f);
} }
float get_parameter(const std::string& param) const
{
return parameters->getFloatValue(param);
}
protected: protected:

View File

@ -355,14 +355,17 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
atlas.image = new osg::Texture2DArray(); atlas.image = new osg::Texture2DArray();
if (landclasslib.size() > 128) SG_LOG(SG_TERRAIN, SG_ALERT, "Too many landclass entries for uniform arrays"); SG_LOG(SG_TERRAIN, SG_DEBUG, "Generating atlas 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);
atlas.textureLookup1 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_textureLookup1", 128); 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", 128); 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", 128); 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", 128); 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", 128); 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", 128); 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.image->setMaxAnisotropy(SGSceneFeatures::instance()->getTextureFilter()); atlas.image->setMaxAnisotropy(SGSceneFeatures::instance()->getTextureFilter());
atlas.image->setResizeNonPowerOfTwoHint(false); atlas.image->setResizeNonPowerOfTwoHint(false);
@ -396,56 +399,76 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
atlas.diffuse->setElement(materialLookupIndex, mat->get_diffuse()); atlas.diffuse->setElement(materialLookupIndex, mat->get_diffuse());
atlas.specular->setElement(materialLookupIndex, mat->get_specular()); atlas.specular->setElement(materialLookupIndex, mat->get_specular());
// Add any missing textures into the atlas image // The following are material parameters that are normally built into the Effect as Uniforms. In the WS30
for (std::size_t i = 0; i < mat->get_num_textures(0); ++i) { // case we need to pass them as an array, indexed against the material.
const std::string texture = mat->get_one_texture(0,i); 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")));
if (! texture.empty()) { 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")));
SGPath texturePath = SGPath("Textures"); // Similarly, there are specifically 7 textures that are defined in the materials that need to be passed into
std::string fullPath = SGModelLib::findDataFile(texture, options, texturePath); // 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/void.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
if (fullPath.empty()) { for (unsigned int i = 0; i < SGMaterialCache::MAX_TEXTURES; i++) {
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find texture \"" std::string texture = mat->get_one_texture(0,i);
<< texture << "\" in Textures folders when creating texture atlas");
textureList[i] = -2;
continue;
}
if (atlas.textureMap.find(fullPath) == atlas.textureMap.end()) { if (texture.empty()) {
// Copy the texture into the atlas in the appropriate place // This is a rather horrible hardcoded mapping of the default textures defined in
osg::ref_ptr<osg::Image> subtexture = osgDB::readRefImageFile(fullPath, options); // terrain-default.eff and terrain-overlay.eff which are in effect defaults to
// the material definitions
if (subtexture && subtexture->valid()) { if (i < 13) texture = std::string("Textures/Terrain/void.png");
if (i == 13) texture = std::string("Textures/Terrain/rock_alt.png");
if ((subtexture->s() != 2048) || (subtexture->t() != 2048)) { if (i == 14) texture = std::string("Textures/Terrain/grain_texture.png");
subtexture->scaleImage(2048,2048,1); if (i > 14) texture = std::string("Textures/Terrain/void.png");
}
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];
//SG_LOG(SG_TERRAIN, SG_ALERT, "materialLookup Index: " << (materialLookupIndex * SGMaterialCache::MAX_TEXTURES + i) << " " << atlas.textureMap[fullPath] << " " << fullPath);
} else {
textureList[i] = -2;
} }
}
// Fill out the rest of the array SGPath texturePath = SGPath("Textures");
for (std::size_t i = mat->get_num_textures(0); i < SGMaterialCache::MAX_TEXTURES; ++i) { std::string fullPath = SGModelLib::findDataFile(texture, options, texturePath);
textureList[i] = -2;
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. // 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 // 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 // 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.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), 0.0,0.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; ++materialLookupIndex;
@ -456,6 +479,17 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co
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);
}
// 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());

View File

@ -69,7 +69,10 @@ public:
typedef std::map<int, bool> WaterAtlas; typedef std::map<int, bool> WaterAtlas;
// Maximum number of textures per texture-set for the Atlas. // Maximum number of textures per texture-set for the Atlas.
static const unsigned int MAX_TEXTURES = 16; static const unsigned int MAX_TEXTURES = 22;
// Maximum number of material entries in the atlas
static const unsigned int MAX_MATERIALS = 64;
typedef struct { typedef struct {
AtlasIndex index; AtlasIndex index;
@ -80,6 +83,10 @@ public:
osg::ref_ptr<osg::Uniform> ambient; osg::ref_ptr<osg::Uniform> ambient;
osg::ref_ptr<osg::Uniform> diffuse; osg::ref_ptr<osg::Uniform> diffuse;
osg::ref_ptr<osg::Uniform> specular; osg::ref_ptr<osg::Uniform> specular;
osg::ref_ptr<osg::Uniform> materialParams1;
osg::ref_ptr<osg::Uniform> materialParams2;
WaterAtlas waterAtlas; WaterAtlas waterAtlas;
TextureMap textureMap; TextureMap textureMap;
} Atlas; } Atlas;
@ -97,6 +104,8 @@ public:
Atlas getAtlas() { return _atlas; }; Atlas getAtlas() { return _atlas; };
void addAtlasUniforms(osg::StateSet* stateset);
// Destructor // Destructor
~SGMaterialCache ( void ); ~SGMaterialCache ( void );

View File

@ -1346,7 +1346,8 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
const SGGeod loc = computeCenterGeod(buffer, masterLocator); const SGGeod loc = computeCenterGeod(buffer, masterLocator);
SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc); SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc);
SGMaterialCache::Atlas atlas = matlib->generateMatCache(loc, _options)->getAtlas(); SGMaterialCache* matCache = matlib->generateMatCache(loc, _options);
SGMaterialCache::Atlas atlas = matCache->getAtlas();
SGMaterialCache::AtlasIndex atlasIndex = atlas.index; 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 index.
@ -1385,14 +1386,9 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
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.image, osg::StateAttribute::ON);
stateset->addUniform(new osg::Uniform("fg_photoScenery", false)); stateset->addUniform(new osg::Uniform("fg_photoScenery", false));
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(new osg::Uniform("fg_zUpTransform", osg::Matrixf(osg::Matrix::inverse(makeZUpFrameRelative(loc))))); stateset->addUniform(new osg::Uniform("fg_zUpTransform", osg::Matrixf(osg::Matrix::inverse(makeZUpFrameRelative(loc)))));
stateset->addUniform(new osg::Uniform("fg_modelOffset", (osg::Vec3f) buffer._transform->getMatrix().getTrans())); stateset->addUniform(new osg::Uniform("fg_modelOffset", (osg::Vec3f) buffer._transform->getMatrix().getTrans()));
matCache->addAtlasUniforms(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());
} }
} }