1#version 310 es
2#extension GL_EXT_tessellation_shader : require
3
4layout(vertices = 1) out;
5layout(location = 0) in vec2 vPatchPosBase[];
6
7layout(std140) uniform UBO
8{
9    vec4 uScale;
10    highp vec3 uCamPos;
11    vec2 uPatchSize;
12    vec2 uMaxTessLevel;
13    float uDistanceMod;
14    vec4 uFrustum[6];
15};
16
17layout(location = 1) patch out vec2 vOutPatchPosBase;
18layout(location = 2) patch out vec4 vPatchLods;
19
20float lod_factor(vec2 pos_)
21{
22    vec2 pos = pos_ * uScale.xy;
23    vec3 dist_to_cam = uCamPos - vec3(pos.x, 0.0, pos.y);
24    float level = log2((length(dist_to_cam) + 0.0001) * uDistanceMod);
25    return clamp(level, 0.0, uMaxTessLevel.x);
26}
27
28float tess_level(float lod)
29{
30    return uMaxTessLevel.y * exp2(-lod);
31}
32
33vec4 tess_level(vec4 lod)
34{
35    return uMaxTessLevel.y * exp2(-lod);
36}
37
38// Guard band for vertex displacement.
39#define GUARD_BAND 10.0
40bool frustum_cull(vec2 p0)
41{
42    vec2 min_xz = (p0 - GUARD_BAND) * uScale.xy;
43    vec2 max_xz = (p0 + uPatchSize + GUARD_BAND) * uScale.xy;
44
45    vec3 bb_min = vec3(min_xz.x, -GUARD_BAND, min_xz.y);
46    vec3 bb_max = vec3(max_xz.x, +GUARD_BAND, max_xz.y);
47    vec3 center = 0.5 * (bb_min + bb_max);
48    float radius = 0.5 * length(bb_max - bb_min);
49
50    vec3 f0 = vec3(
51        dot(uFrustum[0], vec4(center, 1.0)),
52        dot(uFrustum[1], vec4(center, 1.0)),
53        dot(uFrustum[2], vec4(center, 1.0)));
54
55    vec3 f1 = vec3(
56        dot(uFrustum[3], vec4(center, 1.0)),
57        dot(uFrustum[4], vec4(center, 1.0)),
58        dot(uFrustum[5], vec4(center, 1.0)));
59
60    return !(any(lessThanEqual(f0, vec3(-radius))) || any(lessThanEqual(f1, vec3(-radius))));
61}
62
63void compute_tess_levels(vec2 p0)
64{
65    vOutPatchPosBase = p0;
66
67    float l00 = lod_factor(p0 + vec2(-0.5, -0.5) * uPatchSize);
68    float l10 = lod_factor(p0 + vec2(+0.5, -0.5) * uPatchSize);
69    float l20 = lod_factor(p0 + vec2(+1.5, -0.5) * uPatchSize);
70    float l01 = lod_factor(p0 + vec2(-0.5, +0.5) * uPatchSize);
71    float l11 = lod_factor(p0 + vec2(+0.5, +0.5) * uPatchSize);
72    float l21 = lod_factor(p0 + vec2(+1.5, +0.5) * uPatchSize);
73    float l02 = lod_factor(p0 + vec2(-0.5, +1.5) * uPatchSize);
74    float l12 = lod_factor(p0 + vec2(+0.5, +1.5) * uPatchSize);
75    float l22 = lod_factor(p0 + vec2(+1.5, +1.5) * uPatchSize);
76
77    vec4 lods = vec4(
78        dot(vec4(l01, l11, l02, l12), vec4(0.25)),
79        dot(vec4(l00, l10, l01, l11), vec4(0.25)),
80        dot(vec4(l10, l20, l11, l21), vec4(0.25)),
81        dot(vec4(l11, l21, l12, l22), vec4(0.25)));
82
83    vPatchLods = lods;
84
85    vec4 outer_lods = min(lods.xyzw, lods.yzwx);
86    vec4 levels = tess_level(outer_lods);
87    gl_TessLevelOuter[0] = levels.x;
88    gl_TessLevelOuter[1] = levels.y;
89    gl_TessLevelOuter[2] = levels.z;
90    gl_TessLevelOuter[3] = levels.w;
91
92    float min_lod = min(min(lods.x, lods.y), min(lods.z, lods.w));
93    float inner = tess_level(min(min_lod, l11));
94    gl_TessLevelInner[0] = inner;
95    gl_TessLevelInner[1] = inner;
96}
97
98void main()
99{
100    vec2 p0 = vPatchPosBase[0];
101    if (!frustum_cull(p0))
102    {
103        gl_TessLevelOuter[0] = -1.0;
104        gl_TessLevelOuter[1] = -1.0;
105        gl_TessLevelOuter[2] = -1.0;
106        gl_TessLevelOuter[3] = -1.0;
107        gl_TessLevelInner[0] = -1.0;
108        gl_TessLevelInner[1] = -1.0;
109    }
110    else
111    {
112        compute_tess_levels(p0);
113    }
114}
115
116