summaryrefslogtreecommitdiffstats
path: root/res/effectlib/tessellationPhong.glsllib
blob: 8a5351ab2eceb0f5e60ca56a9e13e4132387a24d (plain)
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#ifndef TESSELLATION_PHONG_GLSLLIB
#define TESSELLATION_PHONG_GLSLLIB

struct PhongTessPatch
{
    float projIJ;
    float projJK;
    float projIK;
};

#if TESSELLATION_CONTROL_SHADER
layout (vertices = 3) out;

layout(location = 15) out PhongTessPatch tcTessPatch[3];

// global setup in main
vec3 ctWorldPos[3];
vec3 ctNorm[3];

uniform vec3 eyePosition;
uniform vec2 distanceRange;
uniform float disableCulling;

float isBackFace()
{
    vec3 faceNormal = normalize( cross( ctWorldPos[2] - ctWorldPos[0], ctWorldPos[1] - ctWorldPos[0] ) );

    vec3 ncd = normalize( ctWorldPos[0] - eyePosition );

    return sign( 0.2 + dot(faceNormal, ncd) ); // 0.2 is a conservative offset to account for curved surfaces
}

float adaptiveCameraFactor( in float minTess, in float maxTess )
{
    float distanceValue0 = distance( eyePosition, ctWorldPos[0] );
    float distanceValue1 = distance( eyePosition, ctWorldPos[1] );
    float distanceValue2 = distance( eyePosition, ctWorldPos[2] );

    float range = distanceRange[1] - distanceRange[0];

    vec3 edgeDistance;
    edgeDistance[0] = ((distanceValue1 + distanceValue2) / 2.0) / range;
    edgeDistance[1] = ((distanceValue2 + distanceValue0) / 2.0) / range;
    edgeDistance[2] = ((distanceValue0 + distanceValue1) / 2.0) / range;

    edgeDistance = clamp( edgeDistance, vec3(0.0), vec3(1.0) );

    //float af = mix( minTess, maxTess,  1.0 - edgeDistance[gl_InvocationID] );
    float af = 1.0 - edgeDistance[gl_InvocationID];
    af = clamp( af*af*maxTess , minTess, maxTess );

    return af;
}

float adaptiveFeatureFactor( in float minTess, in float maxTess )
{
    vec3 adaptValue;
    adaptValue[0] = clamp( dot(ctNorm[1], ctNorm[2]), -1.0, 1.0 );
    adaptValue[1] = clamp( dot(ctNorm[2], ctNorm[0]), -1.0, 1.0 );
    adaptValue[2] = clamp( dot(ctNorm[0], ctNorm[1]), -1.0, 1.0 );

    //float af = min( adaptValue[0], min(adaptValue[1], adaptValue[2]) );
    // map [-1, +1] range to [0, 1] range
    float af = (adaptValue[gl_InvocationID] + 1.0) / 2.0;

    af = mix( minTess, maxTess,  1.0 - af );

    return af;
}

float mapToTangentPlane(int i, vec3 q)
{
    vec3 q_minus_p = q - gl_in[i].gl_Position.xyz;
    return q[gl_InvocationID] - dot(q_minus_p, ctNorm[i]) * ctNorm[i][gl_InvocationID];
}

void tessShader ( in float tessEdge, in float tessInner )
{
    // compute projections separate for each xyz component
    tcTessPatch[gl_InvocationID].projIJ = mapToTangentPlane(0, gl_in[1].gl_Position.xyz) + mapToTangentPlane(1, gl_in[0].gl_Position.xyz);
    tcTessPatch[gl_InvocationID].projJK = mapToTangentPlane(1, gl_in[2].gl_Position.xyz) + mapToTangentPlane(2, gl_in[1].gl_Position.xyz);
    tcTessPatch[gl_InvocationID].projIK = mapToTangentPlane(2, gl_in[0].gl_Position.xyz) + mapToTangentPlane(0, gl_in[2].gl_Position.xyz);

    // compute backface
    float bf = isBackFace();
    bf = max(disableCulling, bf);
    // adapative tessellation factor regarding features
    float af = adaptiveFeatureFactor( tessInner, tessEdge );
    // adapative tessellation factor regarding camera
    //float cf = adaptiveFeatureFactor( tessInner, tessEdge );

    // the camera tess factor is the limit
    //af = min(af, cf);

    // Calculate the tessellation levels
    gl_TessLevelInner[0] = af * bf;
    gl_TessLevelOuter[gl_InvocationID] = af * bf;
}

#endif

#if TESSELLATION_EVALUATION_SHADER
layout (triangles, equal_spacing, ccw) in;

layout(location = 15) in PhongTessPatch tcTessPatch[];

uniform float phongBlend;

vec4 tessShader ( )
{
    // pre compute square tesselation coord
    vec3 tessSquared = gl_TessCoord * gl_TessCoord;

    // barycentric linear position
    vec3 linearPos = gl_TessCoord.x * gl_in[0].gl_Position.xyz
                    + gl_TessCoord.y * gl_in[1].gl_Position.xyz
                    + gl_TessCoord.z * gl_in[2].gl_Position.xyz;

    // projective terms
    vec3 projJI = vec3(tcTessPatch[0].projIJ, tcTessPatch[1].projIJ, tcTessPatch[2].projIJ);
    vec3 projKJ = vec3(tcTessPatch[0].projJK, tcTessPatch[1].projJK, tcTessPatch[2].projJK);
    vec3 projIK = vec3(tcTessPatch[0].projIK, tcTessPatch[1].projIK, tcTessPatch[2].projIK);

    // phong interpolated position
    vec3 phongPos = tessSquared.x * gl_in[0].gl_Position.xyz
                  + tessSquared.y * gl_in[1].gl_Position.xyz
                  + tessSquared.z * gl_in[2].gl_Position.xyz
                  + gl_TessCoord.x * gl_TessCoord.y * projJI
                  + gl_TessCoord.y * gl_TessCoord.z * projKJ
                  + gl_TessCoord.z * gl_TessCoord.x * projIK;

    // final blend between linear and phong interpolation
    vec3 finalPos = (1.0-phongBlend)*linearPos + phongBlend*phongPos;

    return vec4( finalPos, 1.0 );
}
#endif

#endif