1617a3babSopenharmony_ci/* 2617a3babSopenharmony_ciThe MIT License (MIT) 3617a3babSopenharmony_ci 4617a3babSopenharmony_ciCopyright (c) 2022 Google LLC 5617a3babSopenharmony_ciCopyright (c) 2022 Sascha Willems 6617a3babSopenharmony_ci 7617a3babSopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining a copy 8617a3babSopenharmony_ciof this software and associated documentation files (the "Software"), to deal 9617a3babSopenharmony_ciin the Software without restriction, including without limitation the rights 10617a3babSopenharmony_cito use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11617a3babSopenharmony_cicopies of the Software, and to permit persons to whom the Software is 12617a3babSopenharmony_cifurnished to do so, subject to the following conditions: 13617a3babSopenharmony_ci 14617a3babSopenharmony_ciThe above copyright notice and this permission notice shall be included in all 15617a3babSopenharmony_cicopies or substantial portions of the Software. 16617a3babSopenharmony_ci 17617a3babSopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18617a3babSopenharmony_ciIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19617a3babSopenharmony_ciFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20617a3babSopenharmony_ciAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21617a3babSopenharmony_ciLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22617a3babSopenharmony_ciOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23617a3babSopenharmony_ciSOFTWARE. 24617a3babSopenharmony_ci*/ 25617a3babSopenharmony_ci 26617a3babSopenharmony_cistruct UBO 27617a3babSopenharmony_ci{ 28617a3babSopenharmony_ci float4x4 projection; 29617a3babSopenharmony_ci float4x4 modelview; 30617a3babSopenharmony_ci float4 lightPos; 31617a3babSopenharmony_ci float4 frustumPlanes[6]; 32617a3babSopenharmony_ci float displacementFactor; 33617a3babSopenharmony_ci float tessellationFactor; 34617a3babSopenharmony_ci float2 viewportDim; 35617a3babSopenharmony_ci float tessellatedEdgeSize; 36617a3babSopenharmony_ci}; 37617a3babSopenharmony_cicbuffer ubo : register(b0) { UBO ubo; }; 38617a3babSopenharmony_ci 39617a3babSopenharmony_ciTexture2D textureHeight : register(t1); 40617a3babSopenharmony_ciSamplerState samplerHeight : register(s1); 41617a3babSopenharmony_ci 42617a3babSopenharmony_cistruct VSOutput 43617a3babSopenharmony_ci{ 44617a3babSopenharmony_ci float4 Pos : SV_POSITION; 45617a3babSopenharmony_ci[[vk::location(0)]] float3 Normal : NORMAL0; 46617a3babSopenharmony_ci[[vk::location(1)]] float2 UV : TEXCOORD0; 47617a3babSopenharmony_ci}; 48617a3babSopenharmony_ci 49617a3babSopenharmony_cistruct HSOutput 50617a3babSopenharmony_ci{ 51617a3babSopenharmony_ci[[vk::location(2)]] float4 Pos : SV_POSITION; 52617a3babSopenharmony_ci[[vk::location(0)]] float3 Normal : NORMAL0; 53617a3babSopenharmony_ci[[vk::location(1)]] float2 UV : TEXCOORD0; 54617a3babSopenharmony_ci}; 55617a3babSopenharmony_ci 56617a3babSopenharmony_cistruct ConstantsHSOutput 57617a3babSopenharmony_ci{ 58617a3babSopenharmony_ci float TessLevelOuter[4] : SV_TessFactor; 59617a3babSopenharmony_ci float TessLevelInner[2] : SV_InsideTessFactor; 60617a3babSopenharmony_ci}; 61617a3babSopenharmony_ci 62617a3babSopenharmony_ci// Calculate the tessellation factor based on screen space 63617a3babSopenharmony_ci// dimensions of the edge 64617a3babSopenharmony_cifloat screenSpaceTessFactor(float4 p0, float4 p1) 65617a3babSopenharmony_ci{ 66617a3babSopenharmony_ci // Calculate edge mid point 67617a3babSopenharmony_ci float4 midPoint = 0.5 * (p0 + p1); 68617a3babSopenharmony_ci // Sphere radius as distance between the control points 69617a3babSopenharmony_ci float radius = distance(p0, p1) / 2.0; 70617a3babSopenharmony_ci 71617a3babSopenharmony_ci // View space 72617a3babSopenharmony_ci float4 v0 = mul(ubo.modelview, midPoint); 73617a3babSopenharmony_ci 74617a3babSopenharmony_ci // Project into clip space 75617a3babSopenharmony_ci float4 clip0 = mul(ubo.projection, (v0 - float4(radius, float3(0.0, 0.0, 0.0)))); 76617a3babSopenharmony_ci float4 clip1 = mul(ubo.projection, (v0 + float4(radius, float3(0.0, 0.0, 0.0)))); 77617a3babSopenharmony_ci 78617a3babSopenharmony_ci // Get normalized device coordinates 79617a3babSopenharmony_ci clip0 /= clip0.w; 80617a3babSopenharmony_ci clip1 /= clip1.w; 81617a3babSopenharmony_ci 82617a3babSopenharmony_ci // Convert to viewport coordinates 83617a3babSopenharmony_ci clip0.xy *= ubo.viewportDim; 84617a3babSopenharmony_ci clip1.xy *= ubo.viewportDim; 85617a3babSopenharmony_ci 86617a3babSopenharmony_ci // Return the tessellation factor based on the screen size 87617a3babSopenharmony_ci // given by the distance of the two edge control points in screen space 88617a3babSopenharmony_ci // and a reference (min.) tessellation size for the edge set by the application 89617a3babSopenharmony_ci return clamp(distance(clip0, clip1) / ubo.tessellatedEdgeSize * ubo.tessellationFactor, 1.0, 64.0); 90617a3babSopenharmony_ci} 91617a3babSopenharmony_ci 92617a3babSopenharmony_ci// Checks the current's patch visibility against the frustum using a sphere check 93617a3babSopenharmony_ci// Sphere radius is given by the patch size 94617a3babSopenharmony_cibool frustumCheck(float4 Pos, float2 inUV) 95617a3babSopenharmony_ci{ 96617a3babSopenharmony_ci // Fixed radius (increase if patch size is increased in example) 97617a3babSopenharmony_ci const float radius = 8.0f; 98617a3babSopenharmony_ci float4 pos = Pos; 99617a3babSopenharmony_ci pos.y -= textureHeight.SampleLevel(samplerHeight, inUV, 0.0).r * ubo.displacementFactor; 100617a3babSopenharmony_ci 101617a3babSopenharmony_ci // Check sphere against frustum planes 102617a3babSopenharmony_ci for (int i = 0; i < 6; i++) { 103617a3babSopenharmony_ci if (dot(pos, ubo.frustumPlanes[i]) + radius < 0.0) 104617a3babSopenharmony_ci { 105617a3babSopenharmony_ci return false; 106617a3babSopenharmony_ci } 107617a3babSopenharmony_ci } 108617a3babSopenharmony_ci return true; 109617a3babSopenharmony_ci} 110617a3babSopenharmony_ci 111617a3babSopenharmony_ciConstantsHSOutput ConstantsHS(InputPatch<VSOutput, 4> patch) 112617a3babSopenharmony_ci{ 113617a3babSopenharmony_ci ConstantsHSOutput output = (ConstantsHSOutput)0; 114617a3babSopenharmony_ci 115617a3babSopenharmony_ci if (!frustumCheck(patch[0].Pos, patch[0].UV)) 116617a3babSopenharmony_ci { 117617a3babSopenharmony_ci output.TessLevelInner[0] = 0.0; 118617a3babSopenharmony_ci output.TessLevelInner[1] = 0.0; 119617a3babSopenharmony_ci output.TessLevelOuter[0] = 0.0; 120617a3babSopenharmony_ci output.TessLevelOuter[1] = 0.0; 121617a3babSopenharmony_ci output.TessLevelOuter[2] = 0.0; 122617a3babSopenharmony_ci output.TessLevelOuter[3] = 0.0; 123617a3babSopenharmony_ci } 124617a3babSopenharmony_ci else 125617a3babSopenharmony_ci { 126617a3babSopenharmony_ci if (ubo.tessellationFactor > 0.0) 127617a3babSopenharmony_ci { 128617a3babSopenharmony_ci output.TessLevelOuter[0] = screenSpaceTessFactor(patch[3].Pos, patch[0].Pos); 129617a3babSopenharmony_ci output.TessLevelOuter[1] = screenSpaceTessFactor(patch[0].Pos, patch[1].Pos); 130617a3babSopenharmony_ci output.TessLevelOuter[2] = screenSpaceTessFactor(patch[1].Pos, patch[2].Pos); 131617a3babSopenharmony_ci output.TessLevelOuter[3] = screenSpaceTessFactor(patch[2].Pos, patch[3].Pos); 132617a3babSopenharmony_ci output.TessLevelInner[0] = lerp(output.TessLevelOuter[0], output.TessLevelOuter[3], 0.5); 133617a3babSopenharmony_ci output.TessLevelInner[1] = lerp(output.TessLevelOuter[2], output.TessLevelOuter[1], 0.5); 134617a3babSopenharmony_ci } 135617a3babSopenharmony_ci else 136617a3babSopenharmony_ci { 137617a3babSopenharmony_ci // Tessellation factor can be set to zero by example 138617a3babSopenharmony_ci // to demonstrate a simple passthrough 139617a3babSopenharmony_ci output.TessLevelInner[0] = 1.0; 140617a3babSopenharmony_ci output.TessLevelInner[1] = 1.0; 141617a3babSopenharmony_ci output.TessLevelOuter[0] = 1.0; 142617a3babSopenharmony_ci output.TessLevelOuter[1] = 1.0; 143617a3babSopenharmony_ci output.TessLevelOuter[2] = 1.0; 144617a3babSopenharmony_ci output.TessLevelOuter[3] = 1.0; 145617a3babSopenharmony_ci } 146617a3babSopenharmony_ci } 147617a3babSopenharmony_ci 148617a3babSopenharmony_ci return output; 149617a3babSopenharmony_ci} 150617a3babSopenharmony_ci 151617a3babSopenharmony_ci[domain("quad")] 152617a3babSopenharmony_ci[partitioning("integer")] 153617a3babSopenharmony_ci[outputtopology("triangle_cw")] 154617a3babSopenharmony_ci[outputcontrolpoints(4)] 155617a3babSopenharmony_ci[patchconstantfunc("ConstantsHS")] 156617a3babSopenharmony_ci[maxtessfactor(20.0f)] 157617a3babSopenharmony_ciHSOutput main(InputPatch<VSOutput, 4> patch, uint InvocationID : SV_OutputControlPointID) 158617a3babSopenharmony_ci{ 159617a3babSopenharmony_ci HSOutput output = (HSOutput)0; 160617a3babSopenharmony_ci output.Pos = patch[InvocationID].Pos; 161617a3babSopenharmony_ci output.Normal = patch[InvocationID].Normal; 162617a3babSopenharmony_ci output.UV = patch[InvocationID].UV; 163617a3babSopenharmony_ci return output; 164617a3babSopenharmony_ci} 165