OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username:
Password:
CapsLock is on.
Remember me (for 1 year)
Log in
Home
Tutorials
Tutorials Home
Basic Tutorials
Intermediate Tutorials
Mad Marx Tutorials
In Depth Tutorials
Older Tutorials
External Tutorials
Cookbook
Cookbook Home
CodeBank
Snippets
Experiences
Ogre Articles
Libraries
Libraries Home
Alternative Languages
Assembling A Toolset
Development Tools
OGRE Libraries
List of Libraries
Tools
Tools Home
DCC Tools
DCC Tutorials
DCC Articles
DCC Resources
Assembling a production pipeline
Development
Development Home
Roadmap
Building Ogre
Installing the Ogre SDK
Setting Up An Application
Ogre Wiki Tutorial Framework
Frequently Asked Questions
Google Summer Of Code
Help Requested
Ogre Core Articles
Community
Community Home
Projects Using Ogre
Recommended Reading
Contractors
Wiki
Immediate Wiki Tasklist
Wiki Ideas
Wiki Guidelines
Article Writing Guidelines
Wiki Styles
Wiki Page Tracker
Ogre Wiki Help
Ogre Wiki Help Overview
Help - Basic Syntax
Help - Images
Help - Pages and Structures
Help - Wiki Plugins
Toolbox
Freetags
Categories
List Pages
Structures
Trackers
Statistics
Rankings
List Galleries
Ogre Lexicon
Comments
History: Projective Decals
View page
Source of version: 3
(current)
{maketoc} !!Introduction This is a quick implementation of ((Intermediate Tutorial 6)). The class ''TerrainDecal'' represents a texture that is projected orthogonaly on top of the terrain from a given point and with a given size. This class will detect the terrain pages that are affected (limited to four, because only the four corners of the projection area are tested) and adds a pass to the materials of those pages. If the Decal has to move, just call ''updatePosition()''. I think you can guess the meaning of ''updateSize()''. ;) !!Using the class on startup: # ''init'' (doesn`t show the decal, just prepares) # ''updatePosition'' # ''show'' after that, do whenever necessary: * ''hide'' * ''show'' * ''updatePosition'' * ''updateSize'' !!Performance One problem with this implementation is the performance: since every decal adds another pass to the underlaying terrain pages, the fps hit is quite hard as soon as multiple decals act at the same time. So I will be happy to accept optimizations! There are some promising new approaches in [http://www.ogre3d.org/phpBB2addons/viewtopic.php?t=498|this forum thread], which I will investigate further in the near future. !!Code {CODE(wrap="1", colors="c++")}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::LogManager::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::Quaternion(Ogre::Degree(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); // update height mFrustum->setOrthoWindowHeight(mSize.y); } } bool isVisible() { return mVisible; } };{CODE} --- Alias: (alias(Projective_Decals))
Search by Tags
Search Wiki by Freetags
Latest Changes
IDE Eclipse
FMOD SoundManager
HDRlib
Building Ogre V2 with CMake
Ogre 2.1 FAQ
Minimal Ogre Collision
Artifex Terra
OpenMB
Advanced Mogre Framework
MogreSocks
...more
Search
Find
Advanced
Search Help
Online Users
107 online users