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