【问题标题】:GLSL - Using a 2D texture for 3D Perlin noise instead of procedural 3D noiseGLSL - 将 2D 纹理用于 3D Perlin 噪声而不是程序 3D 噪声
【发布时间】:2015-08-16 05:51:28
【问题描述】:

我为太阳表面实现了一个着色器,它使用来自ashima/webgl-noisesimplex 噪声。但是它花费了太多的 GPU 时间,特别是如果我要在移动设备上使用它。我需要做同样的效果,但使用噪声纹理。我的片段着色器如下:

#ifdef GL_ES
precision highp float;
#endif
precision mediump float;

varying vec2 v_texCoord;
varying vec3 v_normal;

uniform sampler2D u_planetDay;
uniform sampler2D u_noise; //noise texture (not used yet)
uniform float u_time;

#include simplex_noise_source from Ashima

float noise(vec3 position, int octaves, float frequency, float persistence)   {
float total = 0.0; // Total value so far
float maxAmplitude = 0.0; // Accumulates highest theoretical amplitude
float amplitude = 1.0;
for (int i = 0; i < octaves; i++) {
    // Get the noise sample
    total += ((1.0 - abs(snoise(position * frequency))) * 2.0 - 1.0) * amplitude;
    //I USE LINE BELOW FOR 2D NOISE
    total += ((1.0 - abs(snoise(position.xy * frequency))) * 2.0 - 1.0) * amplitude;
    // Make the wavelength twice as small
    frequency *= 2.0;
    // Add to our maximum possible amplitude
    maxAmplitude += amplitude;
    // Reduce amplitude according to persistence for the next octave
    amplitude *= persistence;
}
// Scale the result by the maximum amplitude
return total / maxAmplitude;
}

void main()
{   
    vec3 position = v_normal *2.5+ vec3(u_time, u_time, u_time);   
    float n1 = noise(position.xyz, 2, 7.7, 0.75) * 0.001;

    vec3 ground = texture2D(u_planetDay, v_texCoord+n1).rgb;
    gl_FragColor = vec4 (color, 1.0);
 }

如何校正此着色器以使用噪声纹理以及纹理应该是什么样子?

据我所知,OpenGL ES 2.0 不支持 3D 纹理。此外,我不知道如何创建 3D 纹理。

【问题讨论】:

    标签: glsl opengl-es-2.0 texture-mapping perlin-noise simplex-noise


    【解决方案1】:

    我用 2D 纹理函数编写了这个 3D 噪声。它仍然对x/y 方向使用硬件插值,然后为z 手动插值。为了获得沿z 方向的噪点,我在不同偏移处采样了相同的纹理。这可能会导致一些重复,但我在我的应用程序中没有注意到任何重复,我的猜测是使用素数帮助。

    shadertoy.com 上让我难过一阵子的是纹理 mipmapping 已启用,这会导致 floor() 函数的值发生变化时出现接缝。一个快速的解决方案是将-999 偏差传递给texture2D

    这是针对 256x256 噪声纹理进行硬编码的,因此请进行相应调整。

    float noise3D(vec3 p)
    {
        p.z = fract(p.z)*256.0;
        float iz = floor(p.z);
        float fz = fract(p.z);
        vec2 a_off = vec2(23.0, 29.0)*(iz)/256.0;
        vec2 b_off = vec2(23.0, 29.0)*(iz+1.0)/256.0;
        float a = texture2D(iChannel0, p.xy + a_off, -999.0).r;
        float b = texture2D(iChannel0, p.xy + b_off, -999.0).r;
        return mix(a, b, fz);
    }
    

    更新:为了扩展到 perlin 噪声,对不同频率的样本求和:

    float perlinNoise3D(vec3 p)
    {
        float x = 0.0;
        for (float i = 0.0; i < 6.0; i += 1.0)
            x += noise3D(p * pow(2.0, i)) * pow(0.5, i);
        return x;
    }
    

    【讨论】:

    • 你的噪点纹理看起来如何?
    • @Nolesh 只是随机值(即rand()%255),但需要GL_LINEAR 过滤。
    • 可能是我使用不当。 vec3 位置 = v_normal + vec3(时间, 0, 0);浮动 n1 = 噪声 3D(位置); gl_FragColor = vec4 (vec3(n1,n1,n1), 1.0);我得到类似的结果,就好像我会使用 texture2D (u_noise, position.xy).x;
    • Here's a simpler test 显示差异,每隔几秒切换一次。检查它是否正常工作的一种简单方法是将position 替换为position.xzy,它应该看起来相同。噪声应该是随机的,并且在所有方向上都是统一的。
    • @Nolesh 我还在 ShaderFrog shaderfrog.com/app/view/253 中实现了它——它的可配置性更高,我正在清理代码。
    【解决方案2】:

    尝试在运行时评估噪声通常是一种不好的做法,除非您想做一些研究工作或快速检查/调试噪声函数(或查看噪声参数的外观)。

    它总是会消耗太多的处理预算(根本不值得),所以忘记在运行时评估噪声吧。

    如果您离线存储噪声结果,您将减少(例如超过 95%)对内存的简单访问。

    我建议将所有这些简化为在预烘焙的 2D 噪声图像上进行纹理查找。到目前为止,您只影响片段管道,因此 2D 噪声纹理绝对是要走的路(您也可以使用此 2D 查找来进行顶点位置变形)。

    为了在没有任何连续性问题的情况下将其映射到球体上,您可以生成带有 4D 噪声的可循环 2D 图像,并为函数提供两个 2D 圆的坐标。

    至于动画,有各种骇人听闻的技巧,要么通过片段管道中的时间语义变形你的查找结果,要么烘焙图像序列以防你真的需要“用噪音动画”的噪音。

    3D 纹理只是一堆 2D 纹理,因此它们太重而无法操作(即使没有动画)来完成您想要做的事情,而且由于您显然只需要一个像样的太阳表面,这将是矫枉过正。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 2017-09-04
      • 2011-08-01
      • 2011-10-21
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      相关资源
      最近更新 更多