Noise-Extras
Noise-Extras copied to clipboard
Need help with tileable GLSL impementation
I've been trying to make OpenSimplex2 tileable in GLSL, so far, only the base function works, and it still seems off
// Inspired by Stefan Gustavson's noise
vec4 permute(vec4 t) {
return t * (t * 34.0 + 133.0);
}
// Gradient set is a normalized expanded rhombic dodecahedron
vec3 grad(float hash) {
// Random vertex of a cube, +/- 1 each
vec3 cube = mod(floor(hash / vec3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;
// Random edge of the three edges connected to that vertex
// Also a cuboctahedral vertex
// And corresponds to the face of its dual, the rhombic dodecahedron
vec3 cuboct = cube;
cuboct[int(hash / 16.0)] = 0.0;
// In a funky way, pick one of the four points on the rhombic face
float type = mod(floor(hash / 8.0), 2.0);
vec3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));
// Expand it so that the new edges are the same length
// as the existing ones
vec3 grad = cuboct * 1.22474487139 + rhomb;
// To make all gradients the same length, we only need to shorten the
// second type of vector. We also put in the whole noise scale constant.
// The compiler should reduce it into the existing floats. I think.
grad *= (1.0 - 0.042942436724648037 * type) * 32.80201376986577;
return grad;
}
vec3 wrap_dist(vec3 dist, vec3 limit) {
vec3 ad = abs(dist);
return sign(dist) * min(ad, limit - ad);
}
vec3 wrap(vec3 dist, vec3 limit) {
vec3 m = mod(dist, limit);
vec3 sign = sign(m);
vec3 is_negative = sign * -0.5 + 0.5;
is_negative *= abs(sign);
return m + is_negative * limit;
}
// BCC lattice split up into 2 cube lattices
vec4 open_simplex2_tileable_base(vec3 X, vec3 frequency, vec3 limit) {
X = wrap(X, limit);
X *= frequency;
limit *= frequency;
// First half-lattice, closest edge
vec3 v1 = wrap(round(X), limit);
vec3 dd1 = X - v1;
vec3 d1 = wrap_dist(dd1, limit);
vec3 score1 = abs(d1);
vec3 dir1 = step(max(score1.yzx, score1.zxy), score1);
vec3 v2 = wrap(v1 + dir1 * sign(dd1), limit);
vec3 d2 = wrap_dist(X - v2, limit);
// Second half-lattice, closest edge
vec3 X2 = wrap(X + 144.5, limit);
vec3 v3 = wrap(round(X2), limit);
vec3 dd3 = X2 - v3;
vec3 d3 = wrap_dist(dd3, limit);
vec3 score2 = abs(d3);
vec3 dir2 = step(max(score2.yzx, score2.zxy), score2);
vec3 v4 = wrap(v3 + dir2 * sign(dd3), limit);
vec3 d4 = wrap_dist(X2 - v4, limit);
// Gradient hashes for the four points, two from each half-lattice
vec4 hashes = permute(mod(vec4(v1.x, v2.x, v3.x, v4.x), 289.0));
hashes = permute(mod(hashes + vec4(v1.y, v2.y, v3.y, v4.y), 289.0));
hashes = mod(permute(mod(hashes + vec4(v1.z, v2.z, v3.z, v4.z), 289.0)), 48.0);
// Gradient extrapolations & kernel function
vec4 a = max(0.5 - vec4(dot(d1, d1), dot(d2, d2), dot(d3, d3), dot(d4, d4)), 0.0);
vec4 aa = a * a; vec4 aaaa = aa * aa;
vec3 g1 = grad(hashes.x); vec3 g2 = grad(hashes.y);
vec3 g3 = grad(hashes.z); vec3 g4 = grad(hashes.w);
vec4 extrapolations = vec4(dot(d1, g1), dot(d2, g2), dot(d3, g3), dot(d4, g4));
// Derivatives of the noise
vec3 derivative = -8.0 * mat4x3(d1, d2, d3, d4) * (aa * a * extrapolations)
+ mat4x3(g1, g2, g3, g4) * aaaa;
// Return it all as a vec4
return vec4(derivative, dot(aaaa, extrapolations));
}
// Use this if you don't want Z to look different from X and Y
vec4 open_simplex2_tileable_conventional(vec3 X, vec3 frequency, vec3 limit) {
// Rotate around the main diagonal. Not a skew transform.
vec4 result = open_simplex2_tileable_base(dot(X, vec3(2.0/3.0)) - X, frequency, limit);
return vec4(dot(result.xyz, vec3(2.0/3.0)) - result.xyz, result.w);
}
// Use this if you want to show X and Y in a plane, then use Z for time, vertical, etc.
vec4 open_simplex2_tileable_improve_xy(vec3 X, vec3 frequency, vec3 limit) {
// Rotate so Z points down the main diagonal. Not a skew transform.
const mat3 orthonormal_map = mat3(
0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626
);
vec4 result = open_simplex2_tileable_base(orthonormal_map * X, frequency, limit);
return vec4(result.xyz * orthonormal_map, result.w);
}
I'm sorry if this isn't the right place to post this