Page 1 of 1

Problem with more than 4 texture layers - Irrlicht 1.7.1

Posted: Tue Jun 15, 2010 5:35 pm
by andres
I've an problem to set more than 4 texture layers. Look what i've done:

1 - Unzip Official Irrlicht 1.7.1 package
2 - Change irrCompileConfig.h to support 8 layers:

Code: Select all

#define _IRR_MATERIAL_MAX_TEXTURES_ 8
3 - run "make" in console.


when i try to set the fourth layer (using GLSL) the mesh is rendered with no texture (just black).


here's my code:

Code: Select all

#include <irrlicht.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:

	virtual void OnSetConstants(video::IMaterialRendererServices* services,
			s32 userData)
	{
	    int d[]	= {0, 1, 2, 3, 4};		//Sampler2d IDs
	    services->setPixelShaderConstant("myTexture",(float*)&d[4],1);
	}
};

int main(int argc, char** argv)
{
    IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0);

    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();

    ISceneNode* node = smgr->addCubeSceneNode(10);

    MyShaderCallBack* mc = new MyShaderCallBack();

    static s32 material=smgr->getVideoDriver()->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles(
        "shader.vert", "vertexMain", video::EVST_VS_3_0,
        "shader.frag", "pixelMain", video::EPST_PS_3_0,
        mc, video::EMT_SOLID);

    node->setMaterialTexture(0,driver->getTexture("L0.png"));
    node->setMaterialTexture(1,driver->getTexture("L1.jpg"));
    node->setMaterialTexture(2,driver->getTexture("L2.jpg"));
    node->setMaterialTexture(3,driver->getTexture("L3.jpg"));
    node->setMaterialTexture(4,driver->getTexture("L4.jpg"));

    node->setMaterialFlag(EMF_LIGHTING,false);
    node->setMaterialType((E_MATERIAL_TYPE)material);

    smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));

    while(device->run())
    {
        driver->beginScene(true, true, SColor(0,200,200,200));

        smgr->drawAll();
        guienv->drawAll();

        driver->endScene();
    }
    device->drop();

    return 0;
}
GLSL vertex program:

Code: Select all

void main(void)
{
	gl_Position = ftransform();
	gl_TexCoord[0] = gl_MultiTexCoord0;
}
GLSL fragment program:

Code: Select all

uniform sampler2D myTexture;

void main (void)
{
    gl_FragColor = texture2D(myTexture, vec2(gl_TexCoord[0]));
}
Why does not work? there is anything else i need to do before compile irrlicht?

PS: OpenSUSE 11.2 + OpenGL 3.2.0 + GLSL 1.5 on Nvidia 9500M GS.

Posted: Tue Jun 15, 2010 11:43 pm
by Viz_Fuerte
This seems have, easy solution.

You have compiled well the Irrlicht and the problem is in the code and the programming of the GLSL.

You can do this the way I was doing, or do it this way, but always stating the textures in the GLSL.

In the code needed something like this:

Code: Select all

class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:

   virtual void OnSetConstants(video::IMaterialRendererServices* services,
         s32 userData)
   {
       int d[]   = {0, 1, 2, 3, 4};      //Sampler2d IDs
       services->setPixelShaderConstant("myTexture0",(float*)&d[0],1);
       services->setPixelShaderConstant("myTexture1",(float*)&d[1],1);
       services->setPixelShaderConstant("myTexture2",(float*)&d[2],1);
       services->setPixelShaderConstant("myTexture3",(float*)&d[3],1);
       services->setPixelShaderConstant("myTexture4",(float*)&d[4],1);
   }
};
And in the GLSL program:

Code: Select all

uniform sampler2D myTexture0;
uniform sampler2D myTexture1;
uniform sampler2D myTexture2;
uniform sampler2D myTexture3;
uniform sampler2D myTexture4;

void main (void)
{
//Here, we must modify the code to do what you want, multi texture, adder ...

..
..
..
    gl_FragColor = texture2D(myTexture0, vec2(gl_TexCoord[0]));
} 
I hope that this will be of assistance :wink:

Posted: Wed Jun 16, 2010 1:17 am
by andres
don't work.

apparently the OpenGL driver does not recognize my graphics card texture units limit.

In COpenGLExtensionHandler.h the driver try to get MaxTextureUnits, but in my case result apparent to be 4 (Wrong cause Geforce 9500 has 16 Texture Units). So i've changed the line:

Code: Select all

MaxTextureUnits=static_cast<u8>(num);
setting manually to 8 :

Code: Select all

MaxTextureUnits=8;
I now this is not a good solution, but i think it can be a bug (correct me if i'm wrong) and need to be resolved in irrlicht.

Posted: Wed Jun 16, 2010 2:21 am
by BlindSide
Interesting, nice find. Unfortunately since it's on Linux it's most likely just a driver bug, I'll have to test it under windows and see.

Moving to Bug Reports.

Posted: Wed Jun 16, 2010 8:00 am
by bmwop
I use something like this:

Code: Select all

diff -rupN irrlicht-1.7.1/source/Irrlicht/COpenGLExtensionHandler.cpp irrlicht-1.7.1_patch3/source/Irrlicht/COpenGLExtensionHandler.cpp
--- irrlicht-1.7.1/source/Irrlicht/COpenGLExtensionHandler.cpp  2010-02-14 13:04:58.000000000 +0100
+++ irrlicht-1.7.1_patch3/source/Irrlicht/COpenGLExtensionHandler.cpp 2010-06-11 09:41:42.000000000 +0200
@@ -467,6 +467,9 @@ void COpenGLExtensionHandler::initExtens
    {
        glGetIntegerv(GL_MAX_TEXTURE_UNITS, &num);
        MaxTextureUnits=static_cast<u8>(num);
+        glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num);
+        if (MaxTextureUnits<static_cast<u8>(num))
+            MaxTextureUnits=static_cast<u8>(num);
    }
 #endif
    glGetIntegerv(GL_MAX_LIGHTS, &num);

Posted: Wed Jun 16, 2010 5:40 pm
by andres
bmwop wrote:I use something like this:

Code: Select all

diff -rupN irrlicht-1.7.1/source/Irrlicht/COpenGLExtensionHandler.cpp irrlicht-1.7.1_patch3/source/Irrlicht/COpenGLExtensionHandler.cpp
--- irrlicht-1.7.1/source/Irrlicht/COpenGLExtensionHandler.cpp  2010-02-14 13:04:58.000000000 +0100
+++ irrlicht-1.7.1_patch3/source/Irrlicht/COpenGLExtensionHandler.cpp 2010-06-11 09:41:42.000000000 +0200
@@ -467,6 +467,9 @@ void COpenGLExtensionHandler::initExtens
    {
        glGetIntegerv(GL_MAX_TEXTURE_UNITS, &num);
        MaxTextureUnits=static_cast<u8>(num);
+        glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num);
+        if (MaxTextureUnits<static_cast<u8>(num))
+            MaxTextureUnits=static_cast<u8>(num);
    }
 #endif
    glGetIntegerv(GL_MAX_LIGHTS, &num);
Thanks, works fine.

Posted: Wed Jun 16, 2010 8:54 pm
by Nadro
Everything is ok, Irrlicht use GL_MAX_TEXTURE_UNITS as texture limit in OpenGL. On modern cards GL_MAX_TEXTURE_UNITS is equal 4 or 8. This number is important only for fixed function (glEnable/glDisable, glTexEnv, glGetTexEnv etc.) for programmable pipeline, so OpenGL 2.0+ You should use GL_MAX_TEXTURE_IMAGE_UNITS (for max avaiable textures in fragment shader), GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS (for vertex shader) and GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS (for geometry shader in OGL3.2).

Posted: Mon Aug 02, 2010 11:32 am
by wing64
I founded a problem same you on Geforce 9600 GS (update with lastest driver). Try set _IRR_MATERIAL_MAX_TEXTURES_ is 8 but opengl driver return 4 (used GL_MAX_TEXTURE_UNITS). When i change to GL_MAX_TEXTURE_IMAGE_UNITS_ARB my program will work correctly. This's good to change GL_MAX_TEXTURE_UNITS to GL_MAX_TEXTURE_IMAGE_UNITS_ARB or not ? Please suggestion me...
best regards,

Posted: Mon Aug 02, 2010 1:25 pm
by shine5128

Posted: Mon Aug 02, 2010 2:49 pm
by wing64
Thanks, It's clear. :D

Posted: Mon Aug 02, 2010 4:34 pm
by hybrid
Thanks for the link. This will definitely help to improve the current texture handling in Irrlicht.