[no bug] Texture Y flipped with OpenGL.

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.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

[no bug] Texture Y flipped with OpenGL.

Post by Foaly »

Textures are flipped along the Y axis when rendering with OpenGL, but not when rendering with D3D9.
I'm not that great writing C++ programs, so the code is just an altered example.
It just renders an image into a render target and then from the render target onto the screen.

Code: Select all

#include <irrlicht.h>
#include <iostream>
#include "driverChoice.h"
#include "exampleHelper.h"
 
using namespace irr;
 
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
 
IrrlichtDevice* device = 0;
 
class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:
    MyShaderCallBack() : WorldViewProjID(-1), FirstUpdate(true)
    {
    }
 
    virtual void OnSetConstants(video::IMaterialRendererServices* services,
            s32 userData)
    {
        video::IVideoDriver* driver = services->getVideoDriver();
 
        // get shader constants id.
 
        if (FirstUpdate)
        {
            WorldViewProjID = services->getVertexShaderConstantID("cameraTransformMatrix");
 
            // Textures ID are important only for OpenGL interface.
 
            if(driver->getDriverType() == video::EDT_OPENGL)
                TextureID = services->getVertexShaderConstantID("TexA");
 
            FirstUpdate = false;
        }
 
        // set clip matrix
 
        core::matrix4 worldViewProj;
        worldViewProj = driver->getTransform(video::ETS_PROJECTION);
        worldViewProj *= driver->getTransform(video::ETS_VIEW);
        worldViewProj *= driver->getTransform(video::ETS_WORLD);
 
        services->setVertexShaderConstant(WorldViewProjID, worldViewProj.pointer(), 16);
 
 
        // set texture, for textures you can use both an int and a float setPixelShaderConstant interfaces (You need it only for an OpenGL driver).
        s32 TextureLayerID = 0;
        services->setPixelShaderConstant(TextureID, &TextureLayerID, 1);
    }
 
private:
    s32 WorldViewProjID;
    s32 TextureID;
 
    bool FirstUpdate;
};
 
/*
The next few lines start up the engine just like in most other tutorials
before. But in addition, we ask the user if he wants to use high level shaders
in this example, if he selected a driver which is capable of doing so.
*/
int main()
{
    // ask user for driver
    video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (driverType==video::EDT_COUNT)
        return 1;
 
    // create device
 
    device = createDevice(driverType, core::dimension2d<u32>(640, 480));
 
    if (device == 0)
        return 1; // could not create selected driver.
 
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
    gui::IGUIEnvironment* gui = device->getGUIEnvironment();
 
    const io::path mediaPath = getExampleMediaPath();
 
    char* vsShaderProgram;
    char* psShaderProgram;
 
    switch(driverType)
    {
    case video::EDT_DIRECT3D9:
        vsShaderProgram =
"struct VS_INPUT\n"
"{\n"
"   float4 position : POSITION;\n"
"   float2 tcoord0  : TEXCOORD0;\n"
"};\n"
""
"struct VS_OUTPUT\n"
"{\n"
"   float4 position : POSITION;\n"
"   float2 tcoord0  : TEXCOORD0;\n"
"};\n"
""
"float4x4 cameraTransformMatrix;\n"
""
"VS_OUTPUT vertexMain(VS_INPUT input)\n"
"{\n"
"   VS_OUTPUT output;\n"
"   output.position = mul(input.position, cameraTransformMatrix);\n"
"   output.tcoord0 = input.tcoord0;\n"
"   return output;\n"
"}\n";
        psShaderProgram = 
"struct PS_OUTPUT\n"
"{\n"
"   float4 color    : COLOR;\n"
"};\n"
""
"struct PS_INPUT\n"
"{\n"
"   float4 position : POSITION;\n"
"   float2 tcoord0  : TEXCOORD0;\n"
"};\n"
""
"sampler2D texA;\n"
""
"PS_OUTPUT pixelMain(PS_INPUT input)\n"
"{\n"
"   PS_OUTPUT output;\n"
"   float4 color = tex2D(texA, input.tcoord0);\n"
"   output.color = color;\n"
"   return output;\n"
"}\n";
        break;
    case video::EDT_OPENGL:
        vsShaderProgram =
"uniform mat4 cameraTransformMatrix;\n"
""
"void main(void)\n"
"{"
"   gl_Position = cameraTransformMatrix * gl_Vertex;\n"
"   gl_TexCoord[0] = gl_MultiTexCoord0;\n"
"}\n";
        psShaderProgram =
"uniform sampler2D texA;\n"
""
"void main(void)\n"
"{\n"
"   vec4 color = texture(texA, gl_TexCoord[0]);\n"
"   gl_FragColor = color;\n"
"}\n";
        break;
    }
 
    video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
    s32 newMaterialType = 0;
 
    if (gpu)
    {
        MyShaderCallBack* mc = new MyShaderCallBack();
 
        const video::E_GPU_SHADING_LANGUAGE shadingLanguage = video::EGSL_DEFAULT;
        newMaterialType = gpu->addHighLevelShaderMaterial(
            vsShaderProgram, "vertexMain", video::EVST_VS_2_0,
            psShaderProgram, "pixelMain", video::EPST_PS_3_0,
            mc, video::EMT_SOLID, 0, shadingLanguage);
 
        mc->drop();
    }
 
    //simple material with any image on it.
    video::SMaterial material1 = video::SMaterial();
    material1.setTexture(0, driver->getTexture(mediaPath + "irrlichtlogo.bmp"));
    material1.setFlag(video::EMF_LIGHTING, false);
    material1.setFlag(video::EMF_BACK_FACE_CULLING, false);
    material1.MaterialType = ((video::E_MATERIAL_TYPE)newMaterialType);
 
    video::ITexture* targetTex1 = driver->addRenderTargetTexture(core::dimension2du(1280, 720), "target1");
 
    //second material has the render target as a texture
    video::SMaterial material2 = video::SMaterial(material1);
    material2.setTexture(0, targetTex1);
 
    float zValue = -0.5f;
    video::SColor defaultColor = video::SColor(255, 255, 255, 255);
 
    // 0 - 1
    // 2 - 3
    video::S3DVertex quadVerts[4] =
    {
        video::S3DVertex(core::vector3df(-.5f,+.5f,zValue), core::vector3df(0), defaultColor, core::vector2df(0,0)),
        video::S3DVertex(core::vector3df(+.5f,+.5f,zValue), core::vector3df(0), defaultColor, core::vector2df(1,0)),
        video::S3DVertex(core::vector3df(-.5f,-.5f,zValue), core::vector3df(0), defaultColor, core::vector2df(0,1)),
        video::S3DVertex(core::vector3df(+.5f,-.5f,zValue), core::vector3df(0), defaultColor, core::vector2df(1,1))
    };
    u16 quadIndices[6] =
    {
        0, 1, 2,
        1, 3, 2
    };
 
    core::matrix4 projectMatrix = core::matrix4();
    core::matrix4 worldMatrix = core::matrix4();
    core::matrix4 cameraMatrix = core::matrix4();
    cameraMatrix = cameraMatrix.buildProjectionMatrixOrthoRH(1.0f, 1.0f, 0.01f, 100.0f);
 
    int lastFPS = -1;
 
    while(device->run())
        if (device->isWindowActive())
    {
        driver->beginScene(video::ECBF_ALL, video::SColor(255,0,0,0));
 
        driver->setTransform(video::ETS_PROJECTION, projectMatrix);
        driver->setTransform(video::ETS_WORLD, worldMatrix);
        driver->setTransform(video::ETS_VIEW, cameraMatrix);
 
 
        //render on the first render target
        driver->setRenderTarget(targetTex1, video::ECBF_ALL);
        driver->setMaterial(material1);
        driver->drawVertexPrimitiveList(quadVerts, 4, quadIndices, 2);
 
        //render on the second render target
        driver->setRenderTarget(nullptr);
        driver->setMaterial(material2);
        driver->drawVertexPrimitiveList(quadVerts, 4, quadIndices, 2);
 
        driver->endScene();
 
        int fps = driver->getFPS();
 
        if (lastFPS != fps)
        {
            core::stringw str = L"Irrlicht Engine - Y flipping bug [";
            str += driver->getName();
            str += "] FPS:";
            str += fps;
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }
 
    device->drop();
 
    return 0;
}
As you can see, the code already contains the shaders, but here they are again, so they are easier to read:
OpenGL:

Code: Select all

//Vertex Shader:
uniform mat4 cameraTransformMatrix;
 
void main(void)
{
    gl_Position = cameraTransformMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
}
 
//Pixel Shader:
uniform sampler2D texA;
 
void main(void)
{
    vec4 color = texture(texA, gl_TexCoord[0]);
    gl_FragColor = color;
}
Direct3D9:

Code: Select all

struct VS_INPUT
{
    float4 position : POSITION;
    float2 tcoord0  : TEXCOORD0;
};
 
struct VS_OUTPUT
{
    float4 position : POSITION;
    float2 tcoord0  : TEXCOORD0;
};
 
float4x4 cameraTransformMatrix;
 
VS_OUTPUT vertexMain(VS_INPUT input)
{
    VS_OUTPUT output;
    output.position = mul(input.position, cameraTransformMatrix);
    output.tcoord0 = input.tcoord0;
    return output;
}
 
struct PS_OUTPUT
{
    float4 color    : COLOR;
};
 
struct PS_INPUT
{
    float4 position : POSITION;
    float2 tcoord0  : TEXCOORD0;
};
 
sampler2D texA;
 
PS_OUTPUT pixelMain(PS_INPUT input)
{
    PS_OUTPUT output;
    float4 color = tex2D(texA, input.tcoord0);
    output.color = color;
    return output;
}
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Texture Y flipped with OpenGL.

Post by CuteAlien »

Seems to be something new. When running in Irrlicht 1.8 (with a few changes to get it to compile) it still works.
Also when using non-shader materials it works (in trunk as well). Only fails with shader-material (for second material, first one doesn't matter) and in trunk and with opengl. Maybe related to changed texture lock()?
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
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Texture Y flipped with OpenGL.

Post by Nadro »

It's related to OpenGL and textures origin at the lower left corner. During v1.9 development process we disabled some stuff for shader based materials like an auto flip for RT texture matrices in OpenGL, because it caused unnecessary overhead (you can flip UV directly in the shader code).
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Texture Y flipped with OpenGL.

Post by Foaly »

So it's supposed to be that way and it will stay like that?
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Texture Y flipped with OpenGL.

Post by CuteAlien »

No can't stay. That would mean this is a specific behavior for one driver, specific materials and depending on the texture-type! You change any of those 3 and the texture flips. That's not good.
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
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Texture Y flipped with OpenGL.

Post by Nadro »

It's really a corner case. Why we want to force all users to worse performance. I understand that it should be flipped in built-in fixed-pipeline materials, because users don't have control of them, but in the shaders it's not a problem anymore.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Texture Y flipped with OpenGL.

Post by CuteAlien »

It's highly confusing. You have to write different shaders now based on texture-type as it does not flip the usual textures. The cost was always there, but looks like in the past it was decided that it was worth to handle this in the engine so the users won't have to care. If we stop caring about this the engine usability is worse than what we already had. If you want to add a flag to get optimized behavior for experts - that's fine. But please don't make this the default.
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
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Texture Y flipped with OpenGL.

Post by Nadro »

OK, we would add compile-time optimization flag (disabled at default), however please remember that it will not work for OpenGL ES2.0+ and OpenGL 3.x Core Profile+ (second option is still unavailable in Irrlicht). Please also remember that if you use shaders you still need to write driver specific shaders and for most of OpenGL/GLSL programmers situation with 'flipped' FBO is normal, thats why I think that it shouldn't be a problem (texture matrices overhead is really high and if more texture unit will be active overhead will be even higher, at now we just have 4 active texture units per SMaterial at default, but user can change this value).

BTW. You don't have to write different shaders for RT and normal textures. You can send texture matrix as an uniform (at this case user just send this matrix if it's required). In GLSL (vertex shader) you just need to multiply tex coords by matrix eg:
vec2 goodUV = vec4(TexMatrixPassedAsUniform * gl_MultiTexCoord0).xy;
Most of the time RT textures are used at post processing effects with full screen quad, where you can set UV what you want, so you don't even need FlippedTextureMatrix passed as uniform (the best performance). If you use shaders there is a few solutions for this problem.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Texture Y flipped with OpenGL.

Post by CuteAlien »

You could also use a runtime-flag. We got a few of those for textures.
Having different results in opengl es is obviously also not good :-(
Why is OpenGL flipping rendertarget textures...?
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
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: Texture Y flipped with OpenGL.

Post by Foaly »

As long as it's documented, I don't think that it would be a big problem if OpenGL just kept flipping the render target.
It only happens if you're writing a shader anyway and it can be fixed easily if you're aware of it.
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Texture Y flipped with OpenGL.

Post by CuteAlien »

I think it was that way in the past. Not a big problem but one of the regular kind where every programmer runs into it again and wastes hours. Which is why you should have a 3D engine which cares about it for you. I can't say this is something important to me, but if we don't do that we will be back to regular posts and irc questions about this. Having it just work (as in Irrlicht 1.8) is simply nice to have. And yeah - speed hit is ugly... tech is just in a state where you can't do things perfect anymore.
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
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Texture Y flipped with OpenGL.

Post by hendu »

FYI, in 1.7 I disabled the auto-flipping, because when chaining multiple RTTs it resulted in randomly flipped or not image (if the number of RTTs was divisible by 2 or not).
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Texture Y flipped with OpenGL.

Post by Nadro »

Flipping ping-pong mentioned by Hendu is another reason why this thing should stay as it is now.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Texture Y flipped with OpenGL.

Post by CuteAlien »

Was that still happening in Irrlicht 1.8?

It's pretty horrible, but if OpenGL really doesn't allow working around that in a sane way then I guess there's nothing we can do.
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
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Texture Y flipped with OpenGL.

Post by hendu »

I don't know, I haven't used 1.8.

Recent GL has a "be like DX" extension which changes the origin, depth, and some other things.
Post Reply