1617a3babSopenharmony_ci/* 2617a3babSopenharmony_ciThe MIT License (MIT) 3617a3babSopenharmony_ci 4617a3babSopenharmony_ciCopyright (c) 2022 Sascha Willems 5617a3babSopenharmony_ci 6617a3babSopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining a copy 7617a3babSopenharmony_ciof this software and associated documentation files (the "Software"), to deal 8617a3babSopenharmony_ciin the Software without restriction, including without limitation the rights 9617a3babSopenharmony_cito use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10617a3babSopenharmony_cicopies of the Software, and to permit persons to whom the Software is 11617a3babSopenharmony_cifurnished to do so, subject to the following conditions: 12617a3babSopenharmony_ci 13617a3babSopenharmony_ciThe above copyright notice and this permission notice shall be included in all 14617a3babSopenharmony_cicopies or substantial portions of the Software. 15617a3babSopenharmony_ci 16617a3babSopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17617a3babSopenharmony_ciIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18617a3babSopenharmony_ciFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19617a3babSopenharmony_ciAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20617a3babSopenharmony_ciLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21617a3babSopenharmony_ciOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22617a3babSopenharmony_ciSOFTWARE. 23617a3babSopenharmony_ci*/ 24617a3babSopenharmony_ci 25617a3babSopenharmony_ci#version 450 26617a3babSopenharmony_ci 27617a3babSopenharmony_cilayout(set = 0, binding = 0) uniform UBO 28617a3babSopenharmony_ci{ 29617a3babSopenharmony_ci mat4 projection; 30617a3babSopenharmony_ci mat4 modelview; 31617a3babSopenharmony_ci vec4 lightPos; 32617a3babSopenharmony_ci vec4 frustumPlanes[6]; 33617a3babSopenharmony_ci float displacementFactor; 34617a3babSopenharmony_ci float tessellationFactor; 35617a3babSopenharmony_ci vec2 viewportDim; 36617a3babSopenharmony_ci float tessellatedEdgeSize; 37617a3babSopenharmony_ci} ubo; 38617a3babSopenharmony_ci 39617a3babSopenharmony_cilayout(set = 0, binding = 1) uniform sampler2D samplerHeight; 40617a3babSopenharmony_ci 41617a3babSopenharmony_cilayout (vertices = 4) out; 42617a3babSopenharmony_ci 43617a3babSopenharmony_cilayout (location = 0) in vec3 inNormal[]; 44617a3babSopenharmony_cilayout (location = 1) in vec2 inUV[]; 45617a3babSopenharmony_ci 46617a3babSopenharmony_cilayout (location = 0) out vec3 outNormal[4]; 47617a3babSopenharmony_cilayout (location = 1) out vec2 outUV[4]; 48617a3babSopenharmony_ci 49617a3babSopenharmony_ci// Calculate the tessellation factor based on screen space 50617a3babSopenharmony_ci// dimensions of the edge 51617a3babSopenharmony_cifloat screenSpaceTessFactor(vec4 p0, vec4 p1) 52617a3babSopenharmony_ci{ 53617a3babSopenharmony_ci // Calculate edge mid point 54617a3babSopenharmony_ci vec4 midPoint = 0.5 * (p0 + p1); 55617a3babSopenharmony_ci // Sphere radius as distance between the control points 56617a3babSopenharmony_ci float radius = distance(p0, p1) / 2.0; 57617a3babSopenharmony_ci 58617a3babSopenharmony_ci // View space 59617a3babSopenharmony_ci vec4 v0 = ubo.modelview * midPoint; 60617a3babSopenharmony_ci 61617a3babSopenharmony_ci // Project into clip space 62617a3babSopenharmony_ci vec4 clip0 = (ubo.projection * (v0 - vec4(radius, vec3(0.0)))); 63617a3babSopenharmony_ci vec4 clip1 = (ubo.projection * (v0 + vec4(radius, vec3(0.0)))); 64617a3babSopenharmony_ci 65617a3babSopenharmony_ci // Get normalized device coordinates 66617a3babSopenharmony_ci clip0 /= clip0.w; 67617a3babSopenharmony_ci clip1 /= clip1.w; 68617a3babSopenharmony_ci 69617a3babSopenharmony_ci // Convert to viewport coordinates 70617a3babSopenharmony_ci clip0.xy *= ubo.viewportDim; 71617a3babSopenharmony_ci clip1.xy *= ubo.viewportDim; 72617a3babSopenharmony_ci 73617a3babSopenharmony_ci // Return the tessellation factor based on the screen size 74617a3babSopenharmony_ci // given by the distance of the two edge control points in screen space 75617a3babSopenharmony_ci // and a reference (min.) tessellation size for the edge set by the application 76617a3babSopenharmony_ci return clamp(distance(clip0, clip1) / ubo.tessellatedEdgeSize * ubo.tessellationFactor, 1.0, 64.0); 77617a3babSopenharmony_ci} 78617a3babSopenharmony_ci 79617a3babSopenharmony_ci// Checks the current's patch visibility against the frustum using a sphere check 80617a3babSopenharmony_ci// Sphere radius is given by the patch size 81617a3babSopenharmony_cibool frustumCheck() 82617a3babSopenharmony_ci{ 83617a3babSopenharmony_ci // Fixed radius (increase if patch size is increased in example) 84617a3babSopenharmony_ci const float radius = 8.0f; 85617a3babSopenharmony_ci vec4 pos = gl_in[gl_InvocationID].gl_Position; 86617a3babSopenharmony_ci pos.y -= textureLod(samplerHeight, inUV[0], 0.0).r * ubo.displacementFactor; 87617a3babSopenharmony_ci 88617a3babSopenharmony_ci // Check sphere against frustum planes 89617a3babSopenharmony_ci for (int i = 0; i < 6; i++) { 90617a3babSopenharmony_ci if (dot(pos, ubo.frustumPlanes[i]) + radius < 0.0) 91617a3babSopenharmony_ci { 92617a3babSopenharmony_ci return false; 93617a3babSopenharmony_ci } 94617a3babSopenharmony_ci } 95617a3babSopenharmony_ci return true; 96617a3babSopenharmony_ci} 97617a3babSopenharmony_ci 98617a3babSopenharmony_civoid main() 99617a3babSopenharmony_ci{ 100617a3babSopenharmony_ci if (gl_InvocationID == 0) 101617a3babSopenharmony_ci { 102617a3babSopenharmony_ci if (!frustumCheck()) 103617a3babSopenharmony_ci { 104617a3babSopenharmony_ci gl_TessLevelInner[0] = 0.0; 105617a3babSopenharmony_ci gl_TessLevelInner[1] = 0.0; 106617a3babSopenharmony_ci gl_TessLevelOuter[0] = 0.0; 107617a3babSopenharmony_ci gl_TessLevelOuter[1] = 0.0; 108617a3babSopenharmony_ci gl_TessLevelOuter[2] = 0.0; 109617a3babSopenharmony_ci gl_TessLevelOuter[3] = 0.0; 110617a3babSopenharmony_ci } 111617a3babSopenharmony_ci else 112617a3babSopenharmony_ci { 113617a3babSopenharmony_ci if (ubo.tessellationFactor > 0.0) 114617a3babSopenharmony_ci { 115617a3babSopenharmony_ci gl_TessLevelOuter[0] = screenSpaceTessFactor(gl_in[3].gl_Position, gl_in[0].gl_Position); 116617a3babSopenharmony_ci gl_TessLevelOuter[1] = screenSpaceTessFactor(gl_in[0].gl_Position, gl_in[1].gl_Position); 117617a3babSopenharmony_ci gl_TessLevelOuter[2] = screenSpaceTessFactor(gl_in[1].gl_Position, gl_in[2].gl_Position); 118617a3babSopenharmony_ci gl_TessLevelOuter[3] = screenSpaceTessFactor(gl_in[2].gl_Position, gl_in[3].gl_Position); 119617a3babSopenharmony_ci gl_TessLevelInner[0] = mix(gl_TessLevelOuter[0], gl_TessLevelOuter[3], 0.5); 120617a3babSopenharmony_ci gl_TessLevelInner[1] = mix(gl_TessLevelOuter[2], gl_TessLevelOuter[1], 0.5); 121617a3babSopenharmony_ci } 122617a3babSopenharmony_ci else 123617a3babSopenharmony_ci { 124617a3babSopenharmony_ci // Tessellation factor can be set to zero by example 125617a3babSopenharmony_ci // to demonstrate a simple passthrough 126617a3babSopenharmony_ci gl_TessLevelInner[0] = 1.0; 127617a3babSopenharmony_ci gl_TessLevelInner[1] = 1.0; 128617a3babSopenharmony_ci gl_TessLevelOuter[0] = 1.0; 129617a3babSopenharmony_ci gl_TessLevelOuter[1] = 1.0; 130617a3babSopenharmony_ci gl_TessLevelOuter[2] = 1.0; 131617a3babSopenharmony_ci gl_TessLevelOuter[3] = 1.0; 132617a3babSopenharmony_ci } 133617a3babSopenharmony_ci } 134617a3babSopenharmony_ci 135617a3babSopenharmony_ci } 136617a3babSopenharmony_ci 137617a3babSopenharmony_ci gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; 138617a3babSopenharmony_ci outNormal[gl_InvocationID] = inNormal[gl_InvocationID]; 139617a3babSopenharmony_ci outUV[gl_InvocationID] = inUV[gl_InvocationID]; 140617a3babSopenharmony_ci} 141