gl_FragCoord is larger than the window size

Hello,

I wrote a simple GLSL vertex and fragment shader as follows:

#version 150

uniform mat4 ciModelViewProjection;
in vec4 ciPosition;

void main()
{
    gl_Position = ciModelViewProjection * ciPosition;
}

#version 150

uniform vec2 uResolution;
out vec4 oFragColor;

void main()
{
    oFragColor = vec4(vec3(gl_FragCoord.x < uResolution.x ? 0 : 1), 1.0);
}

and draw() and resize() as follows:

void ExampleApp::draw()
{
	ci::gl::clear(ci::Color(0, 0, 0));
	ci::gl::ScopedGlslProg scopedGlslProg(mGlslProg);
	{
		ci::gl::drawSolidRect(ci::Rectf(ci::vec2(0, 0), ci::vec2(getWindowSize())));
	}
}

void ExampleApp::resize()
{
	if (mGlslProg)
	{
		mGlslProg->uniform("uResolution", ci::vec2(getWindowSize()));
	}
}

So, I think the result would be a white rectangle, but I got:

Does anyone know why the gl_FragCoord is larger than the window size?

I would expect that to be all black as opposed to all white since gl_FragCoord.x would always be < uResolution.x (give or take 0.5 for pixel centres), but either way what you’re seeing is weird.

The code as you’ve pasted it works for me, are you certain the black (or white) you’re seeing is coming from that draw call? A few things:

  1. Can you change your clear colour to make sure?
  2. Do you have any errant transforms that might be shifting where the rectangle is drawn?
  3. Try resetting the matrices with gl::setMatricesWindow ( getWindowSize() ) before your rect draw.

The other unfortunate thing is that mac’s OpenGL driver is old and shit (a few years ago it was just shit) so it’s possible they aren’t respecting the spec’s idea of gl_FragCoord. As a general rule I avoid as many intrinsics as possible to remove these kinds of problems, I make enough mistakes on my own, I don’t need the driver’s help at all with that.

I would also suggest getting comfortable working in UV space where possible since it removes the requirement to know about the window size at all. In your example, your shaders would become:

uniform mat4 ciModelViewProjection;
in vec4 ciPosition;
in vec2 ciTexCoord0;

out vec2 UV;

void main()
{
    gl_Position = ciModelViewProjection * ciPosition;
    UV = ciTexCoord0;
}
in vec2 UV;
out vec4 oFragColor;
 
void main()
{
    oFragColor = vec4(vec3(UV.x < 1.0 ? 0 : 1), 1.0);
}

And you could remove all the resize code and passing any uniforms to the shader since everything is now in the 0..1 range, regardless of window size.

That’s probably it.

-Paul

@lithium @paul.houx Thank you everyone!

First, I changed the clear color like ci::gl::clear(ci::Color(1, 0, 0)), but nothing has changed. So, I’m sure that the window is completely covered with the rectangle.

Next, I called ci::gl::setMatricesWindow(getWindowSize()), but nothing has changed. This is natural because any geometrical transformation has not been applied.

Using ciTexCoord0 instead of gl_FragCoord works well.
However, gl_FragCoord is generally different from ciTexCoord0, so I think this is not a fundamental solution.

I’m using high density display. Is this related to this issue?

Aaaand there it goes. :wink:

In cinder when you’re in high density mode you need to convert your units from points to pixels. Basically any time you use any of the getWindow* functions you’ll want to wrap it in app::toPixels() to multiply it by the window’s content scale.

e.g

mGlslProg->uniform ( "uResolution", ci::vec2 ( app::toPixels ( getWindowSize() ) ) );
2 Likes

ci::app::toPixels works well.
Got it! Thank you!

fyi I think there is a default ciWindowSize uniform that Cinder provides.

2 Likes