Skip to content

Commit

Permalink
Some tweaks to !noise
Browse files Browse the repository at this point in the history
In particular, breaking out the OpenSimplex 2S functions into an include 
file that can be re-used.
  • Loading branch information
jonathanhogg committed Nov 13, 2024
1 parent 1650ca7 commit 9ee409e
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 55 deletions.
11 changes: 8 additions & 3 deletions docs/shaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,7 @@ to the null vector if not supplied.

`components=` *1..4*
: Specify how many distinct noise planes to create, default `1`. Each will
be assigned to one channel of the output image (in the order R, G, B, A). The
unused channels will be set to `1`.
be assigned to one channel of the output image (in the order R, G, B, A).

`octaves=` *OCTAVES*
: Specify how many octaves of noise to generate, default `1`.
Expand Down Expand Up @@ -554,7 +553,13 @@ default `0`.
: Specifies an offset to be added to the multiplied noise value before writing
to the output image, default `0.5`.

Noise values are normally in the range $(-1,1)$. The default values for
`default=` *DEFAULTS*
: Specifies the default values of the color channels as a 4-vector (in the
order R, G, B, A). These will be used for any channels not filled-in with noise
values (see the `components=` attribute above). The default value is `1`,
meaning all unused channels will have the value `1`.

OpenSimplex 2S noise values are in the range $(-1,1)$. The default values for
`multiplier` and `offset` are designed to adjust the noise range into the
standard $(0,1)$ range for color values. However, with an HDR image format
(i.e., the default `colorbits=16`) there is no particular need to restrict the
Expand Down
4 changes: 2 additions & 2 deletions examples/textures.fl
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ let SIZE=1920;1080
days=(beat+25)/60

!offscreen
!adjust id=:stars size=2048;1024 exposure=1 highlights=4 composite=:multiply
!adjust id=:stars size=2048;1024 exposure=2 highlights=4 composite=:multiply
!image filename='assets/stars.jpg'
!noise scale=0.02 z=beat*100 components=1
!noise scale=0.02 z=beat*10 components=1 default=0.5;0.5;0.5;1
!adjust id=:earth size=2048;1024 exposure=1 shadows=2
!image filename='assets/earth.jpg'
!adjust id=:earth_night size=2048;1024 exposure=1
Expand Down
Binary file modified examples/textures.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 9 additions & 49 deletions src/flitter/render/window/glsl/noise.frag
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
${HEADER}

// This OpenSimplex 2S (3D ImproveXY) implementation is largely lifted from
// Kurt Spencer's original (which has been placed into the public domain):
// https://github.com/KdotJPG/OpenSimplex2/blob/master/glsl/OpenSimplex2S.glsl

in vec2 coord;
out vec4 color;

Expand All @@ -18,53 +14,17 @@ uniform vec3 scale;
uniform vec3 tscale;
uniform float offset;
uniform float multiplier;
uniform vec4 default_values;
uniform float alpha;
% for name in child_textures:
uniform sampler2D ${name};
% endfor


<%include file="composite_functions.glsl"/>
<%include file="noise_functions.glsl"/>


const mat3 orthonormalMap = mat3(0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626);

vec4 permute(vec4 t) {
t = mod(t, 289.0);
return t * (t * 34.0 + 133.0);
}

vec3 grad(float hash) {
vec3 cube = mod(floor(hash / vec3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;
vec3 cuboct = cube;
cuboct[int(hash / 16.0)] = 0.0;
float type = mod(floor(hash / 8.0), 2.0);
vec3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));
vec3 grad = cuboct * 1.22474487139 + rhomb;
return grad * (1.0 - 0.042942436724648037 * type) * 3.5946317686139184;
}

float openSimplex2SDerivativesPart(vec4 hashes, vec3 X) {
vec3 b = floor(X);
vec4 i4 = vec4(X - b, 2.5);
vec3 v1 = b + floor(dot(i4, vec4(.25)));
vec3 v2 = b + vec3(1.0, 0.0, 0.0) + vec3(-1.0, 1.0, 1.0) * floor(dot(i4, vec4(-.25, .25, .25, .35)));
vec3 v3 = b + vec3(0.0, 1.0, 0.0) + vec3(1.0, -1.0, 1.0) * floor(dot(i4, vec4(.25, -.25, .25, .35)));
vec3 v4 = b + vec3(0.0, 0.0, 1.0) + vec3(1.0, 1.0, -1.0) * floor(dot(i4, vec4(.25, .25, -.25, .35)));
hashes = permute(hashes + vec4(v1.x, v2.x, v3.x, v4.x));
hashes = permute(hashes + vec4(v1.y, v2.y, v3.y, v4.y));
hashes = mod(permute(hashes + vec4(v1.z, v2.z, v3.z, v4.z)), 48.0);
vec3 d1 = X - v1; vec3 d2 = X - v2; vec3 d3 = X - v3; vec3 d4 = X - v4;
vec4 a = max(0.75 - 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));
return dot(aaaa, extrapolations);
}

void main() {
% if child_textures:
% for name in child_textures:
Expand All @@ -79,18 +39,18 @@ void main() {
% endif
vec3 point = (vec3(coord*size + origin, z) + c.xyz*tscale) * scale;
mat4 hashes;
hashes[0] = permute(vec4(seed_hash));
hashes[1] = permute(hashes[0] + 1.0);
hashes[2] = permute(hashes[1] + 1.0);
hashes[3] = permute(hashes[2] + 1.0);
hashes[0] = vec4(seed_hash);
hashes[1] = opensimplex2s_permute(hashes[0] + 1.0);
hashes[2] = opensimplex2s_permute(hashes[1] + 1.0);
hashes[3] = opensimplex2s_permute(hashes[2] + 1.0);
vec4 sum = vec4(0.0);
float k = 1.0;
float weight = 0.0;
for (int i = 0; i < octaves; i++) {
vec3 p = orthonormalMap * point / k;
vec4 c = vec4(1.0);
vec3 p = point / k;
vec4 c = default_values;
for (int j = 0; j < components; j++) {
float result = openSimplex2SDerivativesPart(hashes[j], p) + openSimplex2SDerivativesPart(hashes[j], p + 144.5);
float result = opensimplex2s_improvexy(hashes[j], p);
c[j] = result * multiplier;
}
sum += c;
Expand Down
61 changes: 61 additions & 0 deletions src/flitter/render/window/glsl/noise_functions.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

// This OpenSimplex 2S (3D ImprovepY) implementation is lifted from
// Kurt Spencer's original (which has been placed into the public domain):
// https://github.com/KdotJPG/OpenSimplex2/blob/master/glsl/OpenSimplex2S.glsl
//
// Other than some renaming and reformatting, the main change is to allow a
// seed hash to be passed in.

const mat3 opensimplex2s_orthonormal_map = mat3(0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626);

vec4 opensimplex2s_permute(vec4 t) {
t = mod(t, 289.0);
return t * (t * 34.0 + 133.0);
}

vec3 opensimplex2s_grad(float hash) {
vec3 cube = mod(floor(hash / vec3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;
vec3 cuboct = cube;
cuboct[int(hash / 16.0)] = 0.0;
float type = mod(floor(hash / 8.0), 2.0);
vec3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));
vec3 grad = cuboct * 1.22474487139 + rhomb;
return grad * (1.0 - 0.042942436724648037 * type) * 3.5946317686139184;
}

float opensimplex2s_derivatives(vec4 seed_hashes, vec3 p) {
vec3 b = floor(p);
vec4 i4 = vec4(p - b, 2.5);
vec3 v1 = b + floor(dot(i4, vec4(.25)));
vec3 v2 = b + vec3(1.0, 0.0, 0.0) + vec3(-1.0, 1.0, 1.0) * floor(dot(i4, vec4(-.25, .25, .25, .35)));
vec3 v3 = b + vec3(0.0, 1.0, 0.0) + vec3(1.0, -1.0, 1.0) * floor(dot(i4, vec4(.25, -.25, .25, .35)));
vec3 v4 = b + vec3(0.0, 0.0, 1.0) + vec3(1.0, 1.0, -1.0) * floor(dot(i4, vec4(.25, .25, -.25, .35)));
vec4 hashes = opensimplex2s_permute(seed_hashes + vec4(v1.x, v2.x, v3.x, v4.x));
hashes = opensimplex2s_permute(hashes + vec4(v1.y, v2.y, v3.y, v4.y));
hashes = mod(opensimplex2s_permute(hashes + vec4(v1.z, v2.z, v3.z, v4.z)), 48.0);
vec3 d1 = p - v1;
vec3 d2 = p - v2;
vec3 d3 = p - v3;
vec3 d4 = p - v4;
vec4 a = max(0.75 - 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 = opensimplex2s_grad(hashes.x);
vec3 g2 = opensimplex2s_grad(hashes.y);
vec3 g3 = opensimplex2s_grad(hashes.z);
vec3 g4 = opensimplex2s_grad(hashes.w);
vec4 extrapolations = vec4(dot(d1, g1), dot(d2, g2), dot(d3, g3), dot(d4, g4));
return dot(aaaa, extrapolations);
}

float opensimplex2s(vec4 seed_hashes, vec3 p) {
p = dot(p, vec3(2.0/3.0)) - p;
return opensimplex2s_derivatives(seed_hashes, p) + opensimplex2s_derivatives(seed_hashes, p + 144.5);
}

float opensimplex2s_improvexy(vec4 seed_hashes, vec3 p) {
p = opensimplex2s_orthonormal_map * p;
return opensimplex2s_derivatives(seed_hashes, p) + opensimplex2s_derivatives(seed_hashes, p + 144.5);
}
3 changes: 2 additions & 1 deletion src/flitter/render/window/shaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,6 @@ class Noise(Shader):

def render(self, node, references, **kwargs):
seed_hash = hash(node['seed'] if 'seed' in node else null) / (1 << 48)
default_values = node.get('default', 4, float, (1, 1, 1, 1))
super().render(node, references, seed_hash=seed_hash, components=1, octaves=1, roughness=0.5, origin=0, z=0,
scale=1, tscale=1, multiplier=0.5, offset=0.5, **kwargs)
scale=1, tscale=1, multiplier=0.5, offset=0.5, default_values=default_values, **kwargs)

0 comments on commit 9ee409e

Please sign in to comment.