summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-04-11 16:22:04 -0700
committeryum <yum.food.vr@gmail.com>2026-04-11 16:22:04 -0700
commit5665d87d1b203cd95e57cc6de4e70abc67741076 (patch)
treeeab1651cfe18812497260c3263f1c49e91be9897
parent30008343bafccd813b5432bb09f3f2af2ee2785b (diff)
aperiodic: clanker analytic aa
-rw-r--r--aperiodic_tiling.cginc177
1 files changed, 92 insertions, 85 deletions
diff --git a/aperiodic_tiling.cginc b/aperiodic_tiling.cginc
index 142a3de..1907c69 100644
--- a/aperiodic_tiling.cginc
+++ b/aperiodic_tiling.cginc
@@ -51,9 +51,20 @@ float2 tile5_barycentric(float4 p03, float p44, float2x2 m, float2 s,
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 interval_box_coverage(float center, float half_extent, float radius) {
+ if (half_extent <= 1e-5) {
+ return abs(center) <= radius ? 1.0 : 0.0;
+ }
+
+ float lo = center - half_extent;
+ float hi = center + half_extent;
+ float overlap = max(min(hi, radius) - max(lo, -radius), 0.0);
+ return overlap / (2.0 * half_extent);
+}
+
+float square_box_coverage(float2 barycentric, float2 half_extents, float radius) {
+ return interval_box_coverage(barycentric.x, half_extents.x, radius) *
+ interval_box_coverage(barycentric.y, half_extents.y, radius);
}
#if defined(_APERIODIC_TILING_NORMALS)
@@ -70,104 +81,102 @@ float3 aperiodic_tiling_normal(float2 barycentric) {
}
#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);
- bool better = (candidate_distance > distance_to_edge);
- distance_to_edge = better ? candidate_distance : distance_to_edge;
- best_barycentric = better ? barycentric : best_barycentric;
-}
+void accumulate_filtered_candidate(
+ float2 barycentric, float2 footprint_half_extents, float edge_width, float3 face_color,
+ inout float3 color_sum, inout float outer_sum, inout float2 normal_xy_sum) {
+ float outer = square_box_coverage(barycentric, footprint_half_extents, 0.5);
+ float inner_radius = max(0.5 - edge_width, 0.0);
+ float inner = square_box_coverage(barycentric, footprint_half_extents, inner_radius);
+ float edge = outer - inner;
-struct AperiodicTileSample {
- float distance_to_edge;
- float2 barycentric;
- uint face_id;
-};
+ color_sum += face_color * inner + _Aperiodic_Tiling_Edge_Color.rgb * edge;
+ outer_sum += outer;
-AperiodicTileSample sample_lattice(
- float4 p03, float p44, float4 a03, float a44, float4 b03, float b44) {
+#if defined(_APERIODIC_TILING_NORMALS)
+ float3 tile_normal = aperiodic_tiling_normal(barycentric);
+ normal_xy_sum += tile_normal.xy * outer;
+#endif
+}
+
+void accumulate_filtered_lattice(
+ float4 p03, float p44, float2 uv_ddx, float2 uv_ddy,
+ float4 a03, float a44, float4 b03, float b44, float edge_width, float3 face_color,
+ inout float3 color_sum, inout float outer_sum, inout float2 normal_xy_sum) {
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);
- 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(
+ float2 dbdx = mul(m, uv_ddx);
+ float2 dbdy = mul(m, uv_ddy);
+ float2 footprint_half_extents = 0.5 * (abs(dbdx) + abs(dbdy));
+
+ accumulate_filtered_candidate(
+ tile5_barycentric(p03, p44, m, r + s.xx, a03, a44, b03, b44),
+ footprint_half_extents, edge_width, face_color, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_candidate(
tile5_barycentric(p03, p44, m, r + s.xy, a03, a44, b03, b44),
- distance_to_edge, best_barycentric);
- choose_aperiodic_candidate(
+ footprint_half_extents, edge_width, face_color, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_candidate(
tile5_barycentric(p03, p44, m, r + s.yx, a03, a44, b03, b44),
- distance_to_edge, best_barycentric);
- choose_aperiodic_candidate(
+ footprint_half_extents, edge_width, face_color, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_candidate(
tile5_barycentric(p03, p44, m, r + s.yy, a03, a44, b03, b44),
- distance_to_edge, best_barycentric);
-
- AperiodicTileSample sample;
- sample.distance_to_edge = distance_to_edge;
- sample.barycentric = best_barycentric;
- return sample;
-}
-
-void accumulate_best(AperiodicTileSample candidate, uint face_id,
- inout AperiodicTileSample best) {
- bool better = (candidate.distance_to_edge > best.distance_to_edge);
- best.distance_to_edge = better ? candidate.distance_to_edge : best.distance_to_edge;
- best.barycentric = better ? candidate.barycentric : best.barycentric;
- best.face_id = better ? face_id : best.face_id;
+ footprint_half_extents, edge_width, face_color, color_sum, outer_sum, normal_xy_sum);
}
-void sample_aperiodic_tiling(float2 uv, out float3 albedo
- , out float3 tiling_normal_tangent
- ) {
+void sample_aperiodic_tiling(float2 uv, inout 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 uv_ddx = ddx(uv);
+ float2 uv_ddy = ddy(uv);
float2 u = float2(0, 1);
- // Accumulate best sample across all 10 face orientations = C(5,2) pairs
- AperiodicTileSample best;
- best.distance_to_edge = -1e10;
- best.barycentric = 0;
- best.face_id = 0;
-
- accumulate_best(sample_lattice(p03, p44, u.yxxx, u.x, u.xyxx, u.x), 0, best);
- accumulate_best(sample_lattice(p03, p44, u.yxxx, u.x, u.xxyx, u.x), 1, best);
- accumulate_best(sample_lattice(p03, p44, u.yxxx, u.x, u.xxxy, u.x), 2, best);
- accumulate_best(sample_lattice(p03, p44, u.yxxx, u.x, u.xxxx, u.y), 3, best);
- accumulate_best(sample_lattice(p03, p44, u.xyxx, u.x, u.xxyx, u.x), 4, best);
- accumulate_best(sample_lattice(p03, p44, u.xyxx, u.x, u.xxxy, u.x), 5, best);
- accumulate_best(sample_lattice(p03, p44, u.xyxx, u.x, u.xxxx, u.y), 6, best);
- accumulate_best(sample_lattice(p03, p44, u.xxyx, u.x, u.xxxy, u.x), 7, best);
- accumulate_best(sample_lattice(p03, p44, u.xxyx, u.x, u.xxxx, u.y), 8, best);
- accumulate_best(sample_lattice(p03, p44, u.xxxy, u.x, u.xxxx, u.y), 9, best);
-
- // Compute edge coverage from distance
- float edge_width = saturate(_Aperiodic_Tiling_Edge_Thickness * 2.0) * 0.5;
- float edge_sd = best.distance_to_edge - edge_width;
- float edge_sd_aa = max(abs(fwidth(edge_sd)), 1e-4);
- float edge_mask = smoothstep(-edge_sd_aa * 0.5, edge_sd_aa * 0.5, edge_sd);
-
- // Select face color and composite
- float3 face_colors[10];
- face_colors[0] = _Aperiodic_Tiling_Color_0.rgb;
- face_colors[1] = _Aperiodic_Tiling_Color_1.rgb;
- face_colors[2] = _Aperiodic_Tiling_Color_2.rgb;
- face_colors[3] = _Aperiodic_Tiling_Color_3.rgb;
- face_colors[4] = _Aperiodic_Tiling_Color_4.rgb;
- face_colors[5] = _Aperiodic_Tiling_Color_5.rgb;
- face_colors[6] = _Aperiodic_Tiling_Color_6.rgb;
- face_colors[7] = _Aperiodic_Tiling_Color_7.rgb;
- face_colors[8] = _Aperiodic_Tiling_Color_8.rgb;
- face_colors[9] = _Aperiodic_Tiling_Color_9.rgb;
-
- float3 edge = _Aperiodic_Tiling_Edge_Color.rgb;
- albedo = lerp(edge, face_colors[best.face_id], edge_mask);
+ // Analytically filter the existing local tile set in each orientation's
+ // barycentric space using a separable box footprint.
+ float edge_width = min(_Aperiodic_Tiling_Edge_Thickness, 0.5);
+ float3 color_sum = 0.0;
+ float outer_sum = 0.0;
+ float2 normal_xy_sum = 0.0;
+
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.yxxx, u.x, u.xyxx, u.x, edge_width,
+ _Aperiodic_Tiling_Color_0.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.yxxx, u.x, u.xxyx, u.x, edge_width,
+ _Aperiodic_Tiling_Color_1.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.yxxx, u.x, u.xxxy, u.x, edge_width,
+ _Aperiodic_Tiling_Color_2.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.yxxx, u.x, u.xxxx, u.y, edge_width,
+ _Aperiodic_Tiling_Color_3.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.xyxx, u.x, u.xxyx, u.x, edge_width,
+ _Aperiodic_Tiling_Color_4.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.xyxx, u.x, u.xxxy, u.x, edge_width,
+ _Aperiodic_Tiling_Color_5.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.xyxx, u.x, u.xxxx, u.y, edge_width,
+ _Aperiodic_Tiling_Color_6.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.xxyx, u.x, u.xxxy, u.x, edge_width,
+ _Aperiodic_Tiling_Color_7.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.xxyx, u.x, u.xxxx, u.y, edge_width,
+ _Aperiodic_Tiling_Color_8.rgb, color_sum, outer_sum, normal_xy_sum);
+ accumulate_filtered_lattice(
+ p03, p44, uv_ddx, uv_ddy, u.xxxy, u.x, u.xxxx, u.y, edge_width,
+ _Aperiodic_Tiling_Color_9.rgb, color_sum, outer_sum, normal_xy_sum);
+
+ float normalization = max(outer_sum, 1e-4);
+ albedo *= color_sum / normalization;
#if defined(_APERIODIC_TILING_NORMALS)
- float3 tile_normal = aperiodic_tiling_normal(best.barycentric);
- tiling_normal_tangent = normalize(float3(tile_normal.xy * edge_mask, 1.0));
+ tiling_normal_tangent = normalize(float3(normal_xy_sum / normalization, 1.0));
#else
tiling_normal_tangent = 0;
#endif
@@ -178,11 +187,9 @@ void apply_aperiodic_tiling(float2 uv, inout float3 albedo, inout float3 normal_
#if defined(_APERIODIC_TILING)
uv *= _Aperiodic_Tiling_Scale;
float3 tiling_normal_tangent;
- sample_aperiodic_tiling(uv, albedo
- , tiling_normal_tangent
- );
+ sample_aperiodic_tiling(uv, albedo, tiling_normal_tangent);
#if defined(_APERIODIC_TILING_NORMALS)
- normal_tangent = blendNormalsHill12(normal_tangent, tiling_normal_tangent);
+ normal_tangent = tiling_normal_tangent;
#endif
#endif // _APERIODIC_TILING
}