OGRESE 地形Tile材质的生成 源码以及详细注释 所有源码出自OGRESE,注释部分出自OGRESE

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;
	}
}























  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值