Vec3 middleOfTriangle = GetMiddlePoint(middlePoint1, middlePoint2, middlePoint3) Vec3 middlePoint3 = GetMiddlePoint(position1, position2) Vec3 middlePoint2 = GetMiddlePoint(position3, position1) Vec3 middlePoint1 = GetMiddlePoint(position2, position3) Vec3 position3 = tessellationControlPosition Vec3 position2 = tessellationControlPosition Vec3 position1 = tessellationControlPosition TessellationEvaluationPosition = tessellationControlPosition TessellationEvaluationTextureCoordinate = tessellationControlTextureCoordinate TessellationEvaluationHeightMapTextureCoordinate = tessellationControlHeightMapTextureCoordinate Pass along the values to the tessellation evaluation shader. Layout (location = 2) out vec3 tessellationEvaluationPosition Layout (location = 1) out vec2 tessellationEvaluationTextureCoordinate Layout (location = 0) out vec2 tessellationEvaluationHeightMapTextureCoordinate Layout (location = 2) in vec3 tessellationControlPosition Layout (location = 1) in vec2 tessellationControlTextureCoordinate Layout (location = 0) in vec2 tessellationControlHeightMapTextureCoordinate My tessellation control shader looks something like this The InvocationID is also a builtin variable, and basically denotes which vertex the shader is on. That is why it’s common practice to wrap these operations in an if (InvocationID = 0) block. Worth noting is that the control shader is run once per vertex, but these values only need to be set once per primitive. The amount of tessellation is done by setting the builtin TessLevelInner and TesseLevelOuter variables. The control shader’s job is determining the amount of tessellation that should be done on each primitive (which can be either triangles, quads or isolines) as well as perform any special transformation you might want. So let’s dive right in and look at the two additional shaders we’ll need – The tessellation control shader and the tessellation evaluation shader. At least as much as I remember! As with previous tutorials, this assumes that you have a basic renderer already up and running and, of course, also basic knowledge of Vulkan. There were a lot of gotchas, so I’ll walk you through the whole thing. For doing this, I needed to implement the tessellation control stage as well as the tessellation evaluation stage. I’ve recently implemented a makeshift terrain renderar, using a runtime-generated plane dynamically tessellated on the GPU using a height map for the overall shape and a displacement map for the small bumps in the terrain. Last time we talked quick about using the same buffer for vertices and indices and today I want to talk a bit about tessellation in Vulkan.