summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--aperiodic_tiling.cginc98
-rwxr-xr-xpbr.cginc2
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
+
diff --git a/pbr.cginc b/pbr.cginc
index 38fd59b..8326ccf 100755
--- a/pbr.cginc
+++ b/pbr.cginc
@@ -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);