1
TESSELLATION 1 OUTLINE Tessellation in OpenGL Tessellation of - - PowerPoint PPT Presentation
TESSELLATION 1 OUTLINE Tessellation in OpenGL Tessellation of - - PowerPoint PPT Presentation
TESSELLATION 1 OUTLINE Tessellation in OpenGL Tessellation of Bezier Surfaces Tessellation for Terrain/Height Maps Level of Detail 2 THE EXAMPLE TESSELLATION SHADING Instead of specifying vertices, you specify a
OUTLINE
2
- Tessellation in OpenGL
- Tessellation of Bezier Surfaces
- Tessellation for Terrain/Height Maps
- Level of Detail
THE EXAMPLE
TESSELLATION SHADING
- Instead of specifying vertices, you specify a “patch”
- Just an ordered set of vertices
- Tessellation control shader determines how much geometry is generated from patch
- Other primitives are processed by vertex, fragment and geometry shaders and
bypass tessellation
- You specify the total number of vertices in the patch (with primitives, OpenGL already
knows how many vertices to expect) glPatchParameteri(GLenum pname, Glint value);
- pname is set to GL_PATCH_VERTICES
- value is number of vertices
glPatchParameteri(GL_PATCH_VERTICES, 4); glDrawArrays(GL_PATCHES, 0, 8);
VERTEX SHADER
#version 430 uniform mat4 mvp; void main(void) { }
TESSELLATION CONTROL SHADER
#version 430 uniform mat4 mvp; layout (vertices = 1) out; void main(void) { gl_TessLevelOuter[0] = 6; gl_TessLevelOuter[2] = 6; gl_TessLevelOuter[1] = 6; gl_TessLevelOuter[3] = 6; gl_TessLevelInner[0] = 12; gl_TessLevelInner[1] = 12; }
Specifies the number of output-patch vertices and specifies how many times the TCS will execute – once for each
- utput vertex.
TESSELLATION LEVELS
QUAD TESSELLATION
TRIANGLE TESSELLATION
TESSELLATION EVALUATION SHADER
- Executed once for each tessellation coordinate that the tessellator generates
- Determines the position of the vertex derived from the coordinate
- Looks similar to vertex shader
- Transforming vertices into screen positions
- (Unless we will use a geometry shader – but that’s at least one
lecture away)
TESSELLATION EVALUATION SHADER
#version 430 layout (quads, equal_spacing, ccw) in; uniform mat4 mvp; void main (void) { float u = gl_TessCoord.x; float v = gl_TessCoord.y; gl_Position = mvp * vec4(u,0,v,1); }
Primitive type can be quads, triangles or isolines cw or ccw for winding order equal_spacing, fractional_even_spacing or fractional_odd_spacing
SPACING
- equal_spacing is the default
- It subdivides the perimeter into the number of segments you specified
- Looks best here, but has the disadvantage that it rounds up to the nearest integer so
if your object changes size you can get visible differences
- fractional_even…and fractional_odd round down – but you are left with a fractional
triangle somewhere
FRAGMENT SHADER
#version 430
- ut vec4 color;
uniform mat4 mvp; void main(void) { color = vec4(1.0, 1.0, 0.0, 1.0); }
TESSELLATION FOR BEZIER SURFACES
VERTEX SHADER
#version 430
- ut vec2 tc;
uniform mat4 mvp; layout (binding = 0) uniform sampler2D tex_color; void main(void) { const vec4 vertices[] = vec4[] (vec4(-1.0, 0.5, -1.0, 1.0), vec4(-0.5, 0.5, -1.0, 1.0), vec4( 0.5, 0.5, -1.0, 1.0), vec4( 1.0, 0.5, -1.0, 1.0), vec4(-1.0, 0.0, -0.5, 1.0), vec4(-0.5, 0.0, -0.5, 1.0), vec4( 0.5, 0.0, -0.5, 1.0), vec4( 1.0, 0.0, -0.5, 1.0), vec4(-1.0, 0.0, 0.5, 1.0), vec4(-0.5, 0.0, 0.5, 1.0), vec4( 0.5, 0.0, 0.5, 1.0), vec4( 1.0, 0.0, 0.5, 1.0), vec4(-1.0,-0.5, 1.0, 1.0), vec4(-0.5, 0.3, 1.0, 1.0), vec4( 0.5, 0.3, 1.0, 1.0), vec4( 1.0, 0.3, 1.0, 1.0)); tc = vec2((vertices[gl_VertexID].x + 1.0)/2.0, (vertices[gl_VertexID].z + 1.0)/2.0); gl_Position = vertices[gl_VertexID]; }
TESSELLATION CONTROL SHADER
#version 430 in vec2 tc[];
- ut vec2 tcs_out[];
uniform mat4 mvp; layout (binding=0) uniform sampler2D tex_color; layout (vertices = 16) out; void main(void) { int TL = 32; // tessellation levels if (gl_InvocationID ==0) { gl_TessLevelOuter[0] = TL; gl_TessLevelOuter[2] = TL; gl_TessLevelOuter[1] = TL; gl_TessLevelOuter[3] = TL; gl_TessLevelInner[0] = TL; gl_TessLevelInner[1] = TL; } tcs_out[gl_InvocationID] = tc[gl_InvocationID]; gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; }
16 control points per patch
TESSELLATION EVALUATION SHADER
#version 430 layout (quads, equal_spacing,ccw) in; uniform mat4 mvp; layout (binding = 0) uniform sampler2D tex_color; in vec2 tcs_out[];
- ut vec2 tes_out;
…
TESSELLATION EVALUATION SHADER
void main (void) { vec3 p00 = (gl_in[0].gl_Position).xyz; vec3 p10 = (gl_in[1].gl_Position).xyz; vec3 p20 = (gl_in[2].gl_Position).xyz; vec3 p30 = (gl_in[3].gl_Position).xyz; vec3 p01 = (gl_in[4].gl_Position).xyz; vec3 p11 = (gl_in[5].gl_Position).xyz; vec3 p21 = (gl_in[6].gl_Position).xyz; vec3 p31 = (gl_in[7].gl_Position).xyz; vec3 p02 = (gl_in[8].gl_Position).xyz; vec3 p12 = (gl_in[9].gl_Position).xyz; vec3 p22 = (gl_in[10].gl_Position).xyz; vec3 p32 = (gl_in[11].gl_Position).xyz; vec3 p03 = (gl_in[12].gl_Position).xyz; vec3 p13 = (gl_in[13].gl_Position).xyz; vec3 p23 = (gl_in[14].gl_Position).xyz; vec3 p33 = (gl_in[15].gl_Position).xyz;
…
TESSELLATION EVALUATION SHADER
float u = gl_TessCoord.x; float v = gl_TessCoord.y; // cubic Bezier basis functions float bu0 = (1.0-u) * (1.0-u) * (1.0-u); //(1-u)^3 float bu1 = 3.0 * u * (1.0-u) * (1.0-u); //3u(1-u)^2 float bu2 = 3. * u * u * (1.0-u); //3u^2(1-u) float bu3 = u * u * u; //u^3 float bv0 = (1.0-v) * (1.0-v) * (1.0-v); //(1-v)^3 float bv1 = 3.0 * v * (1.0-v) * (1.0-v); //3v(1-v)^2 float bv2 = 3. * v * v * (1.0-v); //3v^2(1-v) float bv3 = v * v * v; //v^3
TESSELLATION EVALUATION SHADER
// output the position of this vertex in the tessellated patch vec3 outputPosition = bu0 * ( bv0*p00 + bv1*p01 + bv2*p02 + bv3*p03 ) + bu1 * ( bv0*p10 + bv1*p11 + bv2*p12 + bv3*p13 ) + bu2 * ( bv0*p20 + bv1*p21 + bv2*p22 + bv3*p23 ) + bu3 * ( bv0*p30 + bv1*p31 + bv2*p32 + bv3*p33 ); gl_Position = mvp * vec4(outputPosition,1.0f); // shows bezier curve // gl_Position = mvp * vec4(u,0,v,1); // shows original grid (pick one) // output the interpolated texture coordinates vec2 tc1 = mix(tcs_out[0], tcs_out[3], gl_TessCoord.x); vec2 tc2 = mix(tcs_out[12], tcs_out[15], gl_TessCoord.x); vec2 tc = mix(tc2, tc1, gl_TessCoord.y); tes_out = tc; }
FRAGMENT SHADER
#version 430 in vec2 tes_out;
- ut vec4 color;
uniform mat4 mvp; layout (binding=0) uniform sampler2D tex_color; void main(void) { color = texture(tex_color, tes_out); }
TESSELLATION FOR TERRAIN / HEIGHT MAPS
- Height mapping from the vertex shader can lose detail
- Tesselation shaders introduce additional vertices
- Can use this to flesh out the detail
- Matches object geometry better
- Improves silhouette / edge detail
- Strategy:
- Place a tesselated grid in the x-z plane
- Use height map to set y coordinates
- Doesn’t require any patches
- Use grey scale image for both texture and height map
- Initial result?
TESSELLATION FOR TERRAIN / HEIGHT MAPS
- White areas should be higher and black areas lower
- Does not correspond on the result
- Even by adding vertices with tessellation, the resolution is too low to capture details
TESSELLATION FOR TERRAIN / HEIGHT MAPS
- The solution:
- Use instancing
- Remember instancing from way early on?
- Rendering multiple Java objects with a single Java call
- Build a patch in the vertex shader
- Instance the picture with 64x64 patches - results in over 4 million vertices
VERTEX SHADER
#version 430
- ut vec2 tc;
uniform mat4 mvp; layout (binding = 0) uniform sampler2D tex_color; void main(void) { vec2 patchTexCoords[] = vec2[] (vec2(0,0), vec2(1,0), vec2(0,1), vec2(1,1)); // compute an offset for coordinates based on which instance this is int x = gl_InstanceID % 64; int y = gl_InstanceID / 64; // texture coordinates are distributed across 64 patches tc = vec2( (x+patchTexCoords[gl_VertexID].x)/64.0, (y+patchTexCoords[gl_VertexID].y)/64.0 ); // vertex locations range from -0.5 to +0.5 gl_Position = vec4(tc.x-0.5, 0.0, (1.0-tc.y)-0.5, 1.0); }
TESSELLATION CONTROL SHADER
#version 430 layout (vertices = 4) out; in vec2 tc[];
- ut vec2 tcs_out[];
uniform mat4 mvp; layout (binding=0) uniform sampler2D tex_color; void main(void) { int TL = 32; if (gl_InvocationID == 0) { gl_TessLevelOuter[0] = TL; gl_TessLevelOuter[2] = TL; gl_TessLevelOuter[1] = TL; gl_TessLevelOuter[3] = TL; gl_TessLevelInner[0] = TL; gl_TessLevelInner[1] = TL; } tcs_out[gl_InvocationID] = tc[gl_InvocationID]; gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; }
TESSELLATION EVALUATION SHADER
#version 430 layout (quads, equal_spacing,ccw) in; uniform mat4 mvp; layout (binding = 0) uniform sampler2D tex_color; in vec2 tcs_out[];
- ut vec2 tes_out;
void main (void) { // map the texture coordinates onto the sub-grid specified by the incoming control points vec2 tc = vec2(tcs_out[0].x+(gl_TessCoord.x)/64.0, tcs_out[0].y+(1.0-gl_TessCoord.y)/64.0); // map the tessellated grid onto the sub-grid specified by the incoming control points vec4 tessellatedPoint = vec4(gl_in[0].gl_Position.x + gl_TessCoord.x / 64.0, 0.0, gl_in[0].gl_Position.z + gl_TessCoord.y / 64.0, 1.0); // add the height from the height map to the vertex: tessellatedPoint.y += (texture(tex_color, tc).r) / 40.0; gl_Position = mvp * tessellatedPoint; tes_out = tc; }
FRAGMENT SHADER
#version 430 in vec2 tes_out;
- ut vec4 color;
uniform mat4 mvp; layout (binding=0) uniform sampler2D tex_color; void main(void) { color = texture(tex_color, tes_out); }
And the result? …
OVERLY JAGGED
ANOTHER ATTEMPT
- Height mapping detail is somewhat correct, but areas not quite right
- One problem is using a greyscale texture image for height doesn’t quite work
- Not all variations in greyscale images are due to height- some are just color
- Another problem – we don’t have normals so we can do the lighting
- Solution – use a true height map and a normal map
- Bonus – the image now responds to lighting
HEIGHT MAP AND NORMAL MAP
WITH NORMAL MAP AND LIGHTING
SO …WHAT’S THE DRAWBACK?
- Imagery is great, but we have over 4 million vertices just to draw the moon surface
- Any additional graphic objects are going to start taxing the system
- Solution – Only use high resolution in the areas that matter
- Those that are closer to the viewer
- Level of Detail:
- Changing the number of vertices based on the distance from the camera
- One catch… changing detail level, as the object/camera moves can make parts
- f the image “pop” or wiggle
- The fix? Use fractional_even_spacing instead of equal_spacing
LEVEL OF DETAIL
SUMMARY
35
- Tessellation in OpenGL
- Tessellation of Bezier Surfaces
- Tessellation for Terrain/Height Maps
- Level of Detail