Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Texture coordinates on GLSL (shaders)  (Read 9934 times)

0 Members and 1 Guest are viewing this topic.

Karleon

  • Newbie
  • *
  • Posts: 18
    • View Profile
Texture coordinates on GLSL (shaders)
« on: April 14, 2013, 01:31:48 am »
Hello,

I think I have run into a bug, or at the very least an inconsistency in the behaviour.

The scenenario is the following:

  • I have a sprite, with some kind of drawing.
  • I want to use a shader on it, using another texture as a mask


I was not able to make it work correctly, and the mask texture seemed to be upside down. I though that this was because I forgot to use the .display() function on my rendertexture after drawing the mask on it. That was not the case, and decided to construct a minimal example, and I found out the following behaviour:

When you pass a texture to a shader, the coordinate system is different depending on the texture loaded:
  • If the texture was loaded from  a file, the top-left corner of the texture is the point (0,0) and the bottom-right corner is the point (1,1).
  • If the texture is from a renderTexture, the bottom-left corner of the texture is the point (0,0) and the top-right corner is the point (1,1).


This means that one of the coordinate system is upside down.
Since this example needs of several files (the code, the shader and a couple of images) I have packed them into a file and attached it to the post.

Here is what is displayed in the example:



1. The target sprite
2. The renderTexture mask
3. The renderTexture's texture drawn over the target sprite
4. The texture loaded from a file
5. The texture drawn over the target sprite


Is this behaviour expected? Should one of the coordinate system be changed to be consistent between each other?


I hope the example is clear enough. If you have any question about it, please ask so I can clarify it.


[attachment deleted by admin]

Ancurio

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Re: Texture coordinates on GLSL (shaders)
« Reply #1 on: April 14, 2013, 05:38:43 am »
Are you sure you called ".display()" on the renderTexture after drawing to it?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Texture coordinates on GLSL (shaders)
« Reply #2 on: April 14, 2013, 09:56:37 am »
In the vertex shader you must apply the texture matrix to your texture coordinates. Look at the Shader example of the SFML SDK.
Laurent Gomila - SFML developer

Karleon

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Texture coordinates on GLSL (shaders)
« Reply #3 on: April 14, 2013, 04:18:06 pm »
Are you sure you called ".display()" on the renderTexture after drawing to it?

I checked and double checked, and this was not the case.

In the vertex shader you must apply the texture matrix to your texture coordinates. Look at the Shader example of the SFML SDK.
Shouldn't the default vertex shader apply the appropiate matrix on the target texture?

I have used the following shader, over a file loaded texture and over a renderTexture made texture:

        vec2 position = gl_TexCoord[0].xy;
        vec4 pixel;
       
        pixel.r=position.y;
        pixel.a=1.0;
       
        gl_FragColor = pixel;
 

The following image is the result of the shader being applied to different textures:


The top rectangle is the renderTexture-made texture, and the bottom one the one loaded from a file.
As you can see from the shader, the color red of each pixel is equals the y value of the texture's coordinate.
Only the shader has been cutomized, and in the openGL documentation you can read the following (http://www.opengl.org/sdk/docs/manglsl/ in "gl_FragCoord" under the "Built-in Variables") :

Quote
By default, gl_FragCoord assumes a lower-left origin for window coordinates and assumes pixel centers are located at half-pixel centers.
As far as I know, this looks like the default behaviour of gl_FragCoord is not being respected, something is changed in the loading process of the textures in SFML that is modifying the default behaviour on GLSL.

« Last Edit: April 14, 2013, 04:19:51 pm by Karleon »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Texture coordinates on GLSL (shaders)
« Reply #4 on: April 14, 2013, 06:10:07 pm »
Quote
Shouldn't the default vertex shader apply the appropiate matrix on the target texture?
It does, but since you didn't give any detail at all about your shader(s), I assumed you had your own vertex shader.

Please give us a complete and minimal code that reproduces the problem. And test the Shader example of SFML, this one works fine and has both textures loaded from file or from render-texture.
« Last Edit: April 14, 2013, 08:23:22 pm by Laurent »
Laurent Gomila - SFML developer

Karleon

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Texture coordinates on GLSL (shaders)
« Reply #5 on: April 14, 2013, 07:19:32 pm »
Here is a complete and minimal code of the issue at hand:
#include <SFML/Graphics.hpp>





int main()
{

    sf::RenderWindow m_window;

    sf::Sprite maskSprite;
    sf::RenderTexture maskRender;
    sf::Texture maskTexture;

    sf::Shader shader;

    m_window.create(sf::VideoMode(800, 600), "Fragment shader!");


     //Setup our file-loaded mask
    maskTexture.loadFromFile("mask.png");

    //Setup our renderTexture-made mask
    maskRender.create(maskTexture.getSize().x, maskTexture.getSize().y);
    maskRender.clear(sf::Color(0,0,0,255));
    maskRender.display();


    //Load the shader
    shader.loadFromFile("fragment.frag",sf::Shader::Fragment);

    while(m_window.isOpen())
    {
        sf::Event event;
        while(m_window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                m_window.close();
        }

        //We load the mask texture loaded from a file into the sprite and draw it, so we can compare it to the result
        maskSprite.setTexture(maskTexture);
        maskSprite.setPosition(256,300);
        m_window.draw(maskSprite , &shader);

        //We load the render-made mask into the sprite and draw it, so we can compare it to the result
        maskSprite.setTexture(maskRender.getTexture());
        maskSprite.setPosition(0,0);
        m_window.draw(maskSprite, &shader);

        m_window.display();
    }

}

 

The shader is the following:


void main()
{
        vec2 position = gl_TexCoord[0].xy;
       
       
       
        vec4 pixel;
       
        pixel.r=position.y;
        pixel.a=1.0;


       
        gl_FragColor = pixel;
}

You just need an image with the name "mask.png"



Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Texture coordinates on GLSL (shaders)
« Reply #6 on: April 14, 2013, 08:38:49 pm »
Thanks.

The texture coordinates are inverted because the texture produced by sf::RenderTexture is inverted (because of FBO). So I don't know what your initial idea was, but don't do it this way ;)

PS: all SFML resources can be created directly in source code, which is more convenient for me when you submit a minimal example

#include <SFML/Graphics.hpp>

const char* fragmentShader =
    "void main()"
    "{"
    "    gl_FragColor = vec4(gl_TexCoord[0].y, 0.0, 0.0, 1.0);"
    "}"
    ;

int main()
{
    sf::RenderWindow m_window(sf::VideoMode(800, 600), "Fragment shader!");

    // Setup our file-loaded mask
    sf::Image image;
    image.create(100, 100, sf::Color::Green);
    sf::Texture maskTexture;
    maskTexture.loadFromImage(image);

    // Setup our renderTexture-made mask
    sf::RenderTexture maskRender;
    maskRender.create(maskTexture.getSize().x, maskTexture.getSize().y);
    maskRender.clear(sf::Color(0, 0, 0, 255));
    maskRender.display();

    // Load the shader
    sf::Shader shader;
    shader.loadFromMemory(fragmentShader, sf::Shader::Fragment);

    sf::Sprite maskSprite;

    while (m_window.isOpen())
    {
        sf::Event event;
        while (m_window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                m_window.close();
        }

        // We load the mask texture loaded from a file into the sprite and draw it, so we can compare it to the result
        maskSprite.setTexture(maskTexture);
        maskSprite.setPosition(0, 300);
        m_window.draw(maskSprite, &shader);

        // We load the render-made mask into the sprite and draw it, so we can compare it to the result
        maskSprite.setTexture(maskRender.getTexture());
        maskSprite.setPosition(0, 0);
        m_window.draw(maskSprite, &shader);

        m_window.display();
    }

    return 0;
}
Laurent Gomila - SFML developer

Karleon

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Texture coordinates on GLSL (shaders)
« Reply #7 on: April 14, 2013, 10:27:03 pm »

The texture coordinates are inverted because the texture produced by sf::RenderTexture is inverted (because of FBO). So I don't know what your initial idea was, but don't do it this way ;)


I see, as long as this behaviour is consistent with sf::renderTexture's texture I can live with it on my code. I ran into this when I decided to draw a mask (renderTexture) I was using over a sprite's texture (loaded from a file), in order to check if it was correctly aligned, just to debug it.

So no real harm. Just wanted to let you guys know, just in case someone ran into this. Loving the library so far, so I was eager to report a bug, knowing I would be of some help.

Thanks!