diff options
| author | yum <yum.food.vr@gmail.com> | 2026-04-10 18:40:47 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-04-10 18:40:47 -0700 |
| commit | f2ceb26af143f2e929e4f23ccb1fc86fa9e5307b (patch) | |
| tree | a4b391469ab805a8361a28c74b9daa24a85dbe69 /aperiodic_tiling.cginc | |
| parent | 283b8f253cff4a0e39005ba675d7c2cd7ef3c123 (diff) | |
aperiodic: let user specify colors, add normals
Diffstat (limited to 'aperiodic_tiling.cginc')
| -rw-r--r-- | aperiodic_tiling.cginc | 140 |
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 } |
