diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index 4ccf2375..59a3175c 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -403,6 +403,11 @@ public: (0 < tex_height) ? 1000.0f/tex_height : 1.0f); } + float get_parameter(const std::string& param) const + { + return parameters->getFloatValue(param); + } + protected: diff --git a/simgear/scene/material/matlib.cxx b/simgear/scene/material/matlib.cxx index ce98a2ce..05f27692 100644 --- a/simgear/scene/material/matlib.cxx +++ b/simgear/scene/material/matlib.cxx @@ -355,14 +355,17 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co 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.textureLookup2 = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_textureLookup2", 128); - atlas.dimensions = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_dimensionsArray", 128); - atlas.ambient = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_ambientArray", 128); - atlas.diffuse = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_diffuseArray", 128); - atlas.specular = new osg::Uniform(osg::Uniform::Type::FLOAT_VEC4, "fg_specularArray", 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", 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.image->setMaxAnisotropy(SGSceneFeatures::instance()->getTextureFilter()); atlas.image->setResizeNonPowerOfTwoHint(false); @@ -396,56 +399,76 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co atlas.diffuse->setElement(materialLookupIndex, mat->get_diffuse()); atlas.specular->setElement(materialLookupIndex, mat->get_specular()); - // Add any missing textures into the atlas image - for (std::size_t i = 0; i < mat->get_num_textures(0); ++i) { - const std::string texture = mat->get_one_texture(0,i); - if (! texture.empty()) { + // 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"))); - SGPath texturePath = SGPath("Textures"); - std::string fullPath = SGModelLib::findDataFile(texture, options, texturePath); + // 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/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()) { - SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find texture \"" - << texture << "\" in Textures folders when creating texture atlas"); - textureList[i] = -2; - continue; - } + for (unsigned int i = 0; i < SGMaterialCache::MAX_TEXTURES; i++) { + std::string texture = mat->get_one_texture(0,i); - if (atlas.textureMap.find(fullPath) == atlas.textureMap.end()) { - // Copy the texture into the atlas in the appropriate place - osg::ref_ptr 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]; - //SG_LOG(SG_TERRAIN, SG_ALERT, "materialLookup Index: " << (materialLookupIndex * SGMaterialCache::MAX_TEXTURES + i) << " " << atlas.textureMap[fullPath] << " " << fullPath); - } else { - textureList[i] = -2; + 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 > 14) texture = std::string("Textures/Terrain/void.png"); } - } - // Fill out the rest of the array - for (std::size_t i = mat->get_num_textures(0); i < SGMaterialCache::MAX_TEXTURES; ++i) { - textureList[i] = -2; + 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 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), 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; @@ -456,6 +479,17 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co 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 SGMaterialCache::~SGMaterialCache ( void ) { SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialCache::~SGMaterialCache() size=" << cache.size()); diff --git a/simgear/scene/material/matlib.hxx b/simgear/scene/material/matlib.hxx index a63e1544..1a485e8f 100644 --- a/simgear/scene/material/matlib.hxx +++ b/simgear/scene/material/matlib.hxx @@ -69,7 +69,10 @@ public: typedef std::map WaterAtlas; // 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 { AtlasIndex index; @@ -80,6 +83,10 @@ public: osg::ref_ptr ambient; osg::ref_ptr diffuse; osg::ref_ptr specular; + + osg::ref_ptr materialParams1; + osg::ref_ptr materialParams2; + WaterAtlas waterAtlas; TextureMap textureMap; } Atlas; @@ -97,6 +104,8 @@ public: Atlas getAtlas() { return _atlas; }; + void addAtlasUniforms(osg::StateSet* stateset); + // Destructor ~SGMaterialCache ( void ); diff --git a/simgear/scene/tgdb/VPBTechnique.cxx b/simgear/scene/tgdb/VPBTechnique.cxx index 6cc8a39e..4e116d58 100644 --- a/simgear/scene/tgdb/VPBTechnique.cxx +++ b/simgear/scene/tgdb/VPBTechnique.cxx @@ -1346,7 +1346,8 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) const SGGeod loc = computeCenterGeod(buffer, masterLocator); 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; // 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(1, atlas.image, osg::StateAttribute::ON); 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_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()); } }