Translation of texture doesn't work in gl_TextureMatrix

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.

Translation of texture doesn't work in gl_TextureMatrix

Postby randomMesh » Thu May 25, 2017 12:04 pm

Hi,

i think i've found a bug with CMatrix4::setTextureTranslate. :o

I scale and translate textures and therefore i want to access the texture matrix in my GLSL vertex shader.

So i tried this:
cpp Code: Select all
gl_TexCoord[0] = gl_TextureMatrix[0]*gl_MultiTexCoord0;

Doesn't do anything. Neither translation nor scale is accessible in TextureMatrix[0].

Next thing i tried was to send the texture matrix as a uniform variable to the shader:
cpp Code: Select all
 
this->textureMatrixID = services->getVertexShaderConstantID("tMatrix");
...
services->setVertexShaderConstant(this->textureMatrixID, reinterpret_cast<float*>(material.getTextureMatrix(0).pointer()), 16);
...
uniform mat4 tMatrix;
...
gl_TexCoord[0] = tMatrix * gl_MultiTexCoord0;
 

This only works for scale, translation doesn't work?!

Using this ugly workaround finally did it:
cpp Code: Select all
 
irr::core::matrix4 m;
irr::f32 tx, ty, sx, sy;
 
material.getTextureMatrix(0).getTextureTranslate(tx, ty);
material.getTextureMatrix(0).getTextureScale(sx, sy);
 
m.setTranslation(irr::core::vector3df(tx, ty, 0));
m.setScale(irr::core::vector3df(sx, sy, 1));
 
services->setVertexShaderConstant(this->textureMatrixID, reinterpret_cast<float*>(m.pointer()), 16);
 


So it seems there are two bugs:

1. Irrlichts texture matrix is not accessible in gl_TextureMatrix, it doesn't "inject" its values.
2. Irrlichts texture matrix stores its translation values in a place that is not accessible in gl_TextureMatrix when sent as a uniform variable, you have to copy the translation to an new matrix using translation rather than texture translation.


PS: It seems to have worked some time ago.
PPS: I am shader noob, did i miss something?
"Whoops..."
User avatar
randomMesh
 
Posts: 1178
Joined: Fri Dec 29, 2006 12:04 am

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby CuteAlien » Thu May 25, 2017 3:24 pm

We send it with glLoadMatrixf... which looks correct to me (don't really know other options). Strange stuff - I would have to write some example to reproduce that first - so can't say anything else right now.

edit: About your second solution. Irrlicht uses d3d texture matrices - so you can't send them directly like that. OpenGL driver has internally a function getGLTextureMatrix to transform matrices to OGL style (I also didn't know about that...).
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8528
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby randomMesh » Thu May 25, 2017 4:00 pm

I made a minimal compilable example which reproduces the problem.

There is a simple cube with a scaled texture.

The shader does nothing special, just display the texture 1:1. Unfortunately, the texture matrix gets ignored.

cpp Code: Select all
 
#include <irrlicht.h>
 
const irr::core::stringc vertexShader =
        "\
        void main(void)\
        {\
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\
            gl_TexCoord[0] = gl_TextureMatrix[0]*gl_MultiTexCoord0;\
        }"
;
 
const irr::core::stringc fragmentShader =
        "uniform sampler2D Texture;\
        \
        void main(void)\
        {\
            gl_FragColor = texture2D(Texture, gl_TexCoord[0].xy);\
        }"
;
 
class MyShaderCallBack: public irr::video::IShaderConstantSetCallBack
{
 
public:
 
    MyShaderCallBack() :
            TextureID(-1), FirstUpdate(true)
    {
    }
 
    virtual void OnSetConstants(irr::video::IMaterialRendererServices* services,
            irr::s32 userData)
    {
        //get shader constant id.
        if (this->FirstUpdate)
        {
            this->TextureID = services->getPixelShaderConstantID("Texture");
            this->FirstUpdate = false;
        }
 
        //set texture
        const irr::s32 TextureLayerID = 0;
        services->setPixelShaderConstant(this->TextureID, &TextureLayerID, 1);
    }
 
private:
 
    irr::s32 TextureID;
 
    bool FirstUpdate;
};
 
int main()
{
    irr::IrrlichtDevice* const device = irr::createDevice(
            irr::video::EDT_OPENGL, irr::core::dimension2du(800, 600));
 
    irr::video::IVideoDriver* const driver = device->getVideoDriver();
    irr::scene::ISceneManager* const smgr = device->getSceneManager();
 
    irr::scene::ICameraSceneNode* const camera = smgr->addCameraSceneNode(0,
            irr::core::vector3df(-0.5f, 1.5, -1.5f));
    camera->setTarget(irr::core::vector3df(0.5f, 0.5f, 0.5f));
 
    //shader
    irr::video::IGPUProgrammingServices* const gpu =
            driver->getGPUProgrammingServices();
 
    MyShaderCallBack* const mc = new MyShaderCallBack;
 
    irr::s32 shaderMaterialType = gpu->addHighLevelShaderMaterial(
            vertexShader.c_str(), "main", irr::video::EVST_VS_1_1,
            fragmentShader.c_str(), "main", irr::video::EPST_PS_1_1, mc);
 
    mc->drop();
 
    //mesh
    irr::scene::IMeshSceneNode* const cube = smgr->addCubeSceneNode(1.0f);
    cube->setMaterialTexture(0,
            driver->getTexture(
                    "./irrlicht-svn/media/wall.jpg"));
    cube->setMaterialFlag(irr::video::EMF_LIGHTING, false);
 
    //Scale the texture, should be accessible with gl_TextureMatrix[0]!
    cube->getMaterial(0).getTextureMatrix(0).setTextureScale(2.3, 4.2);
 
    //comment this to render the cube without shader (and scaled texture)
    cube->setMaterialType((irr::video::E_MATERIAL_TYPE) shaderMaterialType);
 
    while (device->run())
    {
        driver->beginScene();
        smgr->drawAll();
        driver->endScene();
    }
 
    device->drop();
 
    return 0;
}
 
"Whoops..."
User avatar
randomMesh
 
Posts: 1178
Joined: Fri Dec 29, 2006 12:04 am

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby hendu » Thu May 25, 2017 5:52 pm

Image

Works on my 1.7-based fork, so must be broken after that.
hendu
 
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby CuteAlien » Thu May 25, 2017 6:50 pm

Huh, just when I wanted to give up. Yeah - it also works in 1.8 it seems. Hm, guess then I can give it another check :-)

Btw.. for the workaround with passing it yourself you might give that a try:
cpp Code: Select all
 
core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0);
 

(just seen that one used in the ogles2 code). Meaning - don't convert the matrix yourself, but just use current matrix.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8528
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby CuteAlien » Thu May 25, 2017 7:02 pm

OK - seems this is deliberately disabled for shaders (and enabled for fixed function pipeline materials). Meaning - you _have_ to pass the info yourself. While I don't know the reason - my guesses are:
- I found several websites mentioning that using gl_MultiTexCoord0 is deprecated.
- Passing it always (even when it's mostly not necessary) probably adds some serious cost.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8528
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby randomMesh » Thu May 25, 2017 7:48 pm

CuteAlien wrote:
cpp Code: Select all
core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0);

Only works for scale. Translation is ignored too.
CuteAlien wrote:I found several websites mentioning that using gl_MultiTexCoord0 is deprecated.

gl_MultiTexCoord0 and gl_TextureMatrix are deprecated, yes. Full list of deprecated built-in variables in GLSL Shaders. I try to find the replacements. Thanks!
"Whoops..."
User avatar
randomMesh
 
Posts: 1178
Joined: Fri Dec 29, 2006 12:04 am

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby CuteAlien » Thu May 25, 2017 8:33 pm

randomMesh wrote:Only works for scale. Translation is ignored too.


Hm, strange - I'll have to check that (not today, still have to do something else, maybe weekend).
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8528
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby Nadro » Tue May 30, 2017 9:16 pm

CuteAlien wrote:OK - seems this is deliberately disabled for shaders (and enabled for fixed function pipeline materials). Meaning - you _have_ to pass the info yourself. While I don't know the reason - my guesses are:
- I found several websites mentioning that using gl_MultiTexCoord0 is deprecated.
- Passing it always (even when it's mostly not necessary) probably adds some serious cost.

Yes, we disabled stuff like gl_TextureMatrix[N] (+other functions deprecated in OpenGL 3.0) for shader based materials due to a performance reasons.

@randomMesh
As CuteAlien said, you can use IVideoDriver::getTransform and pass this matrix manually.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
 
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby randomMesh » Tue May 30, 2017 9:21 pm

Nadro wrote:@randomMesh
As CuteAlien said, you can use IVideoDriver::getTransform and pass this matrix manually.

I tried this but it only works for scaling. Translation is ignored.
"Whoops..."
User avatar
randomMesh
 
Posts: 1178
Joined: Fri Dec 29, 2006 12:04 am

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby CuteAlien » Tue May 30, 2017 10:36 pm

@randomMesh: Sorry, haven't check it out yet. My suspicion (without coding yet) would be that you try to set translation and scaling in the same matrix and one overwrites the other. But maybe I' on the wrong track as it would also fail without shaders in that case. I hope I'll get to it later this week.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8528
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby randomMesh » Wed May 31, 2017 8:41 am

CuteAlien wrote:@randomMesh: My suspicion (without coding yet) would be that you try to set translation and scaling in the same matrix and one overwrites the other.

No, i set scale for one buffer and translate for another buffer. These values are altered in my update method in case it makes a difference.
cpp Code: Select all
 
...
this->buffer[0].Material.TextureLayer[0].getTextureMatrix().setTextureTranslate(x, y);
...
this->buffer[1].Material.TextureLayer[0].getTextureMatrix().setTextureScale(scale, scale);
 
driver->beginScene();
 
"Whoops..."
User avatar
randomMesh
 
Posts: 1178
Joined: Fri Dec 29, 2006 12:04 am

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby randomMesh » Thu Jun 01, 2017 12:16 pm

Sorry for bumping, but i just made an example which uses the suggested method to send
cpp Code: Select all
core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0);

as a uniform variable.

As you can see in the screenshot, only scaling works this way. (Bottom left cube is the shader one, bottom right is textured with the transformations applied, top cube is the plain texture without any transformation). 1 and 2 should look the same, but they don't!

http://imgur.com/a/yPE4A

Example code:
cpp Code: Select all
 
#include <irrlicht.h>
 
const irr::core::stringc vertexShader =
        "uniform mat4 matrix;\
        void main(void)\
        {\
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\
            gl_TexCoord[0] = matrix*gl_MultiTexCoord0;\
        }"
;
 
const irr::core::stringc fragmentShader =
        "uniform sampler2D Texture;\
        \
        void main(void)\
        {\
            gl_FragColor = texture2D(Texture, gl_TexCoord[0].xy);\
        }"
;
 
class MyShaderCallBack: public irr::video::IShaderConstantSetCallBack
{
 
public:
 
    MyShaderCallBack() :
            TextureID(-1), textureMatrixID(-1), FirstUpdate(true)
    {
    }
 
    virtual void OnSetConstants(irr::video::IMaterialRendererServices* services,
            irr::s32 userData)
    {
        //get shader constant id.
        if (this->FirstUpdate)
        {
            this->TextureID = services->getPixelShaderConstantID("Texture");
            this->textureMatrixID = services->getPixelShaderConstantID(
                    "matrix");
            this->FirstUpdate = false;
        }
 
        //set texture
        const irr::s32 TextureLayerID = 0;
        services->setPixelShaderConstant(this->TextureID, &TextureLayerID, 1);
 
        //set matrix;
        const irr::core::matrix4& matrix =
                services->getVideoDriver()->getTransform(
                        irr::video::ETS_TEXTURE_0);
        services->setVertexShaderConstant(this->textureMatrixID,
                matrix.pointer(), 16);
    }
 
private:
 
    irr::s32 TextureID;
 
    irr::s32 textureMatrixID;
 
    bool FirstUpdate;
};
 
/**
 * Determines if a point is inside a circle.
 *
 * \param x The x coordinate of the point
 * \param y The y coordinate of the point
 * \param cx The x coordinate of the center of the circle
 * \param cy The y coordinate of the center of the circle
 * \param radius The radius of the circle
 * \return True if point is inside circle
 */

bool isInCircle(const irr::u32 x, const irr::u32 y, const irr::u32 cx,
        const irr::u32 cy, const irr::u32 radius)
{
    const irr::u32 dx = x - cx;
    const irr::u32 dy = y - cy;
    const irr::u32 distance = dx * dx + dy * dy;
 
    return distance < (radius * radius);
}
 
irr::video::IImage* createJapaneseFlagImage(irr::video::IVideoDriver* driver,
        const irr::core::dimension2du& size = irr::core::dimension2du(512, 512),
        const irr::video::SColor& foregroundColor = irr::video::SColor(255, 199,
                0, 37), const irr::video::SColor& backgroundColor =
                irr::video::SColor(255, 255, 255, 255))
{
    static const unsigned int BITDEPTH = 4;
    const unsigned int dataSize = size.Width * size.Height * BITDEPTH;
    irr::u8 imageData[dataSize];
 
    const irr::u32 centerX = size.Width / 2;
    const irr::u32 centerY = size.Height / 2;
 
    irr::u32 radius = 0;
    if (centerX > centerY)
        radius = size.Height - centerY;
    else
        radius = size.Width - centerX;
 
    radius*=0.5f;
 
    for (irr::u32 i = 0; i < dataSize; i += BITDEPTH)
    {
        const irr::u32 x = (i / BITDEPTH) % size.Width;
        const irr::u32 y = i / (BITDEPTH * size.Width);
 
        if (isInCircle(x, y, centerX, centerY, radius))
        {
            //point is in circle, so draw in foreground color
            imageData[i] = foregroundColor.getBlue();
            imageData[i + 1] = foregroundColor.getGreen();
            imageData[i + 2] = foregroundColor.getRed();
            imageData[i + 3] = foregroundColor.getAlpha();
        }
        else //draw background
        {
            imageData[i] = backgroundColor.getBlue();
            imageData[i + 1] = backgroundColor.getGreen();
            imageData[i + 2] = backgroundColor.getRed();
            imageData[i + 3] = backgroundColor.getAlpha();
        }
    }
 
    void* data = &imageData[0];
    return driver->createImageFromData(irr::video::ECF_A8R8G8B8,
            irr::core::dimension2du(size.Width, size.Height), data);
}
 
int main()
{
    irr::IrrlichtDevice* const device = irr::createDevice(
            irr::video::EDT_OPENGL, irr::core::dimension2du(800, 600));
 
    irr::video::IVideoDriver* const driver = device->getVideoDriver();
    irr::scene::ISceneManager* const smgr = device->getSceneManager();
 
    irr::scene::ICameraSceneNode* const camera = smgr->addCameraSceneNode(0,
            irr::core::vector3df(1.0f, 1.0, -3.5f));
    camera->setTarget(irr::core::vector3df(1.0f, 0.5f, 0.5f));
 
    //shader
    irr::video::IGPUProgrammingServices* const gpu =
            driver->getGPUProgrammingServices();
 
    MyShaderCallBack* const mc = new MyShaderCallBack;
 
    irr::s32 shaderMaterialType = gpu->addHighLevelShaderMaterial(
            vertexShader.c_str(), "main", irr::video::EVST_VS_1_1,
            fragmentShader.c_str(), "main", irr::video::EPST_PS_1_1, mc);
 
    mc->drop();
 
    //make texture out of an IImage
    irr::video::IImage* image = createJapaneseFlagImage(driver);
    irr::video::ITexture* texture = driver->addTexture("Another texture", image);
    image->drop();
 
    //shared material
    irr::video::SMaterial material;
    material.Lighting = false;
    material.TextureLayer[0].Texture = texture;
    material.TextureLayer[0].getTextureMatrix().setTextureScale(2, 2);
    material.TextureLayer[0].getTextureMatrix().setTextureTranslate(0.5, 0);
 
    //cube 1 with shader
    {
        irr::scene::IMeshSceneNode* node = smgr->addCubeSceneNode(1.0f);
        node->getMaterial(0) = material;
        node->setMaterialType((irr::video::E_MATERIAL_TYPE) shaderMaterialType);
    }
 
    //cube 2 without shader
    {
        irr::scene::IMeshSceneNode* node = smgr->addCubeSceneNode(1.0f, 0, -1,
                irr::core::vector3df(1.5, 0, 0));
        node->getMaterial(0) = material;
    }
 
    //cube 3 with vanilla texture
    {
        irr::scene::IMeshSceneNode* node = smgr->addCubeSceneNode(1.0f, 0, -1,
                irr::core::vector3df(1.0, 1.5, 0.0));
        node->setMaterialTexture(0, texture);
        node->setMaterialFlag(irr::video::EMF_LIGHTING, false);
    }
 
    while (device->run())
    {
        driver->beginScene();
        smgr->drawAll();
        driver->endScene();
    }
 
    device->drop();
 
    return 0;
}
 
 
"Whoops..."
User avatar
randomMesh
 
Posts: 1178
Joined: Fri Dec 29, 2006 12:04 am

Re: Translation of texture doesn't work in gl_TextureMatrix

Postby CuteAlien » Thu Jun 01, 2017 5:58 pm

Workaround for now:
cpp Code: Select all
 
void D3DtoGLTextureMatrix(irr::core::matrix4& m)
{
    m[2] = 0.f;
    m[3] = 0.f;
 
    m[6] = 0.f;
    m[7] = 0.f;
 
    m[12] = m[8];
    m[13] = m[9];
    m[8] = 0.f;
    m[9] = 0.f;
    m[10] = 1.f;
    m[11] = 0.f;
 
 
    m[14] = 0.f;
    m[15] = 1.f;
}
 


Call D3DtoGLTextureMatrix on your matrix before sending it.
Note that this function doesn't work when you used setTextureTranslateTransposed on the matrix.

There should obviously be a converter function in the matrix and the setTexture functions whould all mention that they are for d3d (and maybe additional functions for opengl). Just not adding that now because of the setTextureTranslateTransposed not being supported (I got the conversion function out of opengl driver where it's wrong already).

Or maybe it should even convert it internally at some point (but might be somewhat tricky getting that working without breaking all user-apps).

Also seems you are not the only person who got trapped by that - the code in the ogles2 driver and the COpenGLMaterialRenderer_SPHERE_MAP materials also don't seem to do that stuff (might be correct in COpenGLMaterialRenderer_SPHERE_MAP, but probably wrong in ogles2).

Sorry, got too much stuff right now on my todo's to dig deeper into this currently - but with the conversion function it should at least work now.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
CuteAlien
Admin
 
Posts: 8528
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany


Return to Bug reports

Who is online

Users browsing this forum: No registered users and 1 guest