1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
//----------------------------------------------------------------------------------
// File: FaceWorks/samples/sample_d3d11/shaders/tess_hs.hlsl
// SDK Version: v1.0
// Email: [email protected]
// Site: http://developer.nvidia.com/
//
// Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//----------------------------------------------------------------------------------
#include "common.hlsli"
#include "tess.hlsli"
void calcHSConstants(
in InputPatch<Vertex, 3> i_cps,
out PatchConstData o_pcd)
{
// Backface culling: check if the camera is behind all three tangent planes
float3 vecNdotV =
{
dot(g_posCamera - i_cps[0].m_pos, i_cps[0].m_normal),
dot(g_posCamera - i_cps[1].m_pos, i_cps[1].m_normal),
dot(g_posCamera - i_cps[2].m_pos, i_cps[2].m_normal),
};
if (all(vecNdotV < 0.0))
{
o_pcd.m_tessFactor[0] = 0.0;
o_pcd.m_tessFactor[1] = 0.0;
o_pcd.m_tessFactor[2] = 0.0;
o_pcd.m_insideTessFactor = 0.0;
return;
}
// Frustum culling: check if all three verts are out on the same side of the frustum
// This isn't quite correct because the displacement could make a patch visible even if
// it fails this test; but in practice this is nearly impossible to notice
float4 posClip0 = mul(float4(i_cps[0].m_pos, 1.0), g_matWorldToClip);
float4 posClip1 = mul(float4(i_cps[1].m_pos, 1.0), g_matWorldToClip);
float4 posClip2 = mul(float4(i_cps[2].m_pos, 1.0), g_matWorldToClip);
float3 xs = { posClip0.x, posClip1.x, posClip2.x };
float3 ys = { posClip0.y, posClip1.y, posClip2.y };
float3 ws = { posClip0.w, posClip1.w, posClip2.w };
if (all(xs < -ws) || all(xs > ws) || all(ys < -ws) || all(ys > ws))
{
o_pcd.m_tessFactor[0] = 0.0;
o_pcd.m_tessFactor[1] = 0.0;
o_pcd.m_tessFactor[2] = 0.0;
o_pcd.m_insideTessFactor = 0.0;
return;
}
// Adaptive tessellation based on a screen-space error estimate using curvature
// Calculate approximate screen-space edge length, but including z length as well,
// so we don't undertessellate edges that are foreshortened
float edge0 = length(i_cps[2].m_pos - i_cps[1].m_pos) / (0.5 * (posClip2.w + posClip1.w));
float edge1 = length(i_cps[0].m_pos - i_cps[2].m_pos) / (0.5 * (posClip0.w + posClip2.w));
float edge2 = length(i_cps[1].m_pos - i_cps[0].m_pos) / (0.5 * (posClip1.w + posClip0.w));
// Calculate dots of the two normals on each edge - used to give more tessellation
// in areas with higher curvature
float normalDot0 = dot(i_cps[2].m_normal, i_cps[1].m_normal);
float normalDot1 = dot(i_cps[0].m_normal, i_cps[2].m_normal);
float normalDot2 = dot(i_cps[1].m_normal, i_cps[0].m_normal);
// Calculate target screen-space error
static const float errPxTarget = 0.5;
static const float tanHalfFov = tan(0.5 * 0.5);
static const float errTarget = errPxTarget * 2.0 * tanHalfFov / 1080.0;
// Calculate tess factors using curve fitting approximation to screen-space error
// derived from curvature and edge length
static const float tessScale = 0.41 / sqrt(errTarget);
o_pcd.m_tessFactor[0] = g_tessScale * sqrt(edge0) * pow(1.0 - saturate(normalDot0), 0.27);
o_pcd.m_tessFactor[1] = g_tessScale * sqrt(edge1) * pow(1.0 - saturate(normalDot1), 0.27);
o_pcd.m_tessFactor[2] = g_tessScale * sqrt(edge2) * pow(1.0 - saturate(normalDot2), 0.27);
// Clamp to supported range
o_pcd.m_tessFactor[0] = clamp(o_pcd.m_tessFactor[0], 1.0, s_tessFactorMax);
o_pcd.m_tessFactor[1] = clamp(o_pcd.m_tessFactor[1], 1.0, s_tessFactorMax);
o_pcd.m_tessFactor[2] = clamp(o_pcd.m_tessFactor[2], 1.0, s_tessFactorMax);
// Set interior tess factor to maximum of edge factors
o_pcd.m_insideTessFactor = max(max(o_pcd.m_tessFactor[0],
o_pcd.m_tessFactor[1]),
o_pcd.m_tessFactor[2]);
}
[domain("tri")]
[maxtessfactor(s_tessFactorMax)]
[outputcontrolpoints(3)]
[outputtopology("triangle_cw")]
[partitioning("fractional_odd")]
[patchconstantfunc("calcHSConstants")]
Vertex main(
in InputPatch<Vertex, 3> i_cps,
in uint iCp : SV_OutputControlPointID)
{
return i_cps[iCp];
}
|