History: OgreDecal
Preview of version: 14
Current Maintainer: fd9_
Project: External OGRE Project
Type: OGRE Library
License: MIT
Supported Platforms: Windows / Linux / Mac OS X
Sources:
Status and bug reports:
Description: OgreDecal is a mesh decal generator which should support any triangle mesh and/or scene manager. Unlike the Projective Decal Tutorial, the decals are mesh-based and hence do not require any extra passes to render them, reducing the run-time cost considerably.
How To Use
Generation of a decal requires four parameters:
- The mesh to project onto (pointer to a TriangleMesh object)
- The center position of the projection box
- The width and height of the projected decal
- The material to use for the decal
The first and most important parameter to understand is the mesh object. Typically this will be your world object and can therefore be very large, probably consisting of a large number of triangles. The algorithm will need to collect all of the triangles within the bounding box area you wish to project a decal onto. Because of this, any object you pass in must derive from TriangleMesh, which is an abstract class with a single virtual function called findTrianglesInAABB(). By default, you can use the OgreMesh object, which uses a brute-force test to check each triangle against the AABB. Below is a complete example using OgreMesh (in the example, it is assumed that the decal is projected onto the mesh by means of casting a ray from the camera into the scene).
/// This is the mesh object that we will pass to the decal generator. /// Do not create any more than one OgreMesh per mesh, even if you have multiple instances of the same mesh in your scene. OgreDecal::OgreMesh worldMesh; /// This method will extract all of the triangles from the mesh to be used later. Only should be called once. /// If you scale your mesh at all, pass it in here. worldMesh.initialize( entity->getMesh(), 1.0 ); /// Get the DecalGenerator singleton OgreDecal::DecalGenerator& generator = OgreDecal::DecalGenerator::getSingleton(); /// Set Decal parameters: Ogre::Vector3 pos = getRaycastPoint(); /// Send a ray into the mesh float width = 10; float height = 10; std::string textureName = "MyTexture"; /// Make sure your texture has a depth_bias greater than 1 to avoid z-fighting /// We have everything ready to go. Now it's time to actually generate the decal: OgreDecal::Decal decal = generator.createDecal( &worldMesh, pos, width, height, textureName ); /// Render the decal object. Always verify the returned object - it will be NULL if no decal could be created. if (decal.object) { sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject( decal.object ); }
However, you can also derive your own class from TriangleMesh and implement findTrianglesInAABB() yourself. This gives you several advantages over using the OgreMesh object. For example, your world may consist of more than one mesh. If so, you can derive your own class to lookup triangles within each one. In addition, you may be using a physics engine that has optimizations which allows you to find triangles quicker. I have provided below an example using the Bullet physics engine, using the processAllTriangles() function. Note: Bullet actually performs a triangle bounding box test, which is faster, but also means that there can be many false positives. Because of this, you must test each triangle with collide_triangle_exact() before saving it. If you plan on using a different physics engine, be sure to check the documentation to see if this applies.
class BulletMesh : public OgreDecal::TriangleMesh, public btTriangleCallback { public: BulletMesh() { mMesh = 0; mTriangles = 0; } BulletMesh( btConcaveShape* mesh ) { setMesh( mesh ); mTriangles = 0; } void setMesh( btConcaveShape* mesh ) { mMesh = mesh; } void processTriangle( btVector3* triangle, int partId, int triangleIndex) { /// Convert Bullet vectors to Ogre vectors Ogre::Vector3 v1( triangle[0].getX(), triangle[0].getY(), triangle[0].getZ() ); Ogre::Vector3 v2( triangle[1].getX(), triangle[1].getY(), triangle[1].getZ() ); Ogre::Vector3 v3( triangle[2].getX(), triangle[2].getY(), triangle[2].getZ() ); OgreDecal::Triangle t( v1, v2, v3 ); /// Check for false-positive if (OgreDecal::collide_triangle_exact( mAABBMin, mAABBMax, t )) mTriangles->push_back( t ); } void findTrianglesInAABB( const Ogre::Vector3& aabbMin, const Ogre::Vector3& aabbMax, std::vector< OgreDecal::Triangle >& triangles ) { mTriangles = &triangles; mTriangles->clear(); mAABBMin = aabbMin; mAABBMax = aabbMax; if (mMesh) mMesh->processAllTriangles( this, OgreToBullet(aabbMin), OgreToBullet(aabbMax) ); /// We no longer need to point to the triangle list mTriangles = 0; } private: Ogre::Vector3 mAABBMin, mAABBMax; std::vector< OgreDecal::Triangle >* mTriangles; btConcaveShape* mMesh; };
Debug Drawing
Debug drawing will render the vertices and triangles of each decal. To enable it, set DEBUG_ENABLED to true at the top of OgreDecal.cpp. Then call turnDebugOn():
/// At the top of OgreDecal.cpp, this is required: const bool DEBUG_ENABLED = true; OgreDecal::DecalGenerator::getSingleton().turnDebugOn(); /// Alternatively, you can flip the debug state on/off: OgreDecal::DecalGenerator::getSingleton().flipDebug();
Limitations
1) Decal projection is an approximation and will not always produce desired results. Stretching and cropping will sometimes occur, depending on the geometry. Any contributions to make the algorithm more robust is welcomed.
2) Currently does not properly support disjointed triangles, back facing triangles, or types of geometry which is smaller than the projection box. For example, consider thin surfaces which have opposite facing triangles. The algorithm makes no effort to distinguish one side from the other, so it will simply attempt to project onto both faces. In other words, it uses all triangles found within the projection box. One idea is to provide an optional parameter that specifies a normal (could possibly be the ray vector negated, or the normal of the triangle closest to the center position) and/or a rotational deviation limit which would ignore any triangles that are "facing away", as determined by the rotational limit.
3) Currently only supports static meshes with their default orientation and position unchanged., for sake of simplicity. If you can't get your decals to work, make sure that you haven't reset the position or orientation of your mesh at initialization.
4) Any decals which are generated on top of eachother will have z-fighting. To overcome this, you'll need to change the material of one the decals to have a different depth_bias.