-
Notifications
You must be signed in to change notification settings - Fork 96
Expand file tree
/
Copy pathpomEffects.glsl
More file actions
222 lines (172 loc) · 7.43 KB
/
pomEffects.glsl
File metadata and controls
222 lines (172 loc) · 7.43 KB
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#include "/lib/util/dither.glsl"
vec2 vTexCoord = signMidCoordPos * 0.5 + 0.5;
#include "/lib/util/dFdxdFdy.glsl"
vec4 ReadNormal(vec2 coord) {
coord = fract(coord) * vTexCoordAM.pq + vTexCoordAM.st;
return textureGrad(normals, coord, dcdx, dcdy);
}
vec2 TileEpsilon() {
vec2 tileSize = atlasSize * vTexCoordAM.pq;
return 0.5 / tileSize;
}
vec2 AtlasClamp(vec2 local) {
vec2 eps = TileEpsilon();
vec2 lc = clamp(local, eps, 1.0 - eps);
return lc * vTexCoordAM.pq + vTexCoordAM.st;
}
vec4 ReadNormalLocalNoWrap(vec2 localCoord) {
vec2 atlasCoord = AtlasClamp(localCoord);
return textureGrad(normals, atlasCoord, dcdx, dcdy);
}
#define ATLAS(_local_) (fract(_local_) * vTexCoordAM.pq + vTexCoordAM.st)
// Created a new function to mitigate the side effects in case the original one has any reference outside this scope
vec4 ReadNormalLocal(vec2 localCoord) {
vec2 atlasCoord = ATLAS(localCoord);
return textureGrad(normals, atlasCoord, dcdx, dcdy);
}
vec2 GetParallaxCoord(float parallaxFade, float dither, inout vec2 newCoord, inout float texDepth, inout vec3 traceCoordDepth) {
float invParallaxQuality = 1.0 / POM_QUALITY;
float minHeight = 1.0 - invParallaxQuality;
vec4 normalMap = ReadNormal(vTexCoord.st);
vec2 normalMapM = normalMap.xy * 2.0 - 1.0;
float normalCheck = normalMapM.x + normalMapM.y;
// Early-outs: grazing view, flat height, extreme normal and nearly faded
if (viewVector.z >= 0.0 || normalMap.a >= minHeight || normalCheck <= -1.999 || parallaxFade > 0.98) return vTexCoord.st;
// Layer step in tangent plane (scaled by depth & fade)
vec2 layerStep = viewVector.xy * (0.25 * (1.0 - parallaxFade) * POM_DEPTH) / (-viewVector.z * POM_QUALITY);
float i = 0.0;
vec2 baseLC = vTexCoord.st;
float h = texDepth; // if a caller-provided history exists; otherwise first sample overwrites
// Ensure texDepth matches current start layer
{
vec2 lc0 = baseLC + i * layerStep;
h = ReadNormalLocal(lc0).a;
}
#if defined GBUFFERS_TERRAIN || defined GBUFFERS_BLOCK
if (texDepth <= 1.0 - i * invParallaxQuality) {
i = dither;
vec2 lc1 = baseLC + i * layerStep;
h = texDepth = ReadNormalLocal(lc1).a;
}
#endif
// Calculate stride based on |z|
float viewFlat = clamp(1.0 - abs(viewVector.z), 0.0, 1.0);
float coarseStride = mix(1.0, 2.0, clamp(0.4 * parallaxFade + 0.4 * viewVector.z*viewVector.z, 0.0, 1.0));
coarseStride = (viewFlat > 0.7) ? 1.0 : coarseStride;
// March forward by stride until we cross the height threshold
float iPrev = i;
float hPrev = h;
for (; i < POM_QUALITY && h <= (1.0 - i * invParallaxQuality); i += coarseStride) {
vec2 lc = baseLC + i * layerStep;
hPrev = h;
iPrev = i;
h = ReadNormalLocal(lc).a;
}
// If we ran out of layers without crossing, clamp to last valid layer and return
if (i >= POM_QUALITY && h <= (1.0 - (POM_QUALITY - 1.0) * invParallaxQuality)) {
i = POM_QUALITY;
float pI = float(max(int(i) - 1, 0));
traceCoordDepth.xy -= pI * layerStep;
traceCoordDepth.z -= pI * invParallaxQuality;
vec2 localCoord = baseLC + pI * layerStep;
newCoord = AtlasClamp(localCoord);
texDepth = ReadNormalLocalNoWrap(localCoord).a;
return clamp(localCoord, 0.0, 1.0);
}
// Refine with a short binary search in the [iPrev, i] bracket
float lo = max(iPrev, 0.0);
float hi = clamp(i, 0.0, POM_QUALITY);
float hLo = hPrev;
float hHi = h;
for (int it = 0; it < 3; ++it) {
float mid = 0.5 * (lo + hi);
float threshold = 1.0 - mid * invParallaxQuality;
vec2 lcMid = baseLC + mid * layerStep;
float hMid = ReadNormalLocal(lcMid).a;
bool below = (hMid <= threshold);
lo = below ? mid : lo;
hi = below ? hi : mid;
hLo = below ? hMid: hLo;
hHi = below ? hHi : hMid;
}
// Pick the layer just before the crossing
float pI = max(lo, 0.0);
// Accumulate trace offsets (xy: coord, z: layer depth)
traceCoordDepth.xy -= pI * layerStep;
traceCoordDepth.z -= pI * invParallaxQuality;
vec2 localCoord = fract(baseLC + pI * layerStep);
newCoord = ATLAS(localCoord);
texDepth = ReadNormalLocal(baseLC + pI * layerStep).a;
return localCoord;
}
float GetParallaxShadow(float parallaxFade, float dither, float height,
vec2 coord /* local [0..1] */, vec3 lightVec, mat3 tbn) {
if (parallaxFade >= 0.98) return 1.0;
vec3 parallaxdir = tbn * lightVec;
if (abs(parallaxdir.z) < 1e-4) return 1.0;
// scale to your POM depth (same as main trace)
parallaxdir.xy *= POM_DEPTH;
// steps tuned by fade
int MAX_STEPS = (parallaxFade < 0.25) ? 4 : 2;
float parallaxshadow = 1.0;
vec2 baseLocal = coord;
vec2 eps = TileEpsilon();
for (int i = 0; i < MAX_STEPS && parallaxshadow >= 0.01; ++i) {
float stepLC = 0.025 * (float(i) + dither);
float currentHeight = height + parallaxdir.z * stepLC;
// NO fract: march in local, and bail if we’d leave the tile
vec2 lc = baseLocal + parallaxdir.xy * stepLC;
// If off the tile, treat as unoccluded and stop (prevents seam shadows)
if (any(lessThan(lc, eps)) || any(greaterThan(lc, 1.0 - eps))) {
break;
}
float offsetHeight = ReadNormalLocalNoWrap(lc).a;
// soften when the surface rises above the ray
parallaxshadow *= clamp(1.0 - (offsetHeight - currentHeight) * 4.0, 0.0, 1.0);
}
return mix(parallaxshadow, 1.0, parallaxFade);
}
// Big thanks to null511 for slope normals
vec3 GetParallaxSlopeNormal(vec2 texCoord, float traceDepth, vec3 viewDir) {
vec2 atlasPixelSize = 1.0 / atlasSize;
float atlasAspect = atlasSize.x / atlasSize.y;
vec2 atlasCoord = fract(texCoord) * vTexCoordAM.pq + vTexCoordAM.st;
vec2 tileSize = atlasSize * vTexCoordAM.pq;
vec2 tilePixelSize = 1.0 / tileSize;
vec2 tex_snapped = floor(atlasCoord * atlasSize) * atlasPixelSize;
vec2 tex_offset = atlasCoord - (tex_snapped + 0.5 * atlasPixelSize);
vec2 stepSign = sign(tex_offset);
vec2 viewSign = sign(viewDir.xy);
bool dir = abs(tex_offset.x * atlasAspect) < abs(tex_offset.y);
vec2 tex_x, tex_y;
if (dir) {
tex_x = texCoord - vec2(tilePixelSize.x * viewSign.x, 0.0);
tex_y = texCoord + vec2(0.0, stepSign.y * tilePixelSize.y);
}
else {
tex_x = texCoord + vec2(tilePixelSize.x * stepSign.x, 0.0);
tex_y = texCoord - vec2(0.0, viewSign.y * tilePixelSize.y);
}
float height_x = ReadNormal(tex_x).a;
float height_y = ReadNormal(tex_y).a;
if (dir) {
if (!(traceDepth > height_y && viewSign.y != stepSign.y)) {
if (traceDepth > height_x) return vec3(-viewSign.x, 0.0, 0.0);
if (abs(viewDir.y) > abs(viewDir.x))
return vec3(0.0, -viewSign.y, 0.0);
else
return vec3(-viewSign.x, 0.0, 0.0);
}
return vec3(0.0, -viewSign.y, 0.0);
}
else {
if (!(traceDepth > height_x && viewSign.x != stepSign.x)) {
if (traceDepth > height_y) return vec3(0.0, -viewSign.y, 0.0);
if (abs(viewDir.y) > abs(viewDir.x))
return vec3(0.0, -viewSign.y, 0.0);
else
return vec3(-viewSign.x, 0.0, 0.0);
}
return vec3(-viewSign.x, 0.0, 0.0);
}
}