Okay, I've finally gotten the complete desired effect- this is shader free- it's just a custom IMaterialRenderer.
I used some information from
this post, but I had to modify things a bit to make it do everything properly- specifically a bunch of the SetTextureStageState() calls (I'm kinda thinking these things should have been modified this way to begin with, actually...?), and the minor adjustments to switch to D3D9.
Please note that a lot of this code is just straight copied, since it's functional the way it was, so I can't take full credit for it- but I'm definitely going to go thru and clean it up to be safer- I just wanted to get an iteration of this out there that is functional so anybody who's come across this issue as well can get things working.
Here's my custom IMaterialRenderer:
Code: Select all
class irrMaterialRendererDualTransparent: virtual public IMaterialRenderer {
public:
IDirect3DDevice9 *mID3DDevice;
IVideoDriver *mDriver;
irrMaterialRendererDualTransparent(IDirect3DDevice9 *dev, IVideoDriver *driver): mID3DDevice(dev),
mDriver(driver) {}
//Wrapped functions
virtual void OnSetMaterial(const SMaterial &material, const SMaterial &lastMaterial, bool resetAllRenderstates,
IMaterialRendererServices *services) {
if (material.MaterialType != lastMaterial.MaterialType ||
material.MaterialTypeParam != lastMaterial.MaterialTypeParam ||
resetAllRenderstates) {
//Set the blend factor
s32 blendValue = (u32)(255 * material.MaterialTypeParam);
mID3DDevice->SetRenderState(D3DRS_TEXTUREFACTOR, (blendValue << 24) | 0x00000000);
//Blend the alpha channel
mID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
mID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
mID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
mID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
mID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
//Blend the blend factor
mID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
mID3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
mID3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_BLENDFACTORALPHA);
mID3DDevice->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
mID3DDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
mID3DDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE);
mID3DDevice->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
mID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
mID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
mID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
s32 refValue = (s32)(material.MaterialTypeParam2 * 255);
if (refValue) {
mID3DDevice->SetRenderState(D3DRS_ALPHAREF, refValue);
mID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
mID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
}
}
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
}
virtual void OnUnsetMaterial() {
mID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
}
virtual bool isTransparent() const {
return true;
}
};
And the small bit of code to put it into place to be used by Irrlicht (unmodified from original post):
Code: Select all
irrMaterialRendererDualTransparent mt(driver->getExposedVideoData().D3D9.D3DDev9,driver);
s32 newMat=driver->addMaterialRenderer(&mt);
And a bit of an example of using it:
Code: Select all
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; //Ref value
billMat3->getMaterial(0).MaterialTypeParam=0.5f; //Vertex alpha value
Unfortunately, as posted in the original thread, there doesn't seem to be a way to get around the need to apply the same texture to both texture layers 0
and 1. This is just because of how Irrlicht automatically calls the Direct3D function SetTexture() with each of the 4 texture layers in the material.
I don't suspect that this is enough of an issue to warrant much action on any of the devs' parts, but at least I'll put my request out there: Can we get implemented a means to define which textures get applied to which Texture Stage in Direct3D? Then we could only define the first texture, and tell Direct3D to use that texture for both Texture Stages, leaving us with our other 3 texture layers to be used as we see fit.