Skip to content

Commit 08545b1

Browse files
committed
improved normal map in biplanar mapping shader
1 parent 0480ecf commit 08545b1

File tree

1 file changed

+47
-36
lines changed

1 file changed

+47
-36
lines changed
Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,78 @@
11

2+
// https://iquilezles.org/articles/biplanar/
3+
24
struct Biplanar
35
{
6+
vec3 normal;
7+
ivec3 a1; // dominant axis indices
8+
ivec3 a2; // second axis indices
9+
ivec3 a3; // least significant axis indices
410
vec2 uv1, uv2;
5-
vec2 d1x, d2x;
6-
vec2 d1y, d2y;
11+
vec2 dx1, dx2;
12+
vec2 dy1, dy2;
713
vec2 w;
8-
float div;
914
};
1015

1116
Biplanar biplanarPrepare(vec3 p, vec3 n, float k)
1217
{
1318
Biplanar bip;
19+
bip.normal = n;
1420
vec3 dpdx = dFdx(p);
1521
vec3 dpdy = dFdy(p);
1622
n = abs(n);
17-
ivec3 ma = (n.x > n.y && n.x > n.z) ? ivec3(0, 1, 2) : (n.y > n.z) ? ivec3(1, 2, 0) : ivec3(2, 0, 1);
18-
ivec3 mi = (n.x < n.y && n.x < n.z) ? ivec3(0, 1, 2) : (n.y < n.z) ? ivec3(1, 2, 0) : ivec3(2, 0, 1);
19-
ivec3 me = ivec3(3) - mi - ma;
20-
bip.uv1 = vec2(p[ma.y], p[ma.z]);
21-
bip.uv2 = vec2(p[me.y], p[me.z]);
22-
bip.d1x = vec2(dpdx[ma.y], dpdx[ma.z]);
23-
bip.d2x = vec2(dpdx[me.y], dpdx[me.z]);
24-
bip.d1y = vec2(dpdy[ma.y], dpdy[ma.z]);
25-
bip.d2y = vec2(dpdy[me.y], dpdy[me.z]);
26-
bip.w = vec2(n[ma.x], n[me.x]);
23+
bip.a1 = (n.x > n.y && n.x > n.z) ? ivec3(0, 1, 2) : (n.y > n.z) ? ivec3(1, 2, 0) : ivec3(2, 0, 1);
24+
bip.a3 = (n.x < n.y && n.x < n.z) ? ivec3(0, 1, 2) : (n.y < n.z) ? ivec3(1, 2, 0) : ivec3(2, 0, 1);
25+
bip.a2 = ivec3(3) - bip.a3 - bip.a1;
26+
bip.uv1 = vec2(p[bip.a1.y], p[bip.a1.z]);
27+
bip.uv2 = vec2(p[bip.a2.y], p[bip.a2.z]);
28+
bip.dx1 = vec2(dpdx[bip.a1.y], dpdx[bip.a1.z]);
29+
bip.dx2 = vec2(dpdx[bip.a2.y], dpdx[bip.a2.z]);
30+
bip.dy1 = vec2(dpdy[bip.a1.y], dpdy[bip.a1.z]);
31+
bip.dy2 = vec2(dpdy[bip.a2.y], dpdy[bip.a2.z]);
32+
bip.w = vec2(n[bip.a1.x], n[bip.a2.x]);
2733
bip.w = saturate((bip.w - 0.5773) / (1 - 0.5773));
2834
bip.w = pow(bip.w, vec2(k / 8));
29-
bip.div = 1 / (bip.w.x + bip.w.y);
35+
bip.w /= bip.w[0] + bip.w[1];
3036
return bip;
3137
}
3238

3339
vec4 biplanarSample(sampler2D sam, Biplanar bip)
3440
{
35-
vec4 x = textureGrad(sam, bip.uv1, bip.d1x, bip.d1y);
36-
vec4 y = textureGrad(sam, bip.uv2, bip.d2x, bip.d2y);
37-
return (x * bip.w.x + y * bip.w.y) * bip.div;
41+
vec4 v1 = textureGrad(sam, bip.uv1, bip.dx1, bip.dy1);
42+
vec4 v2 = textureGrad(sam, bip.uv2, bip.dx2, bip.dy2);
43+
return v1 * bip.w[0] + v2 * bip.w[1];
3844
}
3945

4046
vec4 biplanarSample(sampler2DArray sam, Biplanar bip, float arrayIndex)
4147
{
42-
vec4 x = textureGrad(sam, vec3(bip.uv1, arrayIndex), bip.d1x, bip.d1y);
43-
vec4 y = textureGrad(sam, vec3(bip.uv2, arrayIndex), bip.d2x, bip.d2y);
44-
return (x * bip.w.x + y * bip.w.y) * bip.div;
48+
vec4 v1 = textureGrad(sam, vec3(bip.uv1, arrayIndex), bip.dx1, bip.dy1);
49+
vec4 v2 = textureGrad(sam, vec3(bip.uv2, arrayIndex), bip.dx2, bip.dy2);
50+
return v1 * bip.w[0] + v2 * bip.w[1];
51+
}
52+
53+
vec3 egacBiplanarNormal(Biplanar bip, vec3 n1, vec3 n2)
54+
{
55+
// https://bgolus.medium.com/normal-mapping-for-a-triplanar-shader-10bf39dca05a
56+
// whiteout blend
57+
n1.x *= -1;
58+
n2.x *= -1;
59+
n1 = vec3(n1.xy + vec2(bip.normal[bip.a1.z], bip.normal[bip.a1.y]), abs(n1.z) * bip.normal[bip.a1.x]);
60+
n2 = vec3(n2.xy + vec2(bip.normal[bip.a2.z], bip.normal[bip.a2.y]), abs(n2.z) * bip.normal[bip.a2.x]);
61+
n1 = vec3(n1[bip.a1.z], n1[bip.a1.y], n1[bip.a1.x]);
62+
n2 = vec3(n2[bip.a2.z], n2[bip.a2.y], n2[bip.a2.x]);
63+
return n1 * bip.w[0] + n2 * bip.w[1];
4564
}
4665

47-
vec3 biplanarSampleNormal(sampler2D sam, Biplanar bip, vec3 normal)
66+
vec3 biplanarSampleNormal(sampler2D sam, Biplanar bip)
4867
{
49-
vec3 n1 = restoreNormalMap(textureGrad(sam, bip.uv1, bip.d1x, bip.d1y));
50-
vec3 n2 = restoreNormalMap(textureGrad(sam, bip.uv2, bip.d2x, bip.d2y));
51-
mat3 tbn = makeTangentSpace(normal, varPosition - uniViewport.eyePos.xyz, bip.uv1);
52-
n1 = tbn * n1;
53-
tbn = makeTangentSpace(normal, varPosition - uniViewport.eyePos.xyz, bip.uv2);
54-
n2 = tbn * n2;
55-
return normalize(n1 * bip.w.x + n2 * bip.w.y);
68+
vec3 n1 = restoreNormalMap(textureGrad(sam, bip.uv1, bip.dx1, bip.dy1));
69+
vec3 n2 = restoreNormalMap(textureGrad(sam, bip.uv2, bip.dx2, bip.dy2));
70+
return egacBiplanarNormal(bip, n1, n2);
5671
}
5772

58-
vec3 biplanarSampleNormal(sampler2DArray sam, Biplanar bip, vec3 normal, float arrayIndex)
73+
vec3 biplanarSampleNormal(sampler2DArray sam, Biplanar bip, float arrayIndex)
5974
{
60-
vec3 n1 = restoreNormalMap(textureGrad(sam, vec3(bip.uv1, arrayIndex), bip.d1x, bip.d1y));
61-
vec3 n2 = restoreNormalMap(textureGrad(sam, vec3(bip.uv2, arrayIndex), bip.d2x, bip.d2y));
62-
mat3 tbn = makeTangentSpace(normal, varPosition - uniViewport.eyePos.xyz, bip.uv1);
63-
n1 = tbn * n1;
64-
tbn = makeTangentSpace(normal, varPosition - uniViewport.eyePos.xyz, bip.uv2);
65-
n2 = tbn * n2;
66-
return normalize(n1 * bip.w.x + n2 * bip.w.y);
75+
vec3 n1 = restoreNormalMap(textureGrad(sam, vec3(bip.uv1, arrayIndex), bip.dx1, bip.dy1));
76+
vec3 n2 = restoreNormalMap(textureGrad(sam, vec3(bip.uv2, arrayIndex), bip.dx2, bip.dy2));
77+
return egacBiplanarNormal(bip, n1, n2);
6778
}

0 commit comments

Comments
 (0)