4
votes

I drawing a set of quads. For each quad I have a defined color in a vertex of it.

E.g. now my set of quads looks like:

enter image description here

I achive such result in rather primitive way just passing into vertex shader as attribute color of each vertex of an quad.

My shaders are pretty simple:

Vertex shader

#version 150 core

in vec3 in_Position;
in vec3 in_Color;
out vec3 pass_Color;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;

void main(void) {
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);

    pass_Color = in_Color;
}

Fragment Shader

#version 150 core
in vec3 pass_Color;
out vec4 out_Color;

void main(void) {
    out_Color = vec4(pass_Color, 1.0);
}

Now my goal is to get color non continuous distribution of colors from vertex to vertex. It also can be called "level distribution".

My set of quads should looks like this:

enter image description here

How can I achieve such result?

EDIT:

With vesan and Nico Schertler plate looks like this. (not acceptable variant)

enter image description here

2
Quantize the output color in the fragment shader e.g. with floor(color * steps)/steps.Nico Schertler
@Nico Schertler: could u provide full answer with code snippet, please?frankie
I'm not sure if floor is able to handle vectors. If not, calculate each channel separately. color will become pass_color. steps is a constant.Nico Schertler
@Nico Schertler: still not clear for me :(frankie

2 Answers

3
votes

My guess is there will be issues with the hue colours you're using and vertex interpolation (e.g. skipping some bands). Instead, maybe pass in a single channel value and calculate the hue and discrete levels (as @vesan does) within the fragment shader. I use these functions myself...

vec3 hueToRGB(float h)
{
    h = fract(h) * 6.0;
    vec3 rgb;
    rgb.r = clamp(abs(3.0 - h)-1.0, 0.0, 1.0);
    rgb.g = clamp(2.0 - abs(2.0 - h), 0.0, 1.0);
    rgb.b = clamp(2.0 - abs(4.0 - h), 0.0, 1.0);
    return rgb;
}

vec3 heat(float x)
{
    return hueToRGB(2.0/3.0-(2.0/3.0)*clamp(x,0.0,1.0));
}

and then

float discrete = floor(pass_Value * steps + 0.5) / steps; //0.5 to round
out_Color = vec4(heat(discrete), 1.0);

where in float in_Value is 0 to 1.

3
votes

Just expanding on Nico Schertler's comment: you can modify your fragment shader to:

void main(void) {
    out_Color = vec4(pass_Color, 1.0);
    out_Color = floor(color * steps)/steps;
}

where steps in the number of color steps you want. The floor function will indeed work on a vector, however, the steps will be calculated separately for every color, so the result might not be exactly what you want (the steps might not be as nice as in your example).

Alternatively, you can use some form of "toon shading" (see for example here). That means that you only pass a single number (think a color in grayscale) to your shader, then use your shader to select a color from a color table. The table can either be hardcoded in the shader or selected from a 1-dimensional texture.