TerrainMaterialHandler::TerrainMaterialHandler(TerrainManager* pOwner)
: m_pOwner(pOwner)//m_pOwner:地形管理器
{
size_t numTilesCol = (pOwner->GetWidth()-1) >> m_pOwner->m_nTileExp; //地形Terrain每行包含的Tile的个数
size_t numTilesRow = (pOwner->GetHeight()-1) >> m_pOwner->m_nTileExp; //Terrain 每列包含的Tile的个数
m_MaterialTiles.assign(numTilesCol, MaterialCol(numTilesRow, MaterialTile()));//所有的地形纹理,主要是为所有的地形纹理申请内存空间
//生成地形的光照图
MakeLightMaps();
// 在不用编辑地形的时候这一句后,就可以在加载地形后把m_pInfo释放掉
for (size_t i = 0; i < numTilesCol; ++i)
for (size_t j = 0; j < numTilesRow; ++j)
MakeMaterial(i,j);//针对所有的地形Tile生成材质,一个地形Tile对应一个材质
}
//***************************************************************************************
// 功能: 生成Lightmap Textures, 尺寸根据 m_pOwner 的光照图image
// 返回值: 无
void TerrainMaterialHandler::MakeLightMaps()
{
if (m_pOwner->GetLightmapWidth() == 0 || m_pOwner->GetLightmapHeight() == 0) //如果Terrain没有光照图 则清空对应的光照图内存
{
for (size_t i = 0; i < m_MaterialTiles.size(); ++i)
for (size_t j = 0; j < m_MaterialTiles[i].size(); ++j)
if (!m_MaterialTiles[i][j].lightMapPtr.isNull())//如果地形Tile的纹理材质中包含了光照图纹理 则立即清空
Ogre::TextureManager::getSingleton().remove(m_MaterialTiles[i][j].lightMapPtr->getHandle());
return;
}
//否则得到光照图的宽度和长度(按照网格划分) 宽度
size_t uWidth = m_pOwner->GetLightmapWidth() / m_MaterialTiles.size();
size_t uHeight = m_pOwner->GetLightmapHeight() / m_MaterialTiles[0].size();//uWidth:地形的光照图的宽度,uHeight:地形光照图的高度
const std::string& baseName = m_pOwner->GetName();//获得地形的基础纹理
for (size_t i = 0; i < m_MaterialTiles.size(); ++i)
{
for (size_t j = 0; j < m_MaterialTiles[i].size(); ++j)
{
std::string lightTexName;
if (!m_MaterialTiles[i][j].lightMapPtr.isNull())//如果地形Tile之前包含有了光照图纹理指针 则需要清空
{
lightTexName = m_MaterialTiles[i][j].lightMapPtr->getName();
Ogre::TextureManager::getSingleton().remove(m_MaterialTiles[i][j].lightMapPtr->getHandle());
}
else
lightTexName = baseName+ "<LightMap>_" + Ogre::StringConverter::toString(i) + "_" + Ogre::StringConverter::toString(j);
//根据之前得到的数据手工生成地形TIle的纹理
m_MaterialTiles[i][j].lightMapPtr = Ogre::TextureManager::getSingletonPtr()->createManual(lightTexName,
BRUSH_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, uWidth, uHeight, -1, m_pOwner->GetLightmapImage().getFormat(), Ogre::TU_DEFAULT, this);
}
}
}
//***************************************************************************************
//生成Terrain Tile【i,j】处的材质,包括coverageMap和texture
void TerrainMaterialHandler::MakeMaterial(UINT i, UINT j)
{
MakeCoverageMap(i,j);//创建该块(ij)覆盖图
MaterialTile& matTile = m_MaterialTiles[i][j];//第ij地形块材质
std::vector<std::string> covMapNames(matTile.coverageMaps.size(), std::string());
for (UINT k = 0; k < matTile.coverageMaps.size(); ++k)
{
covMapNames[k] = matTile.coverageMaps[k]->GetName();
}
std::string matName, lightTexName;
if (matTile.materialPtr.isNull())//如果第ij块栅格的材质为空 那么就要创建这个Terrain Tile对应的名字
{
const std::string& baseName = m_pOwner->GetName();
const std::string& strI = Ogre::StringConverter::toString(i);
const std::string& strJ = Ogre::StringConverter::toString(j);
matName = baseName + "<Material>_" + strI + "_"+ strJ;
lightTexName = baseName + "<LightMap>_" + strI + "_"+ strJ;
}
else
{
matName = matTile.materialPtr->getName();//当前Tile的材质 matName
if (matTile.lightMapPtr.isNull())//
lightTexName = m_pOwner->GetName() + "<LightMap>_" + Ogre::StringConverter::toString(i) + "_"
+ Ogre::StringConverter::toString(j);
else
lightTexName = matTile.lightMapPtr->getName();
}
//matName :Tile对应的材质的名字,covMapNames 混合纹理的名字 ,Tile是否平滑过渡,。。
matTile.materialPtr = MakeMaterial(matName, covMapNames, m_pOwner->IsTileSplitSmooth(i,j),
m_pOwner->GetTileSplitScaleX(i,j), m_pOwner->GetTileSplitScaleZ(i,j),
m_pOwner->GetTileTextures(i,j), lightTexName);
}
///
// 功能: 根据参数建立一个材质
// 参数: name 建立的材质名
// covMapNames 混合纹理名, texNames 着色纹理名
// texCount 着色纹理数量,如果为0,则使用texNames的size,如非0,不要小于texNames的size
//***************************************************************************************
Ogre::MaterialPtr TerrainMaterialHandler::MakeMaterial(const std::string& name, const std::vector<std::string>& covMapNames,
bool isTileSplitSmooth, float splitScaleX, float splitScaleZ,
const std::list<std::string>& texNames, const std::string& lightMapName, UINT texCount) const
{
//-----------------
// 计算得到模板材质
//-----------------
const UINT numTex = texNames.size(); //着色纹理名字 texNames numTex:纹理数目
const UINT numCvm = covMapNames.size();//混合纹理的数目 numCvm
if (texCount == 0)//如果texCount==0 那么就texCount=numTex; 着色纹理的数目
texCount = numTex;
ASSERT(texCount >= numTex);//
// ASSERT((texCount - 1)/4 + 1 == covMapNames.size()); // 索引图数量符合材质数量
std::string templateName = "OgreSE/Terrain_" + Ogre::StringConverter::toString(texCount); //获得材质模板的名字 从OgreSE/Terrain_1到OgreSE/Terrain_5
Ogre::MaterialPtr templateMatPtr = Ogre::MaterialManager::getSingletonPtr()->getByName(templateName);
if (templateMatPtr.isNull())
OGRE_EXCEPT(Ogre::Exception::ERR_ITEM_NOT_FOUND, "Can't load material template '" + name + "'!",
"TerrainMaterialHandler::MakeMaterial");
Ogre::MaterialPtr materialPtr = Ogre::MaterialManager::getSingleton().getByName(name);
if (!materialPtr.isNull())
Ogre::MaterialManager::getSingleton().remove(materialPtr->getHandle());
// 拷贝模板材质
materialPtr = templateMatPtr->clone(name, true, BRUSH_RESOURCE_GROUP_NAME);
//-------------------------
// Setup texture alias list
//-------------------------
Ogre::AliasTextureNamePairList aliasList;
UINT i = 0;
for (std::list<std::string>::const_iterator itr= texNames.begin(); itr != texNames.end(); ++itr, ++i)
{
aliasList["<Texture" + Ogre::StringConverter::toString(i) + ">"] = *itr;
}
for (i = 0; i < numCvm; ++i)
{
aliasList["<CoverageMap" + Ogre::StringConverter::toString(i) + ">"] = covMapNames[i];
}
aliasList["<LightMap>"] = lightMapName;
// Applies texture names
materialPtr->applyTextureAliases(aliasList);
Ogre::Material::TechniqueIterator ti = materialPtr->getTechniqueIterator();
while (ti.hasMoreElements())
{
Ogre::Technique* technique = ti.getNext();
Ogre::Technique::PassIterator pi = technique->getPassIterator();
while (pi.hasMoreElements())
{
Ogre::Pass* pass = pi.getNext();
if (!m_pOwner->GetLODMorphEnabled() || m_pOwner->GetHardwareLighttingEnabled())//如果禁用了LOD或者是 允许光照
{
pass->setVertexProgram(Ogre::StringUtil::BLANK);//这样就不适用顶点着色器
}
if (m_pOwner->GetHardwareLighttingEnabled())//允许光照
{
pass->setLightingEnabled(true);
pass->setFragmentProgram(templateName + "_Lighting_PS");//启用像素着色器
}
Ogre::GpuProgramParametersSharedPtr ptr = pass->getFragmentProgramParameters();
ptr->setNamedConstant("splatScaleX", splitScaleX);
ptr->setNamedConstant("splatScaleZ", splitScaleZ); //获取缩放率
if (!isTileSplitSmooth)//如果不启用平滑过渡 则创建额外的纹理,这些纹理的过滤方式比较粗糙
{
for (int num = 0; num < numCvm; ++num)
{
pass->getTextureUnitState(num+numTex)->setTextureFiltering(Ogre::TFO_NONE);
}
}
}
}
return materialPtr;
};
//***************************************************************************************
// 功能: 创建该块混合纹理 创建地形快【i】【j】的 混合图 blendmaps
void TerrainMaterialHandler::MakeCoverageMap(UINT i, UINT j)
{
UINT numTex = m_pOwner->GetTileTextures(i,j).size();//获取第ij栅格处的纹理数目
MaterialTile& matTile = m_MaterialTiles[i][j];//第ij栅格处的材质 包括 混合纹理blend texture,光照图lightmap
UINT numOldCovMaps = matTile.coverageMaps.size();//获取第[i,j]栅格的混合纹理的数目
if (numTex < 2)//当ij栅格的纹理层数为0 和1的时候 清除ij栅格处的混合纹理,因为1层纹理或者是0层纹理不需要混合纹理,然后就立即返回 return
{
for (size_t k = 0; k < numOldCovMaps; ++k)
{
Ogre::TextureManager::getSingleton().remove(matTile.coverageMaps[k]->GetName());
delete matTile.coverageMaps[k];
}
matTile.coverageMaps.clear();
return; // 小于等于一张纹理的情况下就没有索引图
}
const std::string& baseName = m_pOwner->GetName();//基础纹理名字
unsigned short tileSize = m_pOwner->GetTileSize()-1; //地形块大小
//-------------------------------------------
// 如果旧纹理数大于新纹理数, 抛掉不用的索引图
//-------------------------------------------
if (numOldCovMaps > 0)//如果第[i][j]栅格处的混合纹理数目大于0
{
UINT numOldTex = (numOldCovMaps - 1) * 4 // 旧的纹理数
+ matTile.coverageMaps[numOldCovMaps - 1]->GetChannelCount(); //旧的纹理数目=(混合纹理数目-1)*4+混合纹理数组【混合纹理数目-1】.通道数目
if (numOldTex == numTex)//如果新的纹理数目等于旧的纹理数目 则返回
return;
if (numOldTex > numTex) //如果旧的纹理数目大于新的纹理数目 则抛弃不用的索引图
{
UINT numNewCovMaps = (numTex -1) /4 + 1;//需要使用到底混合纹理的数目
while (numNewCovMaps != matTile.coverageMaps.size())//如果新的混合纹理数目!=旧的混合纹理数目
{
CoverageMap* pLastMap = matTile.coverageMaps[matTile.coverageMaps.size() - 1];//保存旧的混合纹理
matTile.coverageMaps.pop_back(); //pop旧的
delete pLastMap;//销毁之
}
UINT lastMapC = numTex % 4;//新的索引通道,而且是最后一个索引通道
if (lastMapC)
{
CoverageMap* pOldLastMap = matTile.coverageMaps[numNewCovMaps - 1];
CoverageMap* pNewLastMap = new CoverageMap(pOldLastMap->GetName(),
BRUSH_RESOURCE_GROUP_NAME, tileSize, tileSize, lastMapC);//生成一个混合纹理,混合纹理名字,混合纹理的组,地形大小,通道数
for(UINT c = 0; c < lastMapC; ++c)
{
for(unsigned short m = 0; m < tileSize; ++m)
for(unsigned short n = 0; n < tileSize; ++n)
pNewLastMap->SetValue(n,m,c,pOldLastMap->GetValue(n,m,c));
}
matTile.coverageMaps[numNewCovMaps - 1] = pNewLastMap;
delete pOldLastMap;
}
return;
}
}
//-----------------------------------------
// 如果旧纹理数小于新纹理数, 创建新的索引图
//-----------------------------------------
UINT numFullMaps = numTex / 4; // 全4通道的索引图数 numTex:第ij栅格处的纹理数目 numFullMaps 混合纹理的数目
UINT numOldFullMaps = numOldCovMaps; // 旧的全4通道的索引图数
CoverageMap* pOldNoFullCovMap(NULL); // 旧的非全通道的索引图指针
if (numOldFullMaps > 0 && matTile.coverageMaps[numOldFullMaps-1]->GetChannelCount() < 4)
{//如果旧的混合纹理数目大于0 且 最后的一个混合纹理的通道数小于4
pOldNoFullCovMap = matTile.coverageMaps[numOldFullMaps-1];//最后的一个混合纹理数目
matTile.coverageMaps.pop_back();
numOldFullMaps -= 1;
}
for (size_t k = numOldFullMaps; k < numFullMaps; ++k) // 创建4通道索引图
{
matTile.coverageMaps.push_back(new CoverageMap(
baseName+ "_CoverageMap_"
+ Ogre::StringConverter::toString(i)
+ Ogre::StringConverter::toString(j)
+ Ogre::StringConverter::toString(k),
BRUSH_RESOURCE_GROUP_NAME, tileSize, tileSize, 4, k != 0));
}
UINT hasNoFullMap = numTex % 4; // 非全通道的索引图的通道数
if ( hasNoFullMap )
{
matTile.coverageMaps.push_back(new CoverageMap(
baseName + "_CoverageMap_"
+ Ogre::StringConverter::toString(i)
+ Ogre::StringConverter::toString(j)
+ Ogre::StringConverter::toString(numFullMaps),
BRUSH_RESOURCE_GROUP_NAME, tileSize, tileSize, hasNoFullMap, numFullMaps != 0));
}
if (pOldNoFullCovMap)
{
for(UINT c = 0; c < pOldNoFullCovMap->GetChannelCount(); ++c)
{
for(unsigned short m = 0; m < tileSize; ++m)
for(unsigned short n = 0; n < tileSize; ++n)
matTile.coverageMaps[numOldFullMaps]->SetValue(n,m,c,
pOldNoFullCovMap->GetValue(n,m,c));
}
delete pOldNoFullCovMap;
}
}
OGRESE 地形Tile材质的生成 源码以及详细注释 所有源码出自OGRESE,注释部分出自OGRESE
最新推荐文章于 2019-07-07 06:53:11 发布