0
\$\begingroup\$

I'm working with shaders so far, but I'm not sure how I can make my shader gl_FragCoord relative to the window. To be more clear, this is what I have:

enter image description here

and this is what I'm looking to achieve no matter where I place the fragment on the screen:

enter image description here

As you can see, the shader take the whole window as the refference canvas insted of the fragment. I'm playing with ranges and division based on resolution and fragment size/position, but couldn't figure it out.

The second image was compiled based on hardcoded data, need to find a general solution..

EDIT: This is my vert & frag glsl code:

#version 330 core
layout(location = 0) in vec2 position;

void main() {
    vec2 fp = vec2(position.x, position.y);
    gl_Position = vec4(position.x, position.y, 0.0, 1.0 );
};

$

#version 330 core
layout(location = 0) out vec4 color;

void main() {
    vec2 pos = gl_FragCoord.xy/vec2(800., 600.);

    float r = 0.4 / 2.0;
    float c = smoothstep(r, r - 0.01, distance(pos, vec2(0.5)));

    color = vec4(vec3(c) * vec3(0.0, 0.5,1.0), 1.0);

};
\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

Your resolution is undoubtedly not actually 800 by 600, as the following shadertoy program gives the output you desire, with the only change being the proper resolution is used to divide. You also don't need to pass in coordinates at all, look at this explanation of gl_FragCoord

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 pos = gl_FragCoord.xy/ iResolution.xy;

    float r = 0.4 / 2.0;
    float c = smoothstep(r, r - 0.01, distance(pos, vec2(0.5)));

    fragColor = vec4(vec3(c) * vec3(0.0, 0.5,1.0), 1.0);
}

Test it out here

EDIT:

You appear to be hinting that you are actually using 400 x 300 resolution, if that is the case, my answer is 100% correct, to fix your problem divide by 400 and 300 instead of 800 and 600!

so instead of

vec2 pos = gl_FragCoord.xy/vec2(800., 600.);

do this

vec2 pos = gl_FragCoord.xy/vec2(400., 300.);

Or if your resolution is different do this where resolution_x and resolution_y are the values for your actual resolution...

vec2 pos = gl_FragCoord.xy/vec2([resolution_x]., [resolution_y].);

If you want this to work with all resolutions you will still need to pass the resolution to the shader.

I recommend changing your shader to this and passing a resolution uniform in.

#version 330 core
layout(location = 0) out vec4 color;
uniform vec2 screenResolution

void main() {
    vec2 pos = gl_FragCoord.xy/screenResolution.xy;

    float r = 0.4 / 2.0;
    float c = smoothstep(r, r - 0.01, distance(pos, vec2(0.5)));

    color = vec4(vec3(c) * vec3(0.0, 0.5,1.0), 1.0);

};
\$\endgroup\$
13
  • \$\begingroup\$ Shadertoy takes the whole window as the refference, not a fragment obeject. 800x600 is the window resolution, the object is 400x300, in this case.. \$\endgroup\$
    – alex1997
    Dec 21, 2017 at 16:17
  • \$\begingroup\$ @alex1997 what are you talking about? This is computed per fragment, I'm not sure what you are trying to say. Clearly your resolution is wrong, shader toy uses actual glsl to display. Yes you don't have access to the uniform iResolution, however as long as you actually have the correct resolution your shader will work. clearly what ever you are dividing your frag coords by isn't going to work. \$\endgroup\$
    – Krupip
    Dec 21, 2017 at 16:20
  • \$\begingroup\$ Now I see what you did there, you divided r with 2 which means multiplication of fragmenWidth/windowWidth (this is what I did to get the circle in the fragment), but if I want to render a circle in a rectagle e.q 400x300 at position (30, 200), it won't work at all since the offest should be takken in consideration untill there's something better like gl_TextCoord[].xy.. see here stackoverflow.com/questions/47702694/… \$\endgroup\$
    – alex1997
    Dec 21, 2017 at 16:26
  • \$\begingroup\$ @alex1997 what are you talking about I litterally copied your code and changed only the iResolution part... you ALSO did that exact same thing with the r. It seems like your resolution is 400 x 300, in which case my answer is 100% correct, you didn't actually divide gl_fragCoord.xy by the right numbers (you use 800 by 600) \$\endgroup\$
    – Krupip
    Dec 21, 2017 at 16:30
  • \$\begingroup\$ If I'm applying your code to the first image case ( where the rectangle is positioned at off1xoff2 it won't work, the circle it won't be in the rectangle..this is what I'm really trying to fix and got the idea to get the size of 1px in [0,1] range than multiply it by my offset and add it to the pos value. That should do the trick, but seems that I'm doing something wrong \$\endgroup\$
    – alex1997
    Dec 21, 2017 at 16:36
0
\$\begingroup\$

We use the built-in gl_FragCoord value, which gives us the (x, y) coordinates (in pixels) of the current fragment in the frame buffer. We divide this by the resolution width and height (e.g. 800, 600) to get values between 0.0 and 1.0.

gl_FragCoord.xy / resolution.xy

Note that gl_FragCoord value uses a lower left origin, so (32, 10) would mean 32 pixels to the right, 10 pixels up from the bottom. However, since our circle is symmetrical and located at center, we do not need to worry about this difference in our specific demo.

We subtract (0.5, 0.5) so that we can determine the length from center, rather than lower-left (the origin).

//determine center
vec2 position = (gl_FragCoord.xy / resolution.xy) - vec2(0.5);  

We will use GLSL's built-in length() method to determine the length from the center point. Fragments at the center will have a length of zero (i.e. black), and it will increase as we move outward (i.e. into white/gray). We can test the shader so far:

//our screen resolution, set from Java whenever the display is resized
uniform vec2 resolution;

//"in" attributes from our vertex shader
varying vec4 vColor;

    void main() {

        //determine origin
        vec2 position = (gl_FragCoord.xy / resolution.xy) - vec2(0.5);

        //determine the vector length of the center position and using step function for drawing circle
        float circle = step(length(position),0.5);

        //show our length for debugging
        gl_FragColor = vec4( vec3(length), 1.0 );
    }

https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson3

https://thebookofshaders.com/07/

\$\endgroup\$
2
  • \$\begingroup\$ Yeah, I what you did there, but I don't see the fragment offset takken in consideration. Your code will render an circle in the middle of the screen (The way I'm doing it with distance is better because it won't require substracting vec2(0.5) to modify origin), but if I want to render a circle in a rectagle e.q 400x300 at position (30, 200), it won't work at all.. \$\endgroup\$
    – alex1997
    Dec 21, 2017 at 16:23
  • \$\begingroup\$ This seems to do the trick, but it uses #version 120 stuffs stackoverflow.com/questions/47702694/… \$\endgroup\$
    – alex1997
    Dec 21, 2017 at 16:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .