Skip to content

Instantly share code, notes, and snippets.

@williamchange
Last active February 21, 2023 15:51
Show Gist options
  • Save williamchange/f6b2630dac9d0be5935a520e41555d17 to your computer and use it in GitHub Desktop.
Save williamchange/f6b2630dac9d0be5935a520e41555d17 to your computer and use it in GitHub Desktop.
Triangle Voronoi Borders HLSL UE (Custom Node)
// Based on "Triangle Voronoi Borders" by Thomas Hooper (@tdhooper)
// https://www.shadertoy.com/view/ss3fW4
struct Functions
{
float3 sdTriEdges(float2 p) {
return float3(
dot(p, float2(0.,-1.)),
dot(p, float2(.866025, .5)),
dot(p, float2(-.866025, .5))
);
}
float sdTri(float2 p) {
float3 t = sdTriEdges(p);
return max(t.x, max(t.y, t.z));
}
float3 primaryAxis(float3 p) {
float3 a = abs(p);
return (1.-step(a.xyz, a.yzx))*step(a.zxy, a.xyz)*sign(p);
}
float3 sdgBorder(float2 pt1, float2 pt2) {
float3 tbRel = sdTriEdges(pt2 - pt1);
float3 axis = primaryAxis(tbRel);
float2 gA = float2(0,-1);
float2 gB = float2(.866025, .5);
float2 gC = float2(-.866025, .5);
float2 norA = gC * axis.x + gA * axis.y + gB * axis.z;
float2 norB = gB * -axis.x + gC * -axis.y + gA * -axis.z;
float2 dir = gA * axis.x + gB * axis.y + gC * axis.z;
float2 corner = dir * dot(dir, pt1 - pt2) * 2./3.;
float2x2 r90 = {0,-1,1,0};
bool isEdge = axis.x + axis.y + axis.z < 0.;
if (isEdge) {
corner = pt2 + corner;
float2 ca = corner + min(0., dot(corner, -norA)) * norA;
float2 cb = corner + max(0., dot(corner, -norB)) * norB;
float side = step(dot(corner, mul(r90,dir)), 0.);
corner = lerp(cb, ca, side);
} else {
corner = pt1 - corner;
float2 ca = corner + max(0., dot(corner, -norA)) * norA;
float2 cb = corner + min(0., dot(corner, -norB)) * norB;
float side = step(dot(corner, mul(r90,dir)), 0.);
corner = lerp(ca, cb, side);
}
float2 nor = normalize(corner);
float d = length(corner);
return float3(abs(d), nor);
}
float2 hash2(float2 p)
{
return frac(sin(float2(dot(p,float2(127.1,311.7)),dot(p,float2(269.5,183.3))))*43758.5453);
}
float2 cellPoint(float2 n, float2 f, float2 cell, float offset) {
float2 coord = n + cell;
float2 o = hash2( n + cell );
o = 0.5 + 0.5*sin( offset * 6.2831 + 6.2831 * o );
float2 pt = cell + o - f;
return pt;
}
float3x3 voronoi(float2 x, float offset)
{
float2 n = floor(x);
float2 f = frac(x);
//----------------------------------
// first pass: regular voronoi
//----------------------------------
float2 closestCell, closestPoint, id, nor;
const int reach = 2;
float closestDist = 8.0;
for( int j = -reach; j <= reach; j++ )
for( int i = -reach; i <= reach; i++ )
{
float2 cell = float2(i, j);
float2 pt = cellPoint(n, f, cell,offset);
float dist = sdTri(pt);
if( dist < closestDist )
{
closestDist = dist;
closestPoint = pt;
closestCell = cell;
id = cell + n;
}
}
//----------------------------------
// second pass: distance to borders
//----------------------------------
closestDist = 8.0;
for( int j = -reach-1; j <= reach+1; j++ )
for( int i = -reach-1; i <= reach+1; i++ )
{
float2 cell = closestCell + float2(i, j);
float2 pt = cellPoint(n, f, cell,offset);
float dist = sdTri(closestPoint - pt);
if( dist > 0.0001 ) {
float3 sdg = sdgBorder(closestPoint, pt);
if (sdg.x < closestDist) {
closestDist = sdg.x;
nor = sdg.yz;
}
}
}
return float3x3( closestDist, closestPoint, id, nor, 0, 0);
}
float3x3 Out(float2 p, float offset) { return voronoi(p,offset); }
};
Functions f;
float3x3 vor = f.Out(uv,offset);
id = vor[1].xy;
nor = float2(vor[1].z, vor[2].x);
return vor[0].xyz;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment