diff options
| -rw-r--r-- | aperiodic_tiling.cginc | 98 | ||||
| -rwxr-xr-x | pbr.cginc | 2 |
2 files changed, 100 insertions, 0 deletions
diff --git a/aperiodic_tiling.cginc b/aperiodic_tiling.cginc new file mode 100644 index 0000000..fa69712 --- /dev/null +++ b/aperiodic_tiling.cginc @@ -0,0 +1,98 @@ +#ifndef __APERIODIC_TILING_INC +#define __APERIODIC_TILING_INC + +// 5D cut-and-project for Penrose tiling. +// References: +// https://www.shadertoy.com/view/XccXW8 (public domain) +// https://gglouser.github.io/cut-and-project-tiling/docs/intro.html#how-it-works +// https://www.youtube.com/watch?v=hwMAOFb6yvA + +#include "math.cginc" + +static const float M5 = sqrt(2.0 / 5.0); + +float4 basis_u5_03 = M5 * float4( + cos(0 * TAU / 10), + cos(1 * TAU / 10), + cos(2 * TAU / 10), + cos(3 * TAU / 10)); +float basis_u5_44 = M5 * cos(4 * TAU / 10); + +float4 basis_v5_03 = M5 * float4( + sin(0 * TAU / 10), + sin(1 * TAU / 10), + sin(2 * TAU / 10), + sin(3 * TAU / 10)); +float basis_v5_44 = M5 * sin(4 * TAU / 10); + +float dot5(float4 a03, float a44, float4 b03, float b44) { + return dot(a03, b03) + a44 * b44; +} + +float2 proj5(float4 p03, float p44) { + return float2( + dot5(p03, p44, basis_u5_03, basis_u5_44), + dot5(p03, p44, basis_v5_03, basis_v5_44)); +} + +float2x2 inv2x2(float2x2 m) { + float d = m[0][0] * m[1][1] - m[0][1] * m[1][0]; + return float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / d; +} + +// Test if point p lies in one candidate tile. +// m: inverse of the forward (barycentric -> projected) matrix. +// s: barycentric center of the candidate tile. +// a, b: axis selectors for this face orientation. +float tile5(float4 p03, float p44, float2x2 m, float2 s, + float4 a03, float a44, float4 b03, float b44) { + float2 q = mul(s, m); + p03 -= (1 - a03 - b03) * round(q.x * basis_u5_03 + q.y * basis_v5_03); + p44 -= (1 - a44 - b44) * round(q.x * basis_u5_44 + q.y * basis_v5_44); + float2 f = abs(mul(m, proj5(p03, p44)) - s); + return max(0.0, 0.5 - max(f.x, f.y)); +} + +// Test all 4 candidate tiles for one face orientation. +// Returns barycentric distance to nearest edge (positive inside, zero outside). +float t5(float4 p03, float p44, float4 a03, float a44, float4 b03, float b44) { + float2 pa = proj5(a03, a44); + float2 pb = proj5(b03, b44); + float2x2 m = inv2x2(float2x2(pa.x, pb.x, pa.y, pb.y)); + float2 r = round(float2(dot5(p03, p44, a03, a44), dot5(p03, p44, b03, b44))); + float2 s = float2(0.5, -0.5); + return tile5(p03, p44, m, r + s.xx, a03, a44, b03, b44) + + tile5(p03, p44, m, r + s.xy, a03, a44, b03, b44) + + tile5(p03, p44, m, r + s.yx, a03, a44, b03, b44) + + tile5(p03, p44, m, r + s.yy, a03, a44, b03, b44); +} + +float3 dim5(float2 uv) { + float4 p03 = uv.x * basis_u5_03 + uv.y * basis_v5_03; + float p44 = uv.x * basis_u5_44 + uv.y * basis_v5_44; + + float2 u = float2(0, 1); + float3 edge = float3(0.04, 0.1, 0.04); + float3 c = edge; + + // 10 face orientations = C(5,2) pairs of 5D axes + c += (float3(0.4, 0.9, 0.4) - edge) * t5(p03, p44, u.yxxx, u.x, u.xyxx, u.x); + c += (float3(0.6, 0.7, 0.2) - edge) * t5(p03, p44, u.yxxx, u.x, u.xxyx, u.x); + c += (float3(0.3, 0.5, 0.0) - edge) * t5(p03, p44, u.yxxx, u.x, u.xxxy, u.x); + c += (float3(0.2, 0.3, 0.0) - edge) * t5(p03, p44, u.yxxx, u.x, u.xxxx, u.y); + c += (float3(0.0, 0.3, 0.2) - edge) * t5(p03, p44, u.xyxx, u.x, u.xxyx, u.x); + c += (float3(0.0, 0.5, 0.4) - edge) * t5(p03, p44, u.xyxx, u.x, u.xxxy, u.x); + c += (float3(0.2, 0.7, 0.6) - edge) * t5(p03, p44, u.xyxx, u.x, u.xxxx, u.y); + c += (float3(0.3, 0.6, 0.0) - edge) * t5(p03, p44, u.xxyx, u.x, u.xxxy, u.x); + c += (float3(0.0, 0.4, 0.0) - edge) * t5(p03, p44, u.xxyx, u.x, u.xxxx, u.y); + c += (float3(0.0, 0.6, 0.3) - edge) * t5(p03, p44, u.xxxy, u.x, u.xxxx, u.y); + + return c; +} + +void apply_aperiodic_tiling(float2 uv, inout float3 albedo) { + albedo = dim5(uv); +} + +#endif // __APERIODIC_TILING_INC + @@ -1,6 +1,7 @@ #ifndef __PBR_INC #define __PBR_INC +#include "aperiodic_tiling.cginc" #include "burley.cginc" #include "custom31.cginc" #include "data.cginc" @@ -286,6 +287,7 @@ Pbr getPbr(v2f i) { apply_burley_tiling(pbr, normal_tangent); apply_triplanar_layers(i.worldPos, i.normal, pbr, normal_tangent); apply_custom31_world(i, pbr, normal_tangent); + apply_aperiodic_tiling(i.uv01.xy, pbr.albedo.xyz); applyDecals(i, pbr, normal_tangent); |
