texture not displayed on 3D object when using 2D drawing

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
AlainSE
Posts: 5
Joined: Wed Jun 12, 2013 8:27 am

texture not displayed on 3D object when using 2D drawing

Post by AlainSE »

Hi,

I found a rather strange bug this morning and I wrote a small test code to reproduce it:

I am creating a quad with two alpha enabled textures on it. In normal use, the quad is displayed and the textures are blended correctly.

But if I use a totally unrelated 2D command (in my case draw2DRectangle) then the second texture of the quad is not displayed.

The code is the following:

Code: Select all

 
int main(int argc,char** argv)
{
 
    IrrlichtDevice *device = createDevice( video::EDT_OPENGL,dimension2du(800,600),32,false,false,true);
 
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
 
    SMesh* pMesh = new SMesh();
    SMeshBuffer *pBuffer = new SMeshBuffer();
    pMesh->addMeshBuffer(pBuffer);
    pBuffer->drop();
    int nVertices = 4;
    
    pBuffer->Vertices.reallocate(nVertices);
    pBuffer->Vertices.set_used(nVertices);
    pBuffer->Vertices[0] = S3DVertex2TCoords(-1,1,0, 0,0,1,    video::SColor(255,255,255,255), 0,0,0,0);
    pBuffer->Vertices[1] = S3DVertex2TCoords(1,1,0, 0,0,1,    video::SColor(255,255,255,255), 1,0, 1,0);
    pBuffer->Vertices[2] = S3DVertex2TCoords(1,-1,0, 0,0,1,    video::SColor(255,255,255,255), 1,1,1,1);
    pBuffer->Vertices[3] = S3DVertex2TCoords(-1,-1,0, 0,0,1,    video::SColor(255,255,255,255), 0,1,0,1);
 
    pBuffer->Indices.reallocate(6);
    pBuffer->Indices.set_used(6);
    pBuffer->Indices[0]=0;
    pBuffer->Indices[1]=1;
    pBuffer->Indices[2]=2;
    pBuffer->Indices[3]=0;
    pBuffer->Indices[4]=2;
    pBuffer->Indices[5]=3;
     
    ISceneNode *node = smgr->addMeshSceneNode(pMesh);
 
    node->setMaterialFlag(EMF_LIGHTING, false);
 
    video::IImage* tImg1 = driver->createImage(ECF_A8R8G8B8, core::dimension2du(128,128));
    video::IImage* tImg2 =  driver->createImage(ECF_A8R8G8B8, core::dimension2du(128,128));
    tImg1->fill(SColor(255,255,0,0));
    tImg2->fill(SColor(128,255,255,255));
    ITexture *texture1 = driver->addTexture("texture1", tImg1);     
    ITexture *texture2 = driver->addTexture("texture2", tImg2);         
    tImg1->drop(); 
    tImg2->drop(); 
 
    node->setMaterialTexture(0, texture1);
    node->setMaterialTexture(1, texture2);
    node->setMaterialType(E_MATERIAL_TYPE::EMT_TRANSPARENT_ALPHA_CHANNEL);
 
    smgr->addCameraSceneNode(0, vector3df(0,0,-4), vector3df(0,0,1));
 
    int i=0;
    while(device->run())
    {
        driver->beginScene(true, true, SColor(255,255,255,255));
        smgr->drawAll();        
        if(i>50)
        {
            driver->draw2DRectangle(video::SColor(255,0,0,0),core::rect<s32>(0,0,50,50));
        }
        driver->endScene();
        i++;
        i = i % 100;
    }
    device->drop();
    return 0;
}
 
Just run it: it should display a red square and alternatively a 2D black rectangle. The red quad is displayed correctly when the black rectangle is not displayed but when the black rectangle is displayed, the red quad does not use anymore the alpha value of the second texture

Image

I did check the code and I guess the problem is here:

Code: Select all

 
void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)
{
    if (CurrentRenderMode != ERM_2D || Transformation3DChanged)
    {
        // unset last 3d material
        if (CurrentRenderMode == ERM_3D)
        {
            if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
                MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
        }
 
Why do we unset this material? and how do I restore it ?

Thanks.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: texture not displayed on 3D object when using 2D drawing

Post by CuteAlien »

There's definitely something going wrong, although not quite the way you expect. What you labeled as "wrong" is actually how it should be per documentation. EMT_TRANSPARENT_ALPHA_CHANNEL should only use the first texture, the second one should always be ignored.

I can reproduce it with your test on OpenGL/Linux, but don't know right now what's causing it.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
AlainSE
Posts: 5
Joined: Wed Jun 12, 2013 8:27 am

Re: texture not displayed on 3D object when using 2D drawing

Post by AlainSE »

Thanks for the answer.

You are right, my label may be wrong.

I just did the exact same test with other materials type... and for a lot of types the quad changes if the 2d square is displayed or not. Seems there is something changed when doing 2D operations and not set back to correct value when returning to 3D... I am analyzing the code but I am no expert in OpenGL so I am a bit lost.

I'll continue to investigate.
AlainSE
Posts: 5
Joined: Wed Jun 12, 2013 8:27 am

Re: texture not displayed on 3D object when using 2D drawing

Post by AlainSE »

After some investigation, it seems the problem comes from the material himself:

Code: Select all

 
    virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
        bool resetAllRenderstates, IMaterialRendererServices* services)
    {
        Driver->disableTextures(1);
...
 
If I remove "Driver->disableTextures(1):" the second texture is always used (as I (wrongly) expected).

It seems this disableTexture() call does not disable correctly the second texture in some cases, but I cannot help more.
Post Reply