iam_peter
iam_peter

Reputation: 3924

GLSL interpolate color tessellation shader

my tessellation shader generates a bezier curve for two vertices. the vertices consists of two coordinates x and y (vec2). now every vertex has a color. my question: how to interpolate the color per vertex on the generated curve? right now the fragment shader sets a default color value (red). but i want him to get the interpolated color.

for example:

vertex 1 [vec2(0.0, 0.0), vec4(1.0, 0.0, 0.0, 1.0)] // red
vertex 2 [vec2(1.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0)] // blue

so there should be a gradient from red to blue. how can i do this with the tessellation shader?

vertex shader:

#version 400

layout (location = 0 ) in vec2 in_position;
layout (location = 1 ) in vec4 in_color;

void main()
{
    gl_Position = vec4(in_position, 0.0, 1.0);
}

tessellation control shader:

#version 400

layout( vertices = 2 ) out;

uniform int NumSegments;
uniform int NumStrips;

void main()
{
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;

    gl_TessLevelOuter[0] = float(NumSegments);
    gl_TessLevelOuter[1] = float(NumStrips);
}

tessellation evaluation shader:

#version 400

layout( isolines ) in;

uniform mat4 Projection;
uniform mat4 Modelview;

void main()
{
    float u = gl_TessCoord.x;

    vec3 p0 = gl_in[0].gl_Position.xyz;
    vec3 p1 = vec3(0.5, gl_in[0].gl_Position.y, 0.0);
    vec3 p2 = vec3(0.5, gl_in[1].gl_Position.y, 0.0);
    vec3 p3 = gl_in[1].gl_Position.xyz;

    float u1 = (1.0 - u);
    float u2 = u * u;

    // Bernstein polynomials
    float b3 = u2 * u;
    float b2 = 3.0 * u2 * u1;
    float b1 = 3.0 * u * u1 * u1;
    float b0 = u1 * u1 * u1;

    // Cubic Bezier interpolation
    vec3 p = p0 * b0 + p1 * b1 + p2 * b2 + p3 * b3;

    gl_Position = Projection * Modelview * vec4(p, 1.0);
}

fragment shader:

#version 400

layout ( location = 0 ) out vec4 FragColor;

void main()
{
  FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Upvotes: 0

Views: 2364

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473946

This is all pretty straightforward. Just follow the pattern of your already existing inputs and outputs.

Your vertex shader outputs a gl_Position value. Therefore, it should also output a color value:

layout (location = 0 ) in vec2 in_position;
layout (location = 1 ) in vec4 in_color;

out vec4 color;

void main()
{
    gl_Position = vec4(in_position, 0.0, 1.0);
    color = in_color;
}

Your tessellation control shader takes an array of gl_Positions. So you take an array of colors. It also needs to write to an array of colors:

layout( vertices = 2 ) out;

uniform int NumSegments;
uniform int NumStrips;

in vec4 color[];

out Tess
{
  vec4 color;
} Out[];

void main()
{
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
    Out[gl_InvocationID].color = color[gl_InvocationID];

    gl_TessLevelOuter[0] = float(NumSegments);
    gl_TessLevelOuter[1] = float(NumStrips);
}

In your evaluation shader, you again need to take an array of input and output layout qualifiers. We used an output interface block called Tess, so we need to match it with an input interface block of the same name:

layout( isolines ) in;

uniform mat4 Projection;
uniform mat4 Modelview;

in Tess
{
  vec4 color;
} In[];

out vec4 color;

void main()
{
    float u = gl_TessCoord.x;

    /** Do whatever interpolation stuff you do **/

    // Cubic Bezier interpolation
    vec3 p = p0 * b0 + p1 * b1 + p2 * b2 + p3 * b3;

    gl_Position = Projection * Modelview * vec4(p, 1.0);
    color = Interpolate(In[0].color, In[1].color, ...); //More interpolation stuff.
}

And that's that. Your fragment shader takes as an input a vec4 color.

Also, a small note: this is not a Bezier spline. Bezier splines require patches of 4 positions, not 2. The way you synthesized the other two values doesn't make them correct.

Upvotes: 1

Related Questions