【问题标题】:What is the math behind the SVG <feTurbulence> filter?SVG <feTurbulence> 过滤器背后的数学原理是什么?
【发布时间】:2021-09-21 14:45:26
【问题描述】:

我目前正在编写一个简单的 SVG 解释器(当然不是详尽无遗,这将非常复杂),我发现自己正在努力使用 过滤器。

基本上,可能会产生两种类型的噪音:

  • fractalNoise 实际上很容易生成,因为可以使用原始的 Perlin 噪声生成器(例如,可以在 here 找到示例代码)。
  • turbulence 是默认过滤器,起初我认为唯一重要的因素是噪声是无散度的,所以我尝试将∇ xf 应用于只有 z 分量非null,以获得无散度的 2D 随机向量场(因为 ∇.(∇ xf) = 0)。问题是产生的噪音看起来不像它应该的那样。

这是 chrome 使用 fractalNoise 和 turbulence 生成的(来自here):

The images generated by chrome

以下是我用上面描述的数学可以产生的噪音:

My fractal noise

My first try at turbulent noise

这里有很多问题。首先:在 SVG 解释器产生的噪音中,我不确定我是否理解颜色代表什么。分形噪声似乎比我的“更亮”,尽管它们都具有相同的“质量”(我的在所有颜色通道上从 0 变为 1)。

至于湍流噪声,生成 2D 场意味着我只有 2 个组件可以使用,而不是 3 个,但最重要的是,我确信这不是实际湍流噪声的生成方式。有谁知道这个噪声发生器的数学原理是什么?

谢谢!

【问题讨论】:

  • 您可能会遇到色彩空间问题。 SVG 过滤器的默认颜色空间是线性 RGB - 与 sRGB 颜色空间不同 - 在 CSS 中的其他任何地方都使用它。如果您将“color-interpolation-filters=sRGB”添加到您的过滤器元素,您可能会得到符合您期望的东西。可以在这里找到确切的数学:w3.org/TR/SVG11/filters.html#feTurbulenceElement
  • 嗨!非常感谢 !我正在编写的解释器实际上是在 OpenGL / GLSL 中,我正在使用片段着色器来生成噪声图像。所有的数学都是在线性色彩空间中完成的,并且只在最后执行到 sRGB 的转换,所以色彩空间应该不是问题……至于代码,非常感谢,我会检查一下:)
  • 好的,所以我阅读了代码,如果我不考虑拼接部分(这实际上可能是真正重要的部分),它看起来像 湍流函数实际上只是八度噪声。这几乎是我已经用 GLSL 编写的代码。 turbulence feTurbulence 类型只是对八度音阶 Perlin 噪声的简单修改(例如采用绝对值)?我将在原始问题的答案中发布我的 GLSL 代码。
  • Chromium lib for perlin 噪音如果有帮助的话:source.chromium.org/chromium/chromium/src/+/main:third_party/… /** 它们不是两种完全不同的噪音。输出看起来不同,但是一旦在 [1, -1] 范围内生成噪声,通过执行以下操作将输出带回 [0, 1] 范围: * kFractalNoise_Type : noise * 0.5 + 0.5 * kTurbulence_Type : abs(噪音)*/
  • 哦哦谢谢!所以这就是我所理解的,它现在似乎可以工作了:) 非常感谢

标签: math svg random noise svg-filters


【解决方案1】:

为了完整起见,这里是我用来生成八度音阶 Perlin 噪声的 GLSL 代码(从 rosettacode 修改,并且尚未进行标准化/参数化):

uniform float time;

mat3 rotation(float angle, vec3 axis){
    float c = cos(angle);
    float s = sin(angle);

    float t = 1 - c;
    float x = axis.x;
    float y = axis.y;
    float z = axis.z;

    return mat3(
        vec3(t * x * x + c,      t * x * y - s * z,  t * x * z + s * y),
        vec3(t * x * y + s * z,  t * y * y + c,      t * y * z - s * x),
        vec3(t * x * z - s * y,  t * y * z + s * x,  t * z * z + c)
    );
}

float rand(vec3 c){
    return fract(sin(dot(c, vec3(12.9898, 78.233, 32.43983))) * 43758.5453);
}
 
float noise(vec3 p, float freq){
    float unit = 1000/freq;
    p = rotation(rand(vec3(23.473, -128.437, 23.439)) * 6.28318531,
        normalize(vec3(rand(vec3(-2, 3, 1)), rand(vec3(23.2, 47.3, 82.8)), rand(vec3(-239.3, -4.3, 2.59))))) * p;
    vec3 ij = floor(p/unit);
    vec3 xy = mod(p,unit)/unit;
    xy = .5*(1.-cos(3.1415926535*xy));
    float a = rand((ij+vec3(0.,0.,0.)));
    float b = rand((ij+vec3(1.,0.,0.)));
    float c = rand((ij+vec3(0.,1.,0.)));
    float d = rand((ij+vec3(1.,1.,0.)));
    float e = rand((ij+vec3(0.,0.,1.)));
    float f = rand((ij+vec3(1.,0.,1.)));
    float g = rand((ij+vec3(0.,1.,1.)));
    float h = rand((ij+vec3(1.,1.,1.)));
    float x1 = mix(a, b, xy.x);
    float x2 = mix(c, d, xy.x);
    float x3 = mix(e, f, xy.x);
    float x4 = mix(g, h, xy.x);
    float y1 = mix(x1, x2, xy.y);
    float y2 = mix(x3, x4, xy.y);
    return mix(y1, y2, xy.z);
}
 
float pNoise(vec3 p, int res){
    float persistance = .5;
    float n = 0.;
    float normK = 0.;
    float f = 4.;
    float amp = 1.;
    int iCount = 0;
    for (int i = 0; i<50; i++){
        n+=amp*noise(p, f);
        f*=2.;
        normK+=amp;
        amp*=persistance;
        if (iCount == res) break;
        iCount++;
    }
    float nf = n/normK;
    return nf;
}

void main(){
    gl_FragColor = vec4(
        pNoise(vec3(gl_FragCoord.xy + vec2(57349.4387, -1271.45738), time), 4),
        pNoise(vec3(gl_FragCoord.xy + vec2(9453.32748, 23875.43473), time), 4),
        pNoise(vec3(gl_FragCoord.xy + vec2(-28574.323, 125943457.3), time), 4), 1);
}

经过进一步测试,查看代码,实际湍流似乎只是 [-1, 1] 范围内的 perlin 噪声,然后取其绝对值。

作为参考,这是我用这种方法得到的图像:

the result of my turbulence filter using an absolute value

还有一个来自我的代码的湍流位移示例:

A turbulence displacement example

谢谢!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-15
    • 2019-01-04
    • 1970-01-01
    • 2012-05-04
    • 2021-02-15
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    相关资源
    最近更新 更多