|
|
关于地表贴图(贴花),纹理投射的问题..(附:Mesh Decals与Projective Decals的资料)..自己实验好久无解,欢迎大家来指教.论讨
建立了一个高度地型之后...就是给地表加入不同的原素.
如地面上有路道..草皮,,沙漠等等...
一般是通过什么方法贴在地表上的..精确的与地表吻合..
我查过以下资料..
第一种方法:
Mesh Decals
代码如下: 编辑通过..执行也无错..就是没有显示我要的地表贴图.
MovableObject* createDecal( SceneManager& sceneMgr,
const String& name,
const String& materialName,
const Vector2& size )
{
NameValuePairList params;
params["materialName"] = materialName;
params["width"] = StringConverter::toString( size.x );
params["height"] = StringConverter::toString( size.y );
params["sceneMgrInstance"] = sceneMgr.getName();
return sceneMgr.createMovableObject( name,
" agingLandScapeMeshDecal",
&params );
}
执行报"PagingLandScapeMeshDecal"不存在...不知道怎么处理了..这个type究竟应该是什么?
第二种方法 rojective Decals
class TerrainDecal
{
protected:
Ogre::Vector3 mPos; // center
Ogre::Vector2 mSize; // size of decal
std::string mTexture; // texture to apply
Ogre::SceneNode* mNode; // the projection node
Ogre::Frustum* mFrustum; // the projection frustum
Ogre::SceneManager* mSceneManager; // pointer to PLSM2
bool mVisible; // is the decal visible/active or not?
// info about materials that are receiving the decal
std::map<std::string,Ogre::Pass*> mTargets; // passes mapped by material names
bool isPosOnTerrain(Ogre::Vector3 pos)
{
// get the terrain boundaries
Ogre::AxisAlignedBox box;
mSceneManager->getOption("MapBoundaries",&box);
// check if pos is in box, ignore y
pos.y = 0;
return box.intersects(pos);
}
std::string getMaterialAtPosition(Ogre::Vector3 pos)
{
void* myOptionPtr = &pos;
// check if position is on battlefield
if( isPosOnTerrain(pos) )
{
mSceneManager->getOption ("getMaterialPageName", myOptionPtr);
std::string name = **static_cast<std::string**>(myOptionPtr);
return name;
}
else
return "";
}
void addMaterial(std::string matName)
{
// check if material is already decalled
if( mTargets.find(matName) != mTargets.end() )
{
Ogre: ogManager::getSingleton().getDefaultLog()->logMessage("material should be added to decal but was already!");
return;
}
using namespace Ogre;
// get the material ptr
MaterialPtr mat = (MaterialPtr)MaterialManager::getSingleton().getByName(matName);
// create a new pass in the material to render the decal
Pass* pass = mat->getTechnique(0)->createPass();
// set up the decal's texture unit
TextureUnitState *texState = pass->createTextureUnitState(mTexture);
texState->setProjectiveTexturing(true, mFrustum);
texState->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
texState->setTextureFiltering(FO_POINT, FO_LINEAR, FO_NONE);
// set our pass to blend the decal over the model's regular texture
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
pass->setDepthBias(1);
// set the decal to be self illuminated instead of lit by scene lighting
pass->setLightingEnabled(false);
// save pass in map
mTargets[matName] = pass;
Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(std::string("added material to decal: ") + matName +
"(" + Ogre::StringConverter::toString(mTargets.size()) + " materials loaded)");
}
std::map<std::string,Ogre::Pass*>::iterator removeMaterial(std::string matName)
{
// remove our pass from the given material
mTargets[matName]->getParent()->removePass(mTargets[matName]->getIndex());
Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(std::string("removed material from decal: ") + matName +
"(" + Ogre::StringConverter::toString(mTargets.size()-1) + " materials loaded)");
// remove from map
return mTargets.erase(mTargets.find(matName));
}
public:
TerrainDecal()
{
mVisible = false;
mNode = 0;
mFrustum = 0;
};
~TerrainDecal()
{
hide();
// delete frustum
mNode->detachAllObjects();
delete mFrustum;
// destroy node
mNode->getParentSceneNode()->removeAndDestroyChild(mNode->getName());
};
void init( Ogre::SceneManager* man, Ogre::Vector2 size, std::string tex )
{
using namespace Ogre;
// set SM
mSceneManager = man;
// init projective decal
// set up the main decal projection frustum
mFrustum = new Ogre::Frustum();
mNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
mNode->attachObject(mFrustum);
mFrustum->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
mNode->setOrientation(Ogre: uaternion(Ogre: egree(90),Ogre::Vector3::UNIT_X));
// set given values
updateSize(size);
mTexture = tex; // texture to apply
// load the images for the decal and the filter
TextureManager::getSingleton().load
(mTexture, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 1);
mVisible = false;
}
void show()
{
if( !mVisible )
{
mVisible = true;
updatePosition(mPos);
}
}
void hide()
{
if( mVisible )
{
// remove all added passes
while( !mTargets.empty() )
removeMaterial(mTargets.begin()->first);
mVisible = false;
}
}
void updatePosition( Ogre::Vector3 pos )
{
// don`t do anything if pos didn`t change
//if( pos == mPos )
// return;
// save the new position
mPos = pos;
mNode->setPosition(pos.x,pos.y+1000,pos.z);
// don`t show if invisible
if( !isVisible() )
return;
// check near pages (up to 4)
std::list<std::string> neededMaterials;
Ogre::Vector3 t;
// x high z high
t = Ogre::Vector3(mPos.x+mSize.x/2.0f,1000,mPos.z+mSize.y/2.0f);
neededMaterials.push_back(getMaterialAtPosition(t));
// x high z low
t = Ogre::Vector3(mPos.x+mSize.x/2.0f,1000,mPos.z-mSize.y/2.0f);
neededMaterials.push_back(getMaterialAtPosition(t));
// x low z low
t = Ogre::Vector3(mPos.x-mSize.x/2.0f,1000,mPos.z-mSize.y/2.0f);
neededMaterials.push_back(getMaterialAtPosition(t));
// x low z high
t = Ogre::Vector3(mPos.x-mSize.x/2.0f,1000,mPos.z+mSize.y/2.0f);
neededMaterials.push_back(getMaterialAtPosition(t));
// remove empties
neededMaterials.remove("");
// remove doubles
neededMaterials.unique();
// compare needed materials with used
// for every used material
std::map<std::string,Ogre::Pass*>::iterator used = mTargets.begin();
while(true)
{
// stop if we are through
if( used == mTargets.end() )
break;
// find in needed
std::list<std::string>::iterator needed =
std::find(neededMaterials.begin(),neededMaterials.end(),used->first);
if( needed == neededMaterials.end() )
{
// material is not needed any longer, so remove it
used = removeMaterial(used->first);
}
else
{
// remove it from needed list, bedause it is already loaded
neededMaterials.remove(used->first);
// go further
used++;
}
}
// add all remaining needed to used list
while( !neededMaterials.empty() )
{
addMaterial(neededMaterials.front());
neededMaterials.erase(neededMaterials.begin());
}
}
void updateSize(Ogre::Vector2 size)
{
if( mSize != size )
{
// save param
mSize = size;
// update aspect ratio
mFrustum->setAspectRatio(mSize.x/mSize.y);
// set fovy so that tan = 1, so 45 degree
mFrustum->setFOVy(Ogre::Degree(45));
// set near clip plane according to fovy:
// distance = halfsize.y / tan(fovy)
mFrustum->setNearClipDistance(mSize.y);
}
}
bool isVisible()
{
return mVisible;
}
};
第三种方法:在别人的BLOG上看到要用manualObject来实现...正在测试中..
有经验的朋友指点一下..谢谢了.
|
|