Jump to content

Vulkan Tessellation Made Practical

Josh

296 views

Now that I have all the Vulkan knowledge I need, and most work is being done with GLSL shader code, development is moving faster. Before starting voxel ray tracing, another hard problem, I decided to work one some *relatively* easier things for a few days. I want tessellation to be an every day feature in the new engine, so I decided to work out a useful implementation of it.

While there are a ton of examples out there showing how to split a triangle up into smaller triangles, useful discussion and techniques of in-game tessellation is much more rare. I think this is because there are several problems to solve before this technical feature can really be made practical.

Tessellation Level

The first problem is deciding how much to tessellate an object. Tessellation should use a single detail level per set of primitives being drawn. The reason for this is that cracks will appear when you apply displacement if you try to use a different tessellation level for each polygon. I solved this with some per-mesh setting for tessellation parameters.

Note: In Leadwerks Game Engine, a model is an entity with one or more surfaces. Each surface has a vertex array, indice array, and a material. In Turbo Game Engine, a model contains one of more LODs, and each LOD can have one or more meshes. A mesh object in Turbo is like a surface object in Leadwerks.

We are not used to per-mesh settings. In fact, the material is the only parameter meshes contained other than vertex or indice data. But for tessellation parameters, that is exactly what we need, because the density of the mesh polygons gives us an idea of how detailed the tessellation should be. This command has been added:

void Mesh::SetTessellation(const float detail, const float nearrange, const float farrange)

Here are what the parameters do:

  • detail: the higher the detail, the more the polygons are split up. Default is 16.
  • nearrange: the distance below which tessellation stops increasing. Default is 1.0 meters.
  • farrange: the distance below which tessellation starts increasing. Default is 20.0 meters.

This command gives you the ability to set properties that will give a roughly equal distribution of polygons in screen space. For convenience, a similar command has been added to the model class, which will apply the settings to all meshes in the model.

Surface Displacement

Another problem is culling offscreen polygons so the GPU doesn't have to process millions of extra vertices. I solved this by testing if all control vertices lie outside one edge of the camera frustum. (This is not the same as testing if any control point is inside the camera frustum, as I have seen suggested elsewhere. The latter will cause problems because it is still possible for a triangle to be visible even if all its corners are outside the view.) To account for displacement, I also tested the same vertices with maximum displacement applied.

To control the amount of displacement, a scale property has been added to the displacementTexture object scheme:

"displacementTexture":
{
	"file": "./harshbricks-height5-16.png",
	"scale": 0.05
}

A Boolean value called "tessellation" has also been added to the JSON material scheme. This will tell the engine to choose a shader that uses tessellation, so you don't need to explicitly specify a shader file. Shadows will also be rendered with tessellation, unless you explicitly choose a different shadow shader.

Here is the result:

Untitled.thumb.jpg.714082f068b59819963fc17a667e1e68.jpg

Surface displacement takes the object scale into account, so if you scale up an object the displacement will increase accordingly.

Surface Curvature

I also added an implementation of the PN Triangles technique. This treats a triangle as control points for a Bezier curve and projects tessellated curved surfaces outwards.

 untitled.png.72b7911750dcb46f0f0865e24670ac4b.png

You can see below the shot using the PN Triangles technique eliminates the pointy edges of the sphere.

linear.png.b309047887252e90c336f5173e5c4713.png

PN.png.6e99cbb858c0fdf739e70a239a43fb17.png

The effects is good, although it is more computationally expensive, and if a strong displacement map is in use, you can't really see a difference. Since vertex positions are being changed but texture coordinates are still using the same interpolation function, it can make texture coordinates appear distorted. To counter this, texture coordinates would need to be recalculated from the new vertex positions.

EDIT:

I found a better algorithm that doesn't produce the texcoord errors seen above.

linear.png.1257ea57f7b195fe536ed8e940a47c88.png

pntris.png.47288a5edd8b65546d996eb003135ee7.png

Finally, a global tessellation factor has been added that lets you scale the effect for different hardware levels:

void SetTessellationDetail(const float detail)

The default setting is 1.0, so you can use this to scale up or down the detail any way you like.

  • Like 2


5 Comments


Recommended Comments

Tessellation should really help to add detail to our games! It seems like I don't see a lot of tessellation in games that I play these days. I wonder why that is because if I recall the tech has been around for 3-5 years already?

Share this comment


Link to comment

I wonder how many games just silently include it.  It's not necessarily something you need to see in an options menu.  And I don't think you should visually notice it in-game, if it's done right.

Share this comment


Link to comment

Depends on game I guess.I think for complex models the 3 lod models are widespread.So graphics section takes care of this.Maybe performance needs? Anyway I think this is good feature for turbo.

Share this comment


Link to comment

@Rick Maybe because models have to be created without UV seams or cracks in displacement will appear. I am adding a displacement vertex value so that displacement can be pulled in along UV seams.

I see tessellation being a common thing in two areas: terrain and brushes. With brush geometry I can add some extra vertices so that displacement gets tucked in along the edges and you never have to worry about it. It's common for PBR materials to include a displacement map so I think tessellation will be much more common in Turbo.

Perhaps a script tool can also be created that detects UV seams and sets those vertices' displacement to zero.

  • Like 2

Share this comment


Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...