Creating transparency based on a key colour in code

From Ogre Wiki

Jump to: navigation, search
/** Utility function that generates a texture with transparency based on a certain colour value 
 @remarks 
 	The generated texture will either have full opacity or full transparency values 
 @param filename 
 	The name of the image file this texture will be based on, residing in resGroup 
 @param keyCol 
 	The colour value which should cause transparency (alpha component is ignored) 
 @param resGroup 
 	The resource group the base image file belongs and the generated texture will belong to 
 @param prefix 
 	The generated texture will be accessible via the name prefix+filename 
 @param numMipmaps 
 	Usually you leave that on default, but if you never intend to scale the texture, you can set it to 0
 @param threshold 
 	If the difference between the pixel colour of the image and keyCol is less than this, it gets 
 	transparent. It should be between 0 and 1. The default value is less than (1 / 256), which means 
 	that for an 8 Bit channels input file, only the EXACT keyCol gets transparent. 
 @return 
 	Returns the name of the texture resource the generated texture can be addressed by (is prefix+filename) 
 */ 
 Ogre::String loadChromaKeyedTexture(const Ogre::String& filename, 
 		const Ogre::ColourValue& keyCol = Ogre::ColourValue::Black, 
 		const Ogre::String& resGroup = Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 
 		const Ogre::String& prefix = "ck_",
 		int numMipmaps = Ogre::MIP_DEFAULT,
 		float threshold = 0.003f) 
 { 
 	using namespace Ogre; 
 	using std::fabs; 
 	Image srcImg; 
 	srcImg.load (filename, resGroup); 
 	uint width = srcImg.getWidth (), height = srcImg.getHeight ();
 	// Since Ogre 1.6 Shoggoth, the OGRE_ALLOC_T memory macro must be used:
 	uchar* pixelData = OGRE_ALLOC_T (uchar, PixelUtil::getMemorySize (width, height, 1, PF_A8R8G8B8), MEMCATEGORY_GENERAL);
 	ulong pxDataIndex = 0, pxDataIndexStep = PixelUtil::getNumElemBytes (PF_A8R8G8B8); 
 
 	for(uint y = 0; y < height; ++y) 
 	{ 
 		for(uint x = 0; x < width; ++x) 
 		{ 
 			ColourValue pixCol = srcImg.getColourAt (x, y, 0); 
 			ColourValue diffCol = pixCol - keyCol; 
 			pixCol.a = ( (fabs(diffCol.r)<threshold) && (fabs(diffCol.g)<threshold) && (fabs(diffCol.b)<threshold) ) 
 				? 0 : 1; 
 			Ogre::PixelUtil::packColour (pixCol, PF_A8R8G8B8, static_cast<void*> (pixelData + pxDataIndex) ); 
 			pxDataIndex += pxDataIndexStep; 
 		} 
 	} 
 
 	Image chromaKeyedImg;
 	chromaKeyedImg.loadDynamicImage (pixelData, width, height, 1, PF_A8R8G8B8, true); 
 	String resName = prefix + filename;
 	// You could save the chroma keyed image at this point for caching:
 	// chromaKeyedImg.save(resName); 
 	TextureManager::getSingleton ().loadImage( resName , resGroup, chromaKeyedImg, TEX_TYPE_2D, numMipmaps );
 	return resName;
 }

Usage

 // Load an image; in this example we use cyan as colour key:
 Ogre::String texName = loadChromaKeyedTexture("chromaKeyed.bmp", Ogre::ColourValue(0,1,1) );

 // Create your material, e.g. like this:
 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create("yourMat", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
 mat->getTechnique(0)->getPass(0)->setSceneBlending (Ogre::SBT_REPLACE);
 mat->getTechnique(0)->getPass(0)->setAlphaRejectSettings (Ogre::CMPF_GREATER_EQUAL, 128);
 mat->getTechnique(0)->getPass(0)->setCullingMode (Ogre::CULL_NONE);
 mat->getTechnique(0)->getPass(0)->setManualCullingMode (Ogre::MANUAL_CULL_NONE);

 // Instead of the original filename of the image, use the one returned by loadChromaKeyedTexture above:
 Ogre::TextureUnitState*  t = mat->getTechnique(0)->getPass(0)->createTextureUnitState(texName);

 t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
 yourEntity->setMaterialName ("yourMat");

Now your texture should have transparency!

Personal tools
administration