2

我實施了一個使用來自ashima/webgl-noisesimplex噪音的太陽表面的着色器。但是它花費了太多GPU時間,特別是如果我要在移動設備上使用它。我需要做同樣的效果,但使用噪點紋理。我的片段着色器如下:GLSL - 使用二維紋理進行3D Perlin噪音而不是程序3D噪音

#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紋理。

回答

0

我從2D紋理函數中寫出了這個3D噪聲。它仍然使用x/y方向的硬件插值,然後手動插入z。爲了獲得沿着z方向的噪聲,我在不同的偏移處採樣了相同的紋理。這可能會導致一些重複,但我沒有注意到任何在我的應用程序,我的猜測是使用素數的幫助。

讓我在shadertoy.com上難住了一段時間,紋理貼圖被啓用,導致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); 
} 

更新:要在不同的頻率擴展到柏林噪聲,和數樣本:

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; 
} 
+0

你的噪點紋理是怎樣的? – Nolesh

+0

@Nolesh只是隨機值(即'rand()%255'),但需要GL_LINEAR過濾。 – jozxyqk

+0

也許,我使用不當。 vec3 position = v_normal + vec3(time,0,0); float n1 = noise3D(position); gl_FragColor = vec4(vec3(n1,n1,n1),1.0);我得到了類似的結果,如果我會使用texture2D(u_noise,position.xy).x; – Nolesh

0

嘗試評估在運行時的噪音往往是一個不好的做法,除非你想做一些研究工作或者快速檢查/調試你的噪聲功能(或者看看你的噪聲參數在視覺上是什麼樣的)。

它總是會消耗太多的處理預算(根本不值得),所以在運行時忘記評估噪聲。

如果您離線存儲噪音結果,您將減少收費(例如超過95%)以簡化對存儲器的訪問。

我建議將所有這些減少到預先烘焙的2D噪聲圖像上的紋理查找。你到目前爲止隻影響片段流水線,所以二維噪聲紋理絕對是要走的路(你也可以使用這個2D查找頂點位置變形)。

爲了將它映射到一個沒有任何連續性問題的球體上,您可以生成一個帶有4D噪聲的可循環2D圖像,併爲該函數提供兩個2D圓的座標。

至於它的動畫效果,有各種各樣的詭計,或者通過在片段管道中將查找結果與時間語義進行變形,或者在真正需要「帶噪聲動畫」的情況下烘焙圖像序列。

三維紋理只是二維紋理的堆棧,所以它們太重,無法操作(即使沒有動畫),因爲你想要做的事情,因爲你顯然只需要一個體面的太陽表面,這將是矯枉過正。