Skip to content

Commit efc63ac

Browse files
committed
Support cylindrical and spherical !noise
1 parent 3d99ebe commit efc63ac

File tree

3 files changed

+56
-12
lines changed

3 files changed

+56
-12
lines changed

docs/shaders.md

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -554,9 +554,28 @@ with the `border` and `repeat` attributes as described above for
554554

555555
### `!noise`
556556

557-
The `!noise` node is primarily an image generator that generates 2D slices
558-
through [OpenSimplex 2S](https://github.com/KdotJPG/OpenSimplex2) 3D ("improved
559-
XY") noise. It is controlled with the following attributes:
557+
The `!noise` node is primarily an image generator that generates slices through
558+
[OpenSimplex 2S](https://github.com/KdotJPG/OpenSimplex2) 3D ("improved XY")
559+
noise. The shape of the slice is controlled with the `shape` attribute, as
560+
follows:
561+
562+
`shape=:plane` (the default)
563+
: The image is constructed from an XY plane of the 'ImproveXY' variant of the
564+
OpenSimplex 2S noise function.
565+
566+
`shape=:cylinder`
567+
: The image is constructed from a cylinder aligned along the Z axis of the
568+
conventional OpenSimplex 2S noise function. This will result in an evenly
569+
distributed noise image that seamlessly wraps on the left and right edges.
570+
571+
`shape=:sphere`
572+
: The image is constructed from a sphere aligned with its poles along the Z
573+
axis of the conventional noise function. The image will appear distorted at the
574+
top and bottom edges, but will seamlessly texture-map onto a shape using
575+
Equirectangular UV coordinates.
576+
577+
All of these noise shapes support the following additional attributes for
578+
controlling the noise function:
560579

561580
`seed=` *SEED*
562581
: `!noise` generates reproducible output with the same input values. Supply a
@@ -580,11 +599,15 @@ passed into the noise function, default `1`.
580599

581600
`origin=` *X*`;`*Y*
582601
: Specifies an offset for the *pre-scaled* X and Y input values, default `0`.
583-
The pre-scaled X and Y coordinates are in pixels from the top left.
584602

585603
`z=` *Z*
586-
: Specifies a *pre-scaled* Z coordinate for the plane to be calculated,
587-
default `0`.
604+
: Specifies an offset for the *pre-scaled* Z input value, default `0`.
605+
606+
:::{note}
607+
The `origin` and `z` attributes are designed primarily for animating the default
608+
`shape=:plane` noise form. Results will be more complicated for cylindrical
609+
and spherical noise.
610+
:::
588611

589612
`multiplier=` *MULTIPLIER*
590613
: Specifies a multiplier for the final noise value, default `0.5`.

src/flitter/render/window/glsl/noise.frag

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,35 @@ uniform sampler2D ${name};
2525
<%include file="noise_functions.glsl"/>
2626

2727

28+
const float Pi = 3.141592653589793115997963468544185161590576171875;
29+
const float Tau = 6.283185307179586231995926937088370323181152343750;
30+
31+
2832
void main() {
33+
% if noise_shape == 'cylinder':
34+
float th = Tau * coord.x;
35+
float r = size.x / Tau;
36+
vec3 point = vec3(vec2(cos(th), sin(th))*r, coord.y*size.y);
37+
% elif noise_shape == 'sphere':
38+
float th = Tau * coord.x;
39+
float r = size.x / Tau;
40+
float lat = Pi * (coord.y - 0.5);
41+
vec3 point = vec3(vec2(cos(th), sin(th))*cos(lat)*r, sin(lat)*r);
42+
% else:
43+
vec3 point = vec3(coord*size, 0);
44+
% endif
45+
point += vec3(origin, z);
2946
% if child_textures:
3047
% for name in child_textures:
3148
% if loop.index == 0:
32-
vec4 c = texture(${name}, coord);
49+
vec4 s = texture(${name}, coord);
3350
% else:
34-
c = composite_${composite}(texture(${name}, coord), c);
51+
s = composite_${composite}(texture(${name}, coord), s);
3552
% endif
3653
% endfor
37-
% else:
38-
vec4 c = vec4(0.0);
54+
point += s * tscale;
3955
% endif
40-
vec3 point = (vec3(coord*size + origin, z) + c.xyz*tscale) * scale;
56+
point *= scale;
4157
mat4 hashes;
4258
hashes[0] = vec4(seed_hash);
4359
hashes[1] = opensimplex2s_permute(hashes[0] + 1.0);
@@ -50,7 +66,11 @@ void main() {
5066
vec3 p = point / k;
5167
vec4 c = vec4(0.0);
5268
for (int j = 0; j < components; j++) {
69+
% if noise_shape in ('cylinder', 'sphere'):
70+
c[j] = opensimplex2s(hashes[j], p);
71+
% else:
5372
c[j] = opensimplex2s_improvexy(hashes[j], p);
73+
% endif
5474
}
5575
sum += c * k;
5676
weight += k;

src/flitter/render/window/shaders.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ class Noise(Shader):
137137
DEFAULT_FRAGMENT_SOURCE = TemplateLoader.get_template('noise.frag')
138138

139139
def render(self, node, references, **kwargs):
140+
noise_shape = node.get('shape', 1, str, 'plane').lower()
140141
seed_hash = hash(node['seed'] if 'seed' in node else null) / (1 << 48)
141142
default_values = node.get('default', 4, float, (1, 1, 1, 1))
142-
super().render(node, references, seed_hash=seed_hash, components=1, octaves=1, roughness=0.5, origin=0, z=0,
143+
super().render(node, references, noise_shape=noise_shape, seed_hash=seed_hash, components=1, octaves=1, roughness=0.5, origin=0, z=0,
143144
scale=1, tscale=1, multiplier=0.5, offset=0.5, default_values=default_values, **kwargs)

0 commit comments

Comments
 (0)