user1767754
user1767754

Reputation: 25154

Tessellation Shader - OpenGL

layout (vertices = 3) out;

void main(void)
{
    if (gl_InvocationID == 0)
    {
        gl_TessLevelInner[0] = 5.0;
        gl_TessLevelOuter[0] = 5.0;
        gl_TessLevelOuter[1] = 5.0;
        gl_TessLevelOuter[2] = 5.0;
    }
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}

Excerpt From: Haemel, Nicholas. “OpenGL SuperBible":

How can I understand TessLevelInner and TessLevelOuter and why is the id 0 listed two times?

Upvotes: 5

Views: 4828

Answers (2)

Christopher Bruns
Christopher Bruns

Reputation: 9518

For triangles, each of the first three "outer" gl_TessLevelOuter[] tessellation values control the subdivision of one of the three sides of the triangle, and the fourth value is unused.

Only the first "inner" gl_TessLevelInner[0] value is used, to determine the subdivision of the the inner triangle. This inner level is more confusing than the outer level, so looking at a picture is better than trying to explain it.

Here is a similar image to the accepted answer, but with the inner value row labels corrected, and a program you can use to experiment with your own values.

The image source link on the accepted answer is currently broken (May 2019). Plus the row labeled "Inner Tesselation Factor" is off by one. The inner tessellation value of the first row is actually zero.

Triangle tessellation matrix

Python program for creating the above image:

import inspect, glfw, numpy
from OpenGL.GL import *
from OpenGL.GL import shaders

glfw.init()
tile_size, tile_count = 80, 8
width = tile_size * tile_count
glfw.window_hint(glfw.SAMPLES, 16)
window = glfw.create_window(width, width, 'tessellation demo', None, None)
glfw.make_context_current(window)
glBindVertexArray(glGenVertexArrays(1))
triangle = numpy.array([
    [-0.9, -0.9, 0.5],  # lower left
    [ 0.9, -0.9, 0.5],  # lower right
    [ 0.0,  0.9, 0.5],  # top
], dtype=numpy.float32)
glBindBuffer(GL_ARRAY_BUFFER, glGenBuffers(1))
glBufferData(GL_ARRAY_BUFFER, triangle, GL_STATIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(index=0, size=3, type=GL_FLOAT, normalized=False, stride=0, pointer=None)
program = shaders.compileProgram(
    shaders.compileShader(source=inspect.cleandoc('''
        #version 460 core
        in vec3 aPos;
        void main() {
            gl_Position = vec4(aPos, 1);
        }
    '''), shaderType=GL_VERTEX_SHADER),
    # Tessellation control shader not defined here because default is OK.
    shaders.compileShader(source=inspect.cleandoc('''
        #version 460 core
        layout(triangles) in;
        void main() {
            gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +
                          (gl_TessCoord.y * gl_in[1].gl_Position) +
                          (gl_TessCoord.z * gl_in[2].gl_Position);
        }
    '''), shaderType=GL_TESS_EVALUATION_SHADER),
    shaders.compileShader(source=inspect.cleandoc('''
        #version 460 core
        out vec4 fragColor;
        void main() {
            fragColor = vec4(vec3(0.1), 1);  // dark gray
        }
    '''), shaderType=GL_FRAGMENT_SHADER),)
glUseProgram(program)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
glPatchParameteri(GL_PATCH_VERTICES, 3)
glClearColor(0.95, 0.95, 0.95, 1)  # pale gray
outer_levels = numpy.array([1, 1, 1, 1], dtype=numpy.float32)
inner_levels = numpy.array([1, 1], dtype=numpy.float32)
while not glfw.window_should_close(window):
    glClear(GL_COLOR_BUFFER_BIT)
    for outer in range(tile_count + 1):  # increase outer tessellation factors left to right
        for inner in range(tile_count + 1):  # inner tesselation factors top to bottom
            glViewport(outer * tile_size, width - inner * tile_size, tile_size, tile_size)
            outer_levels[:] = [outer + 1] * 4  # range 1 to 9; zero means no triangles at all
            inner_levels[:] = [inner] * 2  # range 0 to 8
            glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, outer_levels)
            glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, inner_levels)
            glDrawArrays(GL_PATCHES, 0, 3)
    glfw.swap_buffers(window)
    glfw.poll_events()
glfw.terminate()

Upvotes: 2

ssell
ssell

Reputation: 6597

How can I understand gl_TessLevelInner and gl_TessLevelOuter?

Please see: gl_TessLevelInner, gl_TessLevelOuter, OpenGL Tessellation - Levels

As their names imply, they control the inner and outer tessellation factor levels for the primitive being processed. Below is an image illustrating the results of various inner/outer level settings.

enter image description here Source: http://antongerdelan.net/opengl/tessellation.html


Why is the index 0 used twice?

It is used twice because it is accessing two different objects. The first use of index 0 is with

gl_TessLevelInner[0]

and the second is

gl_TessLevelOuter[0]

Upvotes: 17

Related Questions