Page 1 of 1

(C++) DX8 Sprite material (texture alpha AND overall alpha)

Posted: Thu Aug 31, 2006 3:10 am
by IPv6
Hello!

Here is code for new material that use texture with alpha channel AND user-defined alpha-blend parameter. So now you can fade-in/fade-out objects in a flash (or in the animator) even if it has nice semitransparent texture on it. BUT there are some limitations: material uses texture 0 and texture 1 (they should point on the same texture for sprite behaviour), but you can load independent texture to slot 1 for very interesting effects.

To use it:

Code: Select all

	CSpriteMat mt(driver->getExposedVideoData().D3D8.D3DDev8,driver);
	s32 newMat=driver->addMaterialRenderer(&mt);
	IBillboardSceneNode *billMat3=smgr->addBillboardSceneNode(0,core::dimension2d<f32>(9.0f, 9.0f),core::vector3df(0,0,-0.8f));
	billMat3->setMaterialType((E_MATERIAL_TYPE)newMat);
	ITexture* imgLogo=driver->getTexture("logo1.png");
	billMat3->setMaterialTexture(0, imgLogo);
	billMat3->setMaterialTexture(1, imgLogo);
	billMat3->setMaterialFlag(video::EMF_LIGHTING, false);
	billMat3->getMaterial(0).MaterialTypeParam2=0;
	billMat3->getMaterial(0).MaterialTypeParam=0.5f;
Notice setMaterialTexture(0)/setMaterialTexture(1) are set to the same texture. Overall alpha of this billboard is in the billMat3->getMaterial(0).MaterialTypeParam (0-object is not visible at all, 1-object is fully visible)

Class itself

Code: Select all

//! Transparent alpha channel material renderer
class CSpriteMat : public IMaterialRenderer
{
public:
	IDirect3DDevice8* pID3DDevice;
	video::IVideoDriver* Driver;

	CSpriteMat(IDirect3DDevice8* p, video::IVideoDriver* d)
		: pID3DDevice(p),Driver(d) {}

	virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
		bool resetAllRenderstates, IMaterialRendererServices* services) 
	{

		if (material.MaterialType != lastMaterial.MaterialType 
			|| material.MaterialTypeParam != lastMaterial.MaterialTypeParam 
			|| resetAllRenderstates)
		{
			s32 blendValue=(255*material.MaterialTypeParam);
			pID3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR , (blendValue << 24) | 0x00000000 );
			pID3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
			pID3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
			pID3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_CURRENT );

			pID3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 ); 
			pID3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); 


			pID3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_MODULATE );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );

			pID3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_BLENDFACTORALPHA);


			pID3DDevice->SetTextureStageState( 2, D3DTSS_COLOROP,   D3DTOP_DISABLE ); 
			pID3DDevice->SetTextureStageState( 2, D3DTSS_ALPHAOP,   D3DTOP_DISABLE ); 

			pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); 
			pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 
			pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); 

			s32 refValue = (s32)(material.MaterialTypeParam2 * 255);
			if (refValue){
				pID3DDevice->SetRenderState(D3DRS_ALPHAREF, refValue);            
				pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
				pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); 
			}
		}

		services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
	}

	virtual void OnUnsetMaterial() 
	{ 
		pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); 
	}  

	//! Returns if the material is transparent. 
	virtual bool isTransparent() 
	{
		return true; 
	}
};
Currently this material can be used with DX8 only. there is no problem with creating DX9 material, but i know nothing about OpenGL materials. But it can be then combined with similar class from openGL-only libraries for irrlicht (i read some posts about such libraries)

P.S. may be the code (and renderStates) are not efficient... it would be good to hear any comments from anyone expirienced, expecially with perfomance impact of this material. may be it is possible to optimize renderState switching? or i`m miss something obvious? :)

Posted: Thu Aug 31, 2006 3:56 am
by IPv6
demo project (with src)
http://slil.ru/23075747

Posted: Sun Nov 04, 2007 3:41 pm
by guest22
Hi,

Is it possible to post the demo project again ? (url leads to empty page).
Or just a simple "main" using this "CSpriteMat"

Thanks.

Posted: Thu Nov 08, 2007 4:20 pm
by zet.dp.ua
what is the difference from standard transparent material?

how did you implement 2d sprite rendering in your game?
i'm trying now to modify irrlicht to be able to make casual 2d games
my way is (maybe not the best) in adding sprite node, which can draw rotated, scaled texture or part of texture
my next step will be to add texture animator and add content manager that will be responsible for loading sprites, animation configs

what was your way?

Posted: Fri Nov 09, 2007 3:50 am
by Virion
i'm trying now to modify irrlicht to be able to make casual 2d games
I'll be looking forward on that. =)

Posted: Tue Nov 13, 2007 3:13 pm
by IPv6
zet.dp.ua wrote:what was your way?
The same :) custom-made billboards that support rotation and some special optimizations. Working on my Irrlight-based engine (which is now called GameRotor engine btw :) ) i encountered the folllowing major bottlenecks during casual 2d game creation:
- unsufficient speed of build-in billboards. now i automatically pack the into one mech buffer and send to GPU in one call - much faster. Still waiting for VBO in Irrlight though...
- texture switches. after all i added automatical "atlasing" - when a lot of small textures are packed into one big texture on the fly. This is also usefull for adding animation into billboards
- font rendering. default 2d font rendering is not very usefull. i recreated font rendering in 3d (using the same custom billboards)

Usage of this material is simple. Just add it to engine via int alphaMatID=driver->addMaterialRenderer(new CSpriteMat(...)) and then set to all bewly created billboards via setMaterialType(alphaMatID)

This would be great to port this rendersttes into OpenGL material, BTW!

Posted: Thu Nov 15, 2007 10:47 am
by zet.dp.ua
i'm doing almost the same now
batching sprites, using texture atlases
as for material, i decided to use modified EMT_ONETEXTURE_BLEND
taking into account vertex color and alpha
performance is similar to popcap's and playfirst's engines

more difficult is to make flexible animation system

thank you for the answer

Posted: Sun Nov 23, 2008 2:00 pm
by maxi0361
looking forward to your 2d casual game version of irrlicht!

Posted: Mon Nov 24, 2008 1:51 pm
by IPv6
we already did one game and making several other games for now.
BTW, after all it is better to use shader (simple one of course) instead of build-in material. for similar usage in opengl/directx and greater flexibility