livin_amuk
livin_amuk

Reputation: 1353

Smoother gradient transitions with OpenGL?

I'm using the following shader to render a skydome to simulate a night sky. My issue is the clearly visible transitions between colours.

What causes these harsh gradient transitions?

enter image description here

Fragment shader:

#version 330
in vec3 worldPosition;
layout(location = 0) out vec4 outputColor;

void main()
{
    float height = 0.007*(abs(worldPosition.y)-200);    
    vec4 apexColor = vec4(0,0,0,1);
    vec4 centerColor = vec4(0.159, 0.132, 0.1, 1);

    outputColor = mix(centerColor, apexColor, height);
}

Fbo pixel format:

GL.TexImage2D(
    TextureTarget.Texture2D,
    0,
    PixelInternalFormat.Rgb32f,
    WindowWidth,
    WindowHeight,
    0,
    PixelFormat.Rgb,
    PixelType.Float,
    IntPtr.Zero )

Upvotes: 6

Views: 1899

Answers (2)

livin_amuk
livin_amuk

Reputation: 1353

As Ripi2 explained, 24 bit color is unable to perfectly represent a gradient and discontinuities between representable colours become jarringly visible on gradients of a single color.

To hide the color banding I implemented a simple form of ordered dithering with an 8x8 texture generated using this bayer matrix algorithm.

enter image description here

vec4 dither = vec4(texture2D(MyTexture0, gl_FragCoord.xy / 8.0).r / 32.0 - (1.0 / 128.0));
colourOut += dither;

enter image description here

Upvotes: 8

Ripi2
Ripi2

Reputation: 7198

Normally monitors have 8 bits per channel of resolution. For example, the red intensity varies from 0 to 255.

If your window horizontal size is 768 pixels and you want a full gradient on red channel, then each color step takes 768/256 = 3 pixels. Depending on your eye health you may see bands.

How to do smooth gradient on those 3 pixels? Use sub-pixel rendering.
Basically you "expand" the color step among the neighbour pixels: Add small amounts of other channels to neighbours, and reduce a bit the central pixel amount.

Upvotes: 2

Related Questions