(Translated by https://www.hiragana.jp/)
nodes: add RenderNoise · NopeForge/nope.gl@9fbab3d · GitHub
Skip to content

Commit

Permalink
nodes: add RenderNoise
Browse files Browse the repository at this point in the history
  • Loading branch information
mbouron committed Sep 21, 2023
1 parent fc57e06 commit 9fbab3d
Show file tree
Hide file tree
Showing 17 changed files with 555 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Versioning](https://semver.org/spec/v2.0.0.html) for `libnopegl`.
- `GridLayout` node to make a grid out of a number of scenes
- `FilterColorMap` node to remap colors using a gradient of color points
- Animated GIF export in the viewer
- `RenderNoise` node to generate fractal noise on the GPU

### Fixed
- Viewer path management on Windows
Expand Down
9 changes: 9 additions & 0 deletions doc/_ext/nope/renders/noise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pynopegl_utils.misc import SceneCfg, scene

import pynopegl as ngl


@scene()
def noise(cfg: SceneCfg):
cfg.duration = 3
return ngl.RenderNoise(type="perlin", octaves=4, scale=cfg.aspect_ratio, evolution=ngl.Time())
5 changes: 5 additions & 0 deletions doc/usr/howto/renders.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ Render an image
Render a video
```

```{nope} renders.noise
:export_type: video
Render an animated fractal noise
```

## Render with custom shaders

It is also possible to create a custom shader using the [Render] node and get a
Expand Down
4 changes: 4 additions & 0 deletions libnopegl/meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#
# Copyright 2023 Nope Foundry
# Copyright 2020-2022 GoPro Inc.
#
# Licensed to the Apache Software Foundation (ASF) under one
Expand Down Expand Up @@ -667,6 +668,7 @@ shaders = {
'helper_linear2srgb.glsl': 'helper_linear2srgb_glsl.h',
'helper_srgb2linear.glsl': 'helper_srgb2linear_glsl.h',
'helper_misc_utils.glsl': 'helper_misc_utils_glsl.h',
'helper_noise.glsl': 'helper_noise_glsl.h',
'hwconv.frag': 'hwconv_frag.h',
'hwconv.vert': 'hwconv_vert.h',
'path.frag': 'path_frag.h',
Expand All @@ -681,6 +683,8 @@ shaders = {
'source_gradient4.vert': 'source_gradient4_vert.h',
'source_histogram.frag': 'source_histogram_frag.h',
'source_histogram.vert': 'source_histogram_vert.h',
'source_noise.frag': 'source_noise_frag.h',
'source_noise.vert': 'source_noise_vert.h',
'source_texture.frag': 'source_texture_frag.h',
'source_texture.vert': 'source_texture_vert.h',
'source_waveform.frag': 'source_waveform_frag.h',
Expand Down
94 changes: 94 additions & 0 deletions libnopegl/nodes.specs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,16 @@
"desc": "only the luma channel"
}
],
"noise_type": [
{
"name": "blocky",
"desc": "blocky noise"
},
{
"name": "perlin",
"desc": "perlin noise"
}
],
"scale_mode": [
{
"name": "auto",
Expand Down Expand Up @@ -2891,6 +2901,90 @@
}
]
},
"RenderNoise": {
"file": "src/node_renderother.c",
"params": [
{
"name": "type",
"type": "select",
"default": "blocky",
"choices": "noise_type",
"flags": [],
"desc": "noise type"
},
{
"name": "amplitude",
"type": "f32",
"default": 1.000000,
"flags": ["node"],
"desc": "by how much it oscillates"
},
{
"name": "octaves",
"type": "u32",
"default": 3,
"flags": [],
"desc": "number of accumulated noise layers (controls the level of details), must in [1;8]"
},
{
"name": "lacunarity",
"type": "f32",
"default": 2.000000,
"flags": ["node"],
"desc": "frequency multiplier per octave"
},
{
"name": "gain",
"type": "f32",
"default": 0.500000,
"flags": ["node"],
"desc": "amplitude multiplier per octave (also known as persistence)"
},
{
"name": "seed",
"type": "u32",
"default": 0,
"flags": ["node"],
"desc": "random base seed"
},
{
"name": "scale",
"type": "vec2",
"default": [32.000000,32.000000],
"flags": ["node"],
"desc": "size of the grid in lattice units"
},
{
"name": "evolution",
"type": "f32",
"default": 0.000000,
"flags": ["node"],
"desc": "evolution of the 3rd non-spatial dimension, time if unspecified"
},
{
"name": "blending",
"type": "select",
"default": "default",
"choices": "blend_preset",
"flags": [],
"desc": "define how this node and the current frame buffer are blending together"
},
{
"name": "geometry",
"type": "node",
"node_types": ["Circle", "Geometry", "Quad", "Triangle"],
"flags": [],
"desc": "geometry to be rasterized"
},
{
"name": "filters",
"type": "node_list",
"node_types": ["FilterAlpha", "FilterColorMap", "FilterContrast", "FilterExposure", "FilterInverseAlpha", "FilterLinear2sRGB", "FilterOpacity", "FilterPremult", "FilterSaturation", "FilterSRGB2Linear"],
"flags": [],
"desc": "filter chain to apply on top of this source"
}
]
},
"RenderPath": {
"file": "src/node_renderpath.c",
"params": [
Expand Down
4 changes: 4 additions & 0 deletions libnopegl/src/filterschain.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/*
* Copyright 2023 Matthieu Bouron <matthieu.bouron@gmail,com>
* Copyright 2023 Nope Foundry
* Copyright 2021-2022 GoPro Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one
Expand Down Expand Up @@ -28,6 +30,7 @@
/* Shader helpers */
#include "helper_linear2srgb_glsl.h"
#include "helper_misc_utils_glsl.h"
#include "helper_noise_glsl.h"
#include "helper_srgb2linear_glsl.h"

struct filterschain {
Expand Down Expand Up @@ -88,6 +91,7 @@ static const struct {
const char * const * code; // double dimension to avoid initializer not being a constant
} helpers_mask_code[] = {
{NGLI_FILTER_HELPER_MISC_UTILS, &helper_misc_utils_glsl},
{NGLI_FILTER_HELPER_NOISE, &helper_noise_glsl},
{NGLI_FILTER_HELPER_LINEAR2SRGB, &helper_linear2srgb_glsl},
{NGLI_FILTER_HELPER_SRGB2LINEAR, &helper_srgb2linear_glsl},
};
Expand Down
1 change: 1 addition & 0 deletions libnopegl/src/filterschain.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct filterschain;
#define NGLI_FILTER_HELPER_MISC_UTILS (1 << 0)
#define NGLI_FILTER_HELPER_SRGB2LINEAR (1 << 1)
#define NGLI_FILTER_HELPER_LINEAR2SRGB (1 << 2)
#define NGLI_FILTER_HELPER_NOISE (1 << 3)

struct filter {
const char *name;
Expand Down
172 changes: 172 additions & 0 deletions libnopegl/src/glsl/helper_noise.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Copyright 2023 Matthieu Bouron <matthieu.bouron@gmail.com>
* Copyright 2023 Clément Bœsch <u pkh.me>
* Copyright 2023 Nope Foundry
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/*
* Return a random single-precision float between [0;1)
* Derived from http://prng.di.unimi.it/
*/
highp float u32tof32(highp uint x)
{
uint y = (0x7FU << 23U) | (x >> 9U);
return uintBitsToFloat(y) - 1.0;
}

/*
* lowbias32 hashing from https://nullprogram.com/blog/2018/07/31/
*/
highp uint hash(highp uint x)
{
x ^= x >> 16;
x *= 0x7feb352dU;
x ^= x >> 15;
x *= 0x846ca68bU;
x ^= x >> 16;
return x;
}

highp uint hash(highp uvec2 x)
{
return hash(x.x ^ hash(x.y));
}

highp uint hash(highp uvec3 x)
{
return hash(x.x ^ hash(x.y ^ hash(x.z)));
}

highp float random(highp uvec3 x)
{
return u32tof32(hash(x));
}

highp vec2 random2(highp uvec3 x)
{
/* Generate 2 random floats in [0;1] using 16-bit of information for each */
uint h = hash(x);
float r0 = u32tof32(0x00010001U * (h & 0xffffU));
float r1 = u32tof32(0x00010001U * (h>>16 & 0xffffU));
return vec2(r0, r1);
}

/*
* Generate a random point on a sphere (with uniform distribution)
*
* References:
* - https://web.archive.org/web/20200618040237/https://mrl.nyu.edu/~perlin/paper445.pdf
* - https://web.archive.org/web/20180616011332/http://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds%20/perlin-noise-part-2
*/
highp vec3 random_grad(highp uvec3 x)
{
vec2 r = random2(x);
float theta = acos(2.0 * r.x - 1.0); // use the first random for the polar angle (latitude)
float phi = ngli_tau * r.y; // use the 2nd random for the azimuth (longitude)
return vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta));
}

highp vec3 curve_quintic(highp vec3 t)
{
return ((6. * t - 15.) * t + 10.) * t * t * t;
}

float noise_perlin(vec3 t, uint seed)
{
vec3 i = floor(t);
vec3 f = fract(t);
uvec3 x = uvec3(i) + seed;

float y0 = dot(random_grad(x + uvec3(0, 0, 0)), f - vec3(0, 0, 0));
float y1 = dot(random_grad(x + uvec3(1, 0, 0)), f - vec3(1, 0, 0));
float y2 = dot(random_grad(x + uvec3(0, 1, 0)), f - vec3(0, 1, 0));
float y3 = dot(random_grad(x + uvec3(1, 1, 0)), f - vec3(1, 1, 0));
float y4 = dot(random_grad(x + uvec3(0, 0, 1)), f - vec3(0, 0, 1));
float y5 = dot(random_grad(x + uvec3(1, 0, 1)), f - vec3(1, 0, 1));
float y6 = dot(random_grad(x + uvec3(0, 1, 1)), f - vec3(0, 1, 1));
float y7 = dot(random_grad(x + uvec3(1, 1, 1)), f - vec3(1, 1, 1));

vec3 a = curve_quintic(f);
return mix(mix(mix(y0, y1, a.x), mix(y2, y3, a.x), a.y),
mix(mix(y4, y5, a.x), mix(y6, y7, a.x), a.y),
a.z);
}

/* Adapted from https://en.wikipedia.org/wiki/Bicubic_interpolation */
float bicubic(float a, float b, float c, float d, float t)
{
mat4 m = 0.5 * mat4(
0., 2., 0., 0.,
-1., 0., 1., 0.,
2., -5., 4., -1.,
-1., 3., -3., 1.
);
return dot(m * vec4(1., t, t*t, t*t*t), vec4(a, b, c, d));
}

float noise_blocky(vec3 t, uint seed)
{
uvec2 xy = uvec2(t.xy) + seed;

/*
* For each lattice coordinates (x, y) we determine a random frequency and
* offset that will be used to compute the evolution. For that, we use the
* lattice coordinates (x, y) that we offset and a fixed seed as third
* dimension so the result is not correlated directly to (x, y) and to the
* temporal dimension (t.z). Offseting (x, y) also has the advantage to
* avoid the case where the evolution is derived from random2(uvec3(0, 0,
* 0)) which equals to 0.
*/
vec2 r = random2(uvec3(xy + 1U << 16, seed));
float evolution_freq = r.x;
float evolution_offset = r.y;

/* Apply frequency and offset to the third (temporal) dimension */
float evolution = t.z * evolution_freq + evolution_offset;
uint evolution_i = uint(evolution);
float evolution_f = fract(evolution);

float y0 = random(uvec3(xy, evolution_i - 1U));
float y1 = random(uvec3(xy, evolution_i + 0U));
float y2 = random(uvec3(xy, evolution_i + 1U));
float y3 = random(uvec3(xy, evolution_i + 2U));

float res = bicubic(y0, y1, y2, y3, evolution_f);

/* Scale noise from the [0;1] range to [-1;1] */
return res * 2.0 - 1.0;
}

float fbm(vec3 xyz, int type, float amplitude, uint octaves, float lacunarity, float gain, uint seed)
{
float sum = 0.0;
float amp = amplitude;

for(uint i = 0U; i < octaves; i++) {
if (type == 0)
sum += amp * noise_blocky(xyz, seed);
else
sum += amp * noise_perlin(xyz, seed);
xyz *= lacunarity;
amp *= gain;
}

return sum;
}
29 changes: 29 additions & 0 deletions libnopegl/src/glsl/source_noise.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2023 Matthieu Bouron <matthieu.bouron@gmail.com>
* Copyright 2023 Nope Foundry
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

vec4 source_noise()
{
vec2 st = uv * scale;
vec3 noise = vec3(fbm(vec3(st, evolution), type, amplitude, octaves, lacunarity, gain, seed));
noise = (noise + 1.0) / 2.0;
return vec4(noise, 1.0);
}
Loading

0 comments on commit 9fbab3d

Please sign in to comment.