summaryrefslogtreecommitdiffstats
path: root/aperiodic_tiling.cginc
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-04-10 18:40:47 -0700
committeryum <yum.food.vr@gmail.com>2026-04-10 18:40:47 -0700
commitf2ceb26af143f2e929e4f23ccb1fc86fa9e5307b (patch)
treea4b391469ab805a8361a28c74b9daa24a85dbe69 /aperiodic_tiling.cginc
parent283b8f253cff4a0e39005ba675d7c2cd7ef3c123 (diff)
aperiodic: let user specify colors, add normals
Diffstat (limited to 'aperiodic_tiling.cginc')
-rw-r--r--aperiodic_tiling.cginc140
1 files changed, 108 insertions, 32 deletions
diff --git a/aperiodic_tiling.cginc b/aperiodic_tiling.cginc
index 78c911d..5e12ee0 100644
--- a/aperiodic_tiling.cginc
+++ b/aperiodic_tiling.cginc
@@ -10,6 +10,8 @@
#include "globals.cginc"
#include "math.cginc"
+#if defined(_APERIODIC_TILING)
+
static const float M5 = sqrt(2.0 / 5.0);
static const float4 basis_u5_03 = M5 * float4(
@@ -41,60 +43,134 @@ float2x2 inv2x2(float2x2 m) {
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) {
+struct AperiodicTileSample {
+ float coverage;
+ float2 barycentric;
+};
+
+float2 tile5_barycentric(float4 p03, float p44, float2x2 m, float2 s,
+ float4 a03, float a44, float4 b03, float b44) {
float2 q = mul(s, m);
p03 -= (1.0 - a03 - b03) * round(q.x * basis_u5_03 + q.y * basis_v5_03);
p44 -= (1.0 - 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));
+ return mul(m, proj5(p03, p44)) - s;
+}
+
+float tile5_distance_from_barycentric(float2 barycentric) {
+ float2 f = abs(barycentric);
+ return 0.5 - max(f.x, f.y);
+}
+
+float aperiodic_edge_coverage(float distance_to_edge) {
+ float edge_width = saturate(_Aperiodic_Tiling_Edge_Thickness * 2.0) * 0.5;
+ float signed_distance = distance_to_edge - edge_width;
+ float aa_width = max(fwidth(signed_distance), 1e-4);
+ return smoothstep(-aa_width, aa_width, signed_distance);
}
-// 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) {
+#if defined(_APERIODIC_TILING_NORMALS)
+float3 aperiodic_tiling_normal(float2 barycentric) {
+ float bevel_width = min(_Aperiodic_Tiling_Normal_Thickness, 0.5);
+ if (bevel_width <= 1e-5) {
+ return float3(0.0, 0.0, 1.0);
+ }
+
+ float flat_limit = 0.5 - bevel_width;
+ float2 edge_factor = smoothstep(flat_limit, 0.5, abs(barycentric));
+ float2 xy = sign(barycentric) * edge_factor * _Aperiodic_Tiling_Normal_Strength;
+ return normalize(float3(xy, 1.0));
+}
+#endif // _APERIODIC_TILING_NORMALS
+
+void choose_aperiodic_candidate(float2 barycentric, inout float distance_to_edge,
+ inout float2 best_barycentric) {
+ float candidate_distance = tile5_distance_from_barycentric(barycentric);
+ if (candidate_distance > distance_to_edge) {
+ distance_to_edge = candidate_distance;
+ best_barycentric = barycentric;
+ }
+}
+
+AperiodicTileSample sample_aperiodic_orientation(
+ 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);
+
+ float2 best_barycentric = tile5_barycentric(p03, p44, m, r + s.xx, a03, a44, b03, b44);
+ float distance_to_edge = tile5_distance_from_barycentric(best_barycentric);
+ choose_aperiodic_candidate(
+ tile5_barycentric(p03, p44, m, r + s.xy, a03, a44, b03, b44),
+ distance_to_edge, best_barycentric);
+ choose_aperiodic_candidate(
+ tile5_barycentric(p03, p44, m, r + s.yx, a03, a44, b03, b44),
+ distance_to_edge, best_barycentric);
+ choose_aperiodic_candidate(
+ tile5_barycentric(p03, p44, m, r + s.yy, a03, a44, b03, b44),
+ distance_to_edge, best_barycentric);
+
+ AperiodicTileSample sample;
+ sample.coverage = aperiodic_edge_coverage(distance_to_edge);
+ sample.barycentric = best_barycentric;
+ return sample;
+}
+
+void apply_aperiodic_orientation(float3 face_color,
+ float4 p03, float p44,
+ float4 a03, float a44, float4 b03, float b44,
+ float3 edge_color,
+ inout float3 albedo, inout float2 normal_xy_acc) {
+ AperiodicTileSample sample =
+ sample_aperiodic_orientation(p03, p44, a03, a44, b03, b44);
+ albedo += (face_color - edge_color) * sample.coverage;
+#if defined(_APERIODIC_TILING_NORMALS)
+ normal_xy_acc += aperiodic_tiling_normal(sample.barycentric).xy * sample.coverage;
+#endif
}
-float3 dim5(float2 uv) {
+void sample_aperiodic_tiling(float2 uv, out float3 albedo
+ , out float3 tiling_normal_tangent
+ ) {
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;
+ float3 edge = _Aperiodic_Tiling_Edge_Color.rgb;
+ albedo = edge;
+ float2 normal_xy_accum = 0;
// 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;
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_0.rgb, p03, p44, u.yxxx, u.x, u.xyxx, u.x, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_1.rgb, p03, p44, u.yxxx, u.x, u.xxyx, u.x, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_2.rgb, p03, p44, u.yxxx, u.x, u.xxxy, u.x, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_3.rgb, p03, p44, u.yxxx, u.x, u.xxxx, u.y, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_4.rgb, p03, p44, u.xyxx, u.x, u.xxyx, u.x, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_5.rgb, p03, p44, u.xyxx, u.x, u.xxxy, u.x, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_6.rgb, p03, p44, u.xyxx, u.x, u.xxxx, u.y, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_7.rgb, p03, p44, u.xxyx, u.x, u.xxxy, u.x, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_8.rgb, p03, p44, u.xxyx, u.x, u.xxxx, u.y, edge, albedo, normal_xy_accum);
+ apply_aperiodic_orientation(_Aperiodic_Tiling_Color_9.rgb, p03, p44, u.xxxy, u.x, u.xxxx, u.y, edge, albedo, normal_xy_accum);
+
+#if defined(_APERIODIC_TILING_NORMALS)
+ tiling_normal_tangent = normalize(float3(normal_xy_accum, 1.0));
+#else
+ tiling_normal_tangent = 0;
+#endif
}
+#endif // defined(_APERIODIC_TILING)
-void apply_aperiodic_tiling(float2 uv, inout float3 albedo) {
+void apply_aperiodic_tiling(float2 uv, inout float3 albedo, inout float3 normal_tangent) {
#if defined(_APERIODIC_TILING)
uv *= _Aperiodic_Tiling_Scale;
- albedo = dim5(uv);
+ float3 tiling_normal_tangent;
+ sample_aperiodic_tiling(uv, albedo
+ , tiling_normal_tangent
+ );
+#if defined(_APERIODIC_TILING_NORMALS)
+ normal_tangent = blendNormalsHill12(normal_tangent, tiling_normal_tangent);
+#endif
#endif // _APERIODIC_TILING
}