1#version 310 es
2
3#define YFLIP 0
4#define SPECULAR 0
5#define GLOSSMAP 0
6
7#define DEBUG_NONE      0
8#define DEBUG_DIFFUSE   1
9#define DEBUG_SPECULAR  2
10#define DEBUG_LIGHTING  3
11#define DEBUG_FOG       4
12#define DEBUG           DEBUG_NONE
13
14#define FORWARD   0
15#define DEFERRED  1
16#define DEFERRED_VTEX 2
17
18float saturate(float x) { return clamp(x, 0.0, 1.0); }
19
20layout(std140, binding = 0) uniform GlobalVSData
21{
22    vec4 g_ViewProj_Row0;
23    vec4 g_ViewProj_Row1;
24    vec4 g_ViewProj_Row2;
25    vec4 g_ViewProj_Row3;
26    vec4 g_CamPos;
27    vec4 g_CamRight;
28    vec4 g_CamUp;
29    vec4 g_CamFront;
30    vec4 g_SunDir;
31    vec4 g_SunColor;
32    vec4 g_TimeParams;
33    vec4 g_ResolutionParams;
34    vec4 g_CamAxisRight;
35    vec4 g_FogColor_Distance;
36    vec4 g_ShadowVP_Row0;
37    vec4 g_ShadowVP_Row1;
38    vec4 g_ShadowVP_Row2;
39    vec4 g_ShadowVP_Row3;
40};
41
42vec4 ComputeFogFactor(vec3 WorldPos)
43{
44    vec4 FogData;
45    vec3 vEye = WorldPos - g_CamPos.xyz;
46    vec3 nEye = normalize(vEye);
47    FogData.w = exp(-dot(vEye, vEye) * g_FogColor_Distance.w * 0.75);
48
49    float fog_sun_factor = pow(saturate(dot(nEye, g_SunDir.xyz)), 8.0);
50    FogData.xyz = mix(vec3(1.0, 1.0, 1.0), vec3(0.6, 0.6, 0.9), nEye.y * 0.5 + 0.5);
51    FogData.xyz = mix(FogData.xyz, vec3(0.95, 0.87, 0.78), fog_sun_factor);
52    return FogData;
53}
54
55void ApplyFog(inout vec3 Color, vec4 FogData)
56{
57    Color = mix(FogData.xyz, Color, FogData.w);
58}
59
60void ApplyLighting(inout mediump vec3 Color, mediump float DiffuseFactor)
61{
62    mediump vec3 DiffuseLight = g_SunColor.xyz * DiffuseFactor;
63    mediump vec3 AmbientLight = vec3(0.2, 0.35, 0.55) * 0.5;
64    mediump vec3 Lighting = DiffuseLight + AmbientLight;
65#if DEBUG == DEBUG_LIGHTING
66    Color = Lighting;
67#else
68    Color *= Lighting;
69#endif
70}
71
72#pragma VARIANT SPECULAR
73#pragma VARIANT GLOSSMAP
74
75void ApplySpecular(inout mediump vec3 Color, mediump vec3 EyeVec, mediump vec3 Normal, mediump vec3 SpecularColor, mediump float Shininess, mediump float FresnelAmount)
76{
77    mediump vec3 HalfAngle = normalize(-EyeVec + g_SunDir.xyz);
78
79    mediump float v_dot_h = saturate(dot(HalfAngle, -EyeVec));
80    mediump float n_dot_l = saturate(dot(Normal, g_SunDir.xyz));
81    mediump float n_dot_h = saturate(dot(Normal, HalfAngle));
82    mediump float n_dot_v = saturate(dot(-EyeVec, Normal));
83    mediump float h_dot_l = saturate(dot(g_SunDir.xyz, HalfAngle));
84
85    const mediump float roughness_value = 0.25;
86
87    mediump float r_sq = roughness_value * roughness_value;
88    mediump float n_dot_h_sq = n_dot_h * n_dot_h;
89    mediump float roughness_a = 1.0 / (4.0 * r_sq * n_dot_h_sq * n_dot_h_sq);
90    mediump float roughness_b = n_dot_h_sq - 1.0;
91    mediump float roughness_c = r_sq * n_dot_h_sq;
92    mediump float roughness = saturate(roughness_a * exp(roughness_b / roughness_c));
93
94    FresnelAmount = 0.5;
95    mediump float fresnel_term = pow(1.0 - n_dot_v, 5.0) * (1.0 - FresnelAmount) + FresnelAmount;
96
97    mediump float geo_numerator = 2.0 * n_dot_h;
98    mediump float geo_denominator = 1.0 / v_dot_h;
99    mediump float geo_term = min(1.0, min(n_dot_v, n_dot_l) * geo_numerator * geo_denominator);
100
101#if SPECULAR || GLOSSMAP
102    Color += SpecularColor * g_SunColor.xyz * fresnel_term * roughness * n_dot_l * geo_term / (n_dot_v * n_dot_l + 0.0001);
103#endif
104
105    //Color = vec3(0.025 * 1.0 / (n_dot_v * n_dot_l));
106}
107
108layout(location = 0) in vec2 Position;
109layout(location = 1) in vec4 LODWeights;
110
111layout(location = 0) out vec2 TexCoord;
112layout(location = 1) out vec3 EyeVec;
113
114layout(std140, binding = 2) uniform GlobalGround
115{
116    vec4 GroundScale;
117    vec4 GroundPosition;
118    vec4 InvGroundSize_PatchScale;
119};
120
121struct PatchData
122{
123    vec4 Position;
124    vec4 LODs;
125};
126
127layout(std140, binding = 0) uniform PerPatch
128{
129    PatchData Patches[256];
130};
131
132layout(binding = 0) uniform sampler2D TexHeightmap;
133layout(binding = 1) uniform sampler2D TexLOD;
134
135vec2 lod_factor(vec2 uv)
136{
137    float level = textureLod(TexLOD, uv, 0.0).x * (255.0 / 32.0);
138    float floor_level = floor(level);
139    float fract_level = level - floor_level;
140    return vec2(floor_level, fract_level);
141}
142
143#ifdef VULKAN
144#define INSTANCE_ID gl_InstanceIndex
145#else
146#define INSTANCE_ID gl_InstanceID
147#endif
148
149vec2 warp_position()
150{
151    float vlod = dot(LODWeights, Patches[INSTANCE_ID].LODs);
152    vlod = mix(vlod, Patches[INSTANCE_ID].Position.w, all(equal(LODWeights, vec4(0.0))));
153
154#ifdef DEBUG_LOD_HEIGHT
155    LODFactor = vec4(vlod);
156#endif
157
158    float floor_lod = floor(vlod);
159    float fract_lod = vlod - floor_lod;
160    uint ufloor_lod = uint(floor_lod);
161
162#ifdef DEBUG_LOD_HEIGHT
163    LODFactor = vec4(fract_lod);
164#endif
165
166    uvec2 uPosition = uvec2(Position);
167    uvec2 mask = (uvec2(1u) << uvec2(ufloor_lod, ufloor_lod + 1u)) - 1u;
168    //uvec2 rounding = mix(uvec2(0u), mask, lessThan(uPosition, uvec2(32u)));
169
170    uvec2 rounding = uvec2(
171        uPosition.x < 32u ? mask.x : 0u,
172        uPosition.y < 32u ? mask.y : 0u);
173
174    vec4 lower_upper_snapped = vec4((uPosition + rounding).xyxy & (~mask).xxyy);
175    return mix(lower_upper_snapped.xy, lower_upper_snapped.zw, fract_lod);
176}
177
178void main()
179{
180    vec2 PatchPos = Patches[INSTANCE_ID].Position.xz * InvGroundSize_PatchScale.zw;
181    vec2 WarpedPos = warp_position();
182    vec2 VertexPos = PatchPos + WarpedPos;
183    vec2 NormalizedPos = VertexPos * InvGroundSize_PatchScale.xy;
184    vec2 lod = lod_factor(NormalizedPos);
185
186    vec2 Offset = exp2(lod.x) * InvGroundSize_PatchScale.xy;
187
188    float Elevation =
189        mix(textureLod(TexHeightmap, NormalizedPos + 0.5 * Offset, lod.x).x,
190            textureLod(TexHeightmap, NormalizedPos + 1.0 * Offset, lod.x + 1.0).x,
191            lod.y);
192
193    vec3 WorldPos = vec3(NormalizedPos.x, Elevation, NormalizedPos.y);
194    WorldPos *= GroundScale.xyz;
195    WorldPos += GroundPosition.xyz;
196
197    EyeVec = WorldPos - g_CamPos.xyz;
198    TexCoord = NormalizedPos + 0.5 * InvGroundSize_PatchScale.xy;
199
200    gl_Position = WorldPos.x * g_ViewProj_Row0 + WorldPos.y * g_ViewProj_Row1 + WorldPos.z * g_ViewProj_Row2 + g_ViewProj_Row3;
201}
202
203