How to translate a rectangle's texture/shader?

Hello, trying to figure out how to simply load an image as a texture into a shader so that I can can manipulate it therein…

I’m trying it this way…

void ofApp::setup(){
	ofImage img0;
	img0.load("a.jpg");
	m_tex0 = img0.getTexture();
	m_shader.load("textest");
}
void ofApp::draw(){
	m_shader.begin();
	m_shader.setUniformTexture("u_tex0", m_tex0,0);
	m_shader.setUniform2f("u_resolution", 1920, 1080);
	ofDrawRectangle(0, 0, 1920, 1080);
	m_shader.end();
}
uniform sampler2D u_tex0;
uniform vec2 u_resolution;
void main()
{
    vec2 coord = gl_FragCoord.xy / u_resolution;
    vec4 color =  texture2D(u_tex0,coord);
    gl_FragColor = color;
}

…and just get a black screen. Now I’ve previously used a blur shader where I didn’t set the u_tex0 value directly, but passed an image into fbos with the shader… is that the only correct way to use a shader on an image in oF?

For learning more about shaders, I’ve started with this tutorial series, but welcome any more suitable recommendations if the glsl version isn’t up to date or something… … one thing I notice is that the oF documentation says that setUniformTexture sets a sampler2DRect, whereas the variable in my shader (copied from that tutorial video) uses a sampler2D.

@s_e_p I guess it should work with this:
vec4 color = texture(u_tex0,coord);

Nope, still all black…

And this?
vec4 color = texture(u_tex0, gl_FragCoord.xy) / coord;

could you try

uniform sampler2DRect u_tex0;

and

vec2 coord = gl_FragCoord.xy;
vec4 color = texture2DRect(u_tex0,coord);

there are two ways to work with textures – sampler2D is for power of two textures and sampler2Drect for non power of two textures. by default, OF works with non power of two textures (except on iOS / android, IIRC) and so you’ll probably want to start to trying that. One note is that for sampler2D you refer to 0-1 in the shader and for sampler2Drect, you use 0-w, 0-h (not pcts) in terms of the coordinate you pass in

also if you want to use sampler2D – you can try this – which disables the non power of two texture

ofDisableArbTex();
img0.load(“a.jpg”);

there’s some info here

https://openframeworks.cc/ofBook/chapters/shaders.html

and if you search around the OF forum you may find other discussions of this.

Hey, that worked!.. except the image is mirrored upside-down for some reason.

What is ‘pcts’? You’re saying sampler2D only takes one value for its pixel position but sampler2Drect takes two? I’ll look at the link you posted tomorrow; it’s 4 am here… thanks for your help!

ah cool – sorry no I meant when you do this

vec2 coord = gl_FragCoord.xy / u_resolution;
vec4 color = texture2D(u_tex0,coord);

you are converting pixel coordinate into something like a fraction, from 0-1 in x and 0-1 in y. but when you use sampler2DRect, you refer to the pixels not between 0-1 but between 0-w and 0-h, like this

vec2 coord = gl_FragCoord.xy;
vec4 color = texture2DRect(u_tex0,coord);

(you’ll notice I don’t divide gl_FragCoord.xy by u_resolution)

the upside is a product of OF treating 0,0 like the top left corner and OpenGL having the bottom left corner be 0,0. You could do this (assuming your window is the same size as the image) to fix the flip

vec2 coord = gl_FragCoord.xy;
coord.y = u_resolution.y - coord.y;
vec4 color = texture2DRect(u_tex0,coord);

essentially flipping the coordinate in the shader.

Hey, thanks for the explanation. That’s easy to understand.

I wonder why I need to flip the y coordinate. Is that common?

a million years ago, we decided to make 0,0 the top left corner, to match photoshop / flash , etc. In OpenGL, 0,0 is the lower left corner. This means, sometimes, when translating from OF to GL or vice versa, you need to flip the y coordinate.

there are other ways to work with images in a shader, for example, you could draw the image and use the texture coordinate that are passed through to the shader in the shader vs using the fragment coordinate, that would not require a flip.

Hey, thanks for the explanation. I understand now and got a nice alpha-gradient working…

Since you’re here, I’ll trouble you with another question… how can I displace rectangles that have a shader texture on them? If I do this:

void ofApp::draw(){
	m_shader1.begin();	
	m_shader1.setUniformTexture("u_tex", m_tex1, 0);	
	m_shader1.setUniform2f("u_resolution", m_tex1.getWidth(), m_tex1.getHeight());
	ofDrawRectangle(500, 0, m_tex1.getWidth(), m_tex1.getHeight()); //translate rectangle 500 pixels to the right
	m_shader1.end();

	m_gui.draw();
}
void main()
{
    vec2 coord = gl_FragCoord.xy / u_resolution;
    coord.y = 1.0 - coord.y;
    vec4 color = texture2D(u_tex,coord);
    gl_FragColor = color;
}

…the result is this:

ie. the rectangle’s being translated but not the texture.

I tried adding coord.x += 500 / u_resolution to the shader, but that doesn’t help.

EDIT: OK, I got it working with
coord.x -= 500.0/u_resolution.x;
…which makes sense now that I think about it. Is there a method in oF to automate this offsetting, or do I just always need to update it with a u_translate value?

EDIT2: This is more complicated with resizing. To get the shader to draw properly for an image drawn at half-size I have to do this:

    vec2 coord = gl_FragCoord.xy / u_resolution;
    coord.y = coord.y * 2.0 - 0.5;
    coord.x = coord.x * 2.0;
    coord.y = 1.0 - coord.y;
    vec4 color = texture2D(u_tex,coord);
    gl_FragColor = color;

and this isn’t quite right either, as there’s some distortion at the bottom- probably because I’m not taking aspect ratio into account with my calculations. This seems oddly cumbersome though, am I supposed to be doing something with the vertex shader instead? Right now it only contains this:

void main() {
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

I read through the first page of the shaders tutorial @zach linked me to, but it doesn’t seem to mention this. I thought maybe mapTexCoordsFromTexture() would be relevant, but it seems to be for 3d shapes exclusively,

EDIT 3: OK, looking at the 4th example project, it looks like you have to use ofPlane instead of ofRectangle, which translates the texture/shader together with it.

EDIT 4: For my purposes this time, it seems like it’s easier to just set the position inside the shader and leave the ofRectangle in the same spot, making sure to pass both the resolution of the screen and the resolution of the image into the shader. But I would like to know other ways to do this, eg. when I’m using shaders on something like ofBox2d