В GLSL шума Симплекс с производными финансовыми инструментами


Недавно я сделал шума 2D симплекс на основе когерентного шума в GLSL. [Здесь] - это шейдер игрушки.

Я хотел, чтобы реализация симплекс шума на GPU для того, чтобы получить лучшую производительность, чем реализация процессора. Я еще для сравнения моя реализация процессора, но это проходит довольно быстро, единственная разница заключается в том, что это Общества с одинарной точностью ввода. Другая вещь, которую я хотел увидеть, если я могу использовать мои пользовательские функции хеширования на GPU версия. Мой хэш-функции состоит из двух частей, первая рандомизации входных данных, затем объединение рандомизированных входов, singlehashи combinedHash. Он основан на Murmurhash3 лавина смесителя.

Существуют три основных функции, simplexNoiseV, simplexNoiseDVи simplexNoiseDвместе с их соответствующей октавной аккумулятором функции (accumulateSimplexNoise). Они в основном имеют тот же код, за исключением функции D также нужен для расчета производных функции V нужно вычислить значение шума (ДВ вычисляет оба).

Я ищу производительности предложения, код качества предложения, и/или алгоритм качественного предложения. У меня есть трудное время, пытаясь сделать материал читаемым в GLSL, так как там не много идей для него, и язык имеет некоторые довольно раздражающие синтаксис.

Примечание: есть определение выше основной, DISPLAY_TYPEизменение типа дисплея будет отображать шум, производная от шума, шум и производная на верхней части друг друга, и раздвижные окна показаны бок о бок.

кроме того, есть еще один набор функций в Commonэти не имеют ничего общего с шумом, и вы можете игнорировать их, они были скопированы из другого проекта для моего удобства и нормализовать УФ значения для правильного масштаба независимо от размера окна.

//NOISE CONSTANTS
// captured from https://en.wikipedia.org/wiki/SHA-2#Pseudocode
const uint CONST_A = 0xcc9e2d51u;
const uint CONST_B = 0x1b873593u;
const uint CONST_C = 0x85ebca6bu;
const uint CONST_D = 0xc2b2ae35u;
const uint CONST_E = 0xe6546b64u;
const uint CONST_F = 0x510e527fu;
const uint CONST_G = 0x923f82a4u;
const uint CONST_H = 0x14292967u;

const uint CONST_0 = 4294967291u;
const uint CONST_1 = 604807628u;
const uint CONST_2 = 2146583651u;
const uint CONST_3 = 1072842857u;
const uint CONST_4 = 1396182291u;
const uint CONST_5 = 2227730452u;
const uint CONST_6 = 3329325298u;
const uint CONST_7 = 3624381080u;


//settings for fractal brownian motion noise
struct BrownianFractalSettings{
    int octave_count;
    float frequency;
    float lacunarity;
    float persistence;
    float amplitude;
};


const float SQRT3 = 1.7320508075688772935274463415059;
const float SQRT2 = 1.4142135623730950488016887242096;

//contains a value and a vector derivative. 
struct vecd2{
    float v;
    vec2 d;
};

uvec2 singleHash(uvec2 uval){
    uval ^= uval >> 16;
    uval.x *= CONST_A;
    uval.y *= CONST_B;
    return uval;
}

uint combineHash(uint seed, uvec2 uval){
    // can move this out to compile time if need be. 
    // with out multiplying by one of the randomizing constants
    // will result in not very different results from seed to seed. 
    uint un = seed * CONST_5;
    un ^= (uval.x^uval.y)* CONST_0;
    un ^= (un >> 16);
    return un;
}

float calcGradv(uint uval){
    //straight uint to float conversion will leave 
    //large swaths of zero values on sin(gradv) or cos(gradv)
    //taking only the bottom 16bits takes care of this
    //hash already combines top hash ^= hash >> 16;
    //so no "random-ness" is lost.
    float gradv = float(int(uval & 65535u));
    return gradv;

}

vec2 getGradient(uint uval){
    float gradv = calcGradv(uval);
    //look up tables on gpu are so slow, 
    //gradient calculation will run > 2x as slow with out this
    vec2 grad = vec2(cos(gradv), sin(gradv));
    return grad;
}


//source of some constants
//https://github.com/Auburns/FastNoise/blob/master/FastNoise.cpp
const float SKEW2D = 0.5 * (SQRT3 - 1.0);
const float UNSKEW2D = (3.0 - SQRT3) / 6.0;
const float FAR_CORNER_UNSKEW2D = -1.0 + 2.0*UNSKEW2D;
//wasn't getting consistent high values close to 1.0 or -1.0, so increased scale slightly, sqrt needed to un-normalize sin cos values to be sqrt(2) -> -sqrt(2) range. 
const float NORMALIZE_SCALE2D = 72.0 * SQRT2;
const float DISTCONST_2D = 0.5;
const uint SEED = 5u;

float simplexNoiseV(in vec2 pos){
    float skew_factor = (pos.x + pos.y)*SKEW2D;
    vec2 fsimplex_corner0 = floor(pos + skew_factor);
    ivec2 simplex_corner0 = ivec2(fsimplex_corner0);

    float unskew_factor = (fsimplex_corner0.x + fsimplex_corner0.y) * UNSKEW2D;
    vec2 pos0 = fsimplex_corner0 - unskew_factor;

    //subpos's are positions with in grid cell. 
    vec2 subpos0 = pos - pos0;
    //precomputed values used in determining hash, reduces redundant hash computation
    //shows 10% -> 20% speed boost. 
    uvec2 hashes_offset0 = singleHash(uvec2(simplex_corner0));
    uvec2 hashes_offset1 = singleHash(uvec2(simplex_corner0+1));
    //near corner hash value
    uint hashval0 = combineHash(SEED, hashes_offset0);
    //mid corner hash value
    uint hashval1;
    //far corner hash value
    uint hashval2 = combineHash(SEED, hashes_offset1);

    ivec2 simplex_corner1;
    if(subpos0.x > subpos0.y){
        hashval1 = combineHash(SEED, uvec2(hashes_offset1.x, hashes_offset0.y));
        simplex_corner1 =  ivec2(1, 0);
    }else{
        hashval1 = combineHash(SEED, uvec2(hashes_offset0.x, hashes_offset1.y));
        simplex_corner1 =  ivec2(0, 1);
    }

    vec2 subpos1 = subpos0 - vec2(simplex_corner1) + UNSKEW2D;
    vec2 subpos2 = subpos0 + FAR_CORNER_UNSKEW2D;
    float n0, n1, n2;

    //http://catlikecoding.com/unity/tutorials/simplex-noise/
    //circle distance factor to make sure second derivative is continuous
    // t variables represent (1 - x^2 + y^2 + ...)^3, a distance function with 
    // continous first and second derivatives that are zero when x is one. 
    float t0 = DISTCONST_2D - subpos0.x*subpos0.x - subpos0.y*subpos0.y;
    //if t < 0, we get odd dips in continuity at the ends, so we just force it to zero
    // to prevent it
    if(t0 < 0.0){
        n0 = 0.0;
    }else{
        float t0_pow2 = t0 * t0;
        float t0_pow4 = t0_pow2 * t0_pow2;
        vec2 grad = getGradient(hashval0);
        float product = dot(subpos0, grad);
        n0 = t0_pow4 * product;
    }
    float t1 = 0.5 - subpos1.x*subpos1.x - subpos1.y*subpos1.y;
    if(t1 < 0.0){
        n1 = 0.0;
    }else{
        float t1_pow2 = t1 * t1;
        float t1_pow4 = t1_pow2*t1_pow2;
        vec2 grad = getGradient(hashval1);
        float product = dot(subpos1, grad);
        n1 = t1_pow4 * product;
    }
    float t2 = 0.5 - subpos2.x*subpos2.x - subpos2.y*subpos2.y;
    if(t2 < 0.0){
        n2 = 0.0;
    }else{
        float t2_pow2 = t2 * t2;
        float t2_pow4 = t2_pow2*t2_pow2;
        vec2 grad = getGradient(hashval2);
        float product = dot(subpos2, grad);
        n2 = t2_pow4 * product;
    }
    return (n0 + n1 + n2);
}

vecd2 simplexNoiseDV(in vec2 pos){
    float skew_factor = (pos.x + pos.y)*SKEW2D;
    vec2 fsimplex_corner0 = floor(pos + skew_factor);
    ivec2 simplex_corner0 = ivec2(fsimplex_corner0);

    float unskew_factor = (fsimplex_corner0.x + fsimplex_corner0.y) * UNSKEW2D;
    vec2 pos0 = fsimplex_corner0 - unskew_factor;

    //subpos's are positions with in grid cell. 
    vec2 subpos0 = pos - pos0;
    //precomputed values used in determining hash, reduces redundant hash computation
    //shows 10% -> 20% speed boost. 
    uvec2 hashes_offset0 = singleHash(uvec2(simplex_corner0));
    uvec2 hashes_offset1 = singleHash(uvec2(simplex_corner0+1));
    //near corner hash value
    uint hashval0 = combineHash(SEED, hashes_offset0);
    //mid corner hash value
    uint hashval1;
    //far corner hash value
    uint hashval2 = combineHash(SEED, hashes_offset1);

    ivec2 simplex_corner1;
    if(subpos0.x > subpos0.y){
        hashval1 = combineHash(SEED, uvec2(hashes_offset1.x, hashes_offset0.y));
        simplex_corner1 =  ivec2(1, 0);
    }else{
        hashval1 = combineHash(SEED, uvec2(hashes_offset0.x, hashes_offset1.y));
        simplex_corner1 =  ivec2(0, 1);
    }

    vec2 subpos1 = subpos0 - vec2(simplex_corner1) + UNSKEW2D;
    vec2 subpos2 = subpos0 + FAR_CORNER_UNSKEW2D;
    float n0, n1, n2;
    vec2 dn0, dn1, dn2;

    //http://catlikecoding.com/unity/tutorials/simplex-noise/
    //circle distance factor to make sure second derivative is continuous
    // t variables represent (1 - x^2 + y^2 + ...)^3, a distance function with 
    // continous first and second derivatives that are zero when x is one. 
    float t0 = DISTCONST_2D - subpos0.x*subpos0.x - subpos0.y*subpos0.y;
    //if t < 0, we get odd dips in continuity at the ends, so we just force it to zero
    // to prevent it
    if(t0 < 0.0){
        n0 = 0.0;
        dn0 = vec2(0.0);
    }else{
        float t0_pow2 = t0 * t0;
        float t0_pow3 = t0_pow2 * t0;
        float t0_pow4 = t0_pow2 * t0_pow2;
        vec2 grad = getGradient(hashval0);
        float product = dot(subpos0, grad);
        n0 = t0_pow4 * product;
        float coefA = t0_pow3 * product * -8.0;
        dn0 = (coefA * subpos0) + (t0_pow4 * grad);
    }
    float t1 = 0.5 - subpos1.x*subpos1.x - subpos1.y*subpos1.y;
    if(t1 < 0.0){
        n1 = 0.0;
        dn1= vec2(0.0);
    }else{
        float t1_pow2 = t1 * t1;
        float t1_pow3 = t1_pow2 * t1;
        float t1_pow4 = t1_pow2*t1_pow2;
        vec2 grad = getGradient(hashval1);
        float product = dot(subpos1, grad);
        n1 = t1_pow4 * product;
        float coefA = t1_pow3 * product * -8.0;
        dn1 = (coefA * subpos1) + (t1_pow4 * grad);
    }
    float t2 = 0.5 - subpos2.x*subpos2.x - subpos2.y*subpos2.y;
    if(t2 < 0.0){
        n2 = 0.0;
        dn2 = vec2(0.0);
    }else{
        float t2_pow2 = t2 * t2;
        float t2_pow3 = t2_pow2 * t2;
        float t2_pow4 = t2_pow2*t2_pow2;
        vec2 grad = getGradient(hashval2);
        float product = dot(subpos2, grad);
        n2 = t2_pow4 * product;
        float coefA = t2_pow3 * product * -8.0;
        dn2 = (coefA * subpos2) + (t2_pow4 * grad);
    }
    float v = (n0 + n1 + n2);
    return vecd2(v, vec2(dn0 + dn1 + dn2));
}

vec2 simplexNoiseD(in vec2 pos){
    float skew_factor = (pos.x + pos.y)*SKEW2D;
    vec2 fsimplex_corner0 = floor(pos + skew_factor);
    ivec2 simplex_corner0 = ivec2(fsimplex_corner0);

    float unskew_factor = (fsimplex_corner0.x + fsimplex_corner0.y) * UNSKEW2D;
    vec2 pos0 = fsimplex_corner0 - unskew_factor;

    //subpos's are positions with in grid cell. 
    vec2 subpos0 = pos - pos0;
    //precomputed values used in determining hash, reduces redundant hash computation
    //shows 10% -> 20% speed boost. 
    uvec2 hashes_offset0 = singleHash(uvec2(simplex_corner0));
    uvec2 hashes_offset1 = singleHash(uvec2(simplex_corner0+1));
    //near corner hash value
    uint hashval0 = combineHash(SEED, hashes_offset0);
    //mid corner hash value
    uint hashval1;
    //far corner hash value
    uint hashval2 = combineHash(SEED, hashes_offset1);

    ivec2 simplex_corner1;
    if(subpos0.x > subpos0.y){
        hashval1 = combineHash(SEED, uvec2(hashes_offset1.x, hashes_offset0.y));
        simplex_corner1 =  ivec2(1, 0);
    }else{
        hashval1 = combineHash(SEED, uvec2(hashes_offset0.x, hashes_offset1.y));
        simplex_corner1 =  ivec2(0, 1);
    }

    vec2 subpos1 = subpos0 - vec2(simplex_corner1) + UNSKEW2D;
    vec2 subpos2 = subpos0 + FAR_CORNER_UNSKEW2D;

    vec2 dn0, dn1, dn2;

    //http://catlikecoding.com/unity/tutorials/simplex-noise/
    //circle distance factor to make sure second derivative is continuous
    // t variables represent (1 - x^2 + y^2 + ...)^3, a distance function with 
    // continous first and second derivatives that are zero when x is one. 
    float t0 = DISTCONST_2D - subpos0.x*subpos0.x - subpos0.y*subpos0.y;
    //if t < 0, we get odd dips in continuity at the ends, so we just force it to zero
    // to prevent it
    if(t0 < 0.0){
        dn0 = vec2(0.0);
    }else{
        float t0_pow2 = t0 * t0;
        float t0_pow3 = t0_pow2 * t0;
        float t0_pow4 = t0_pow2 * t0_pow2;
        vec2 grad = getGradient(hashval0);
        float product = dot(subpos0, grad);
        float coefA = t0_pow3 * product * -8.0;
        dn0 = (coefA * subpos0) + (t0_pow4 * grad);
    }
    float t1 = 0.5 - subpos1.x*subpos1.x - subpos1.y*subpos1.y;
    if(t1 < 0.0){
        dn1 = vec2(0.0);
    }else{
        float t1_pow2 = t1 * t1;
        float t1_pow3 = t1_pow2 * t1;
        float t1_pow4 = t1_pow2*t1_pow2;
        vec2 grad = getGradient(hashval1);
        float product = dot(subpos1, grad);
        float coefA = t1_pow3 * product * -8.0;
        dn1 = (coefA * subpos1) + (t1_pow4 * grad);
    }
    float t2 = 0.5 - subpos2.x*subpos2.x - subpos2.y*subpos2.y;
    if(t2 < 0.0){
        dn2 = vec2(0.0);
    }else{
        float t2_pow2 = t2 * t2;
        float t2_pow3 = t2_pow2 * t2;
        float t2_pow4 = t2_pow2*t2_pow2;
        vec2 grad = getGradient(hashval2);
        float product = dot(subpos2, grad);
        float coefA = t2_pow3 * product * -8.0;
        dn2 = (coefA * subpos2) + (t2_pow4 * grad);
    }
    return vec2(dn0 + dn1 + dn2);
}

float accumulateSimplexNoiseV(in BrownianFractalSettings settings, vec2 pos){
    float accumulated_noise = 0.0;
    vec2 octave_pos = pos * settings.frequency;
    for (int octave = 0; octave < settings.octave_count; octave++) {
        float noise = simplexNoiseV(octave_pos);
        noise *= pow(settings.persistence, float(octave));
        accumulated_noise += noise;
        octave_pos *= settings.lacunarity;
    }
    float scale = 2.0 - pow(settings.persistence, float(settings.octave_count - 1));
    return (accumulated_noise/scale) * NORMALIZE_SCALE2D * settings.amplitude;
}

vecd2 accumulateSimplexNoiseDV(in BrownianFractalSettings settings, vec2 pos){
    float accumulated_noise = 0.0;
    vec2 accumulated_dnoise = vec2(0.0);
    vec2 octave_pos = pos * settings.frequency;

    for (int octave = 0; octave < settings.octave_count; octave++) {
        vecd2 vdnoise = simplexNoiseDV(octave_pos);
        vdnoise.v *= pow(settings.persistence, float(octave));
        vdnoise.d *= pow(settings.persistence, float(octave));
        accumulated_noise += vdnoise.v;
        accumulated_dnoise += vdnoise.d;
        octave_pos *= settings.lacunarity;
    }
    float scale = 2.0 - pow(settings.persistence, float(settings.octave_count - 1));
    float noise = (accumulated_noise/scale) * NORMALIZE_SCALE2D * settings.amplitude;
    vec2 dnoise = (accumulated_dnoise/scale) * NORMALIZE_SCALE2D * settings.amplitude;
    return vecd2(noise, dnoise);
}


vec2 accumulateSimplexNoiseD(in BrownianFractalSettings settings, vec2 pos){
    vec2 accumulated_dnoise = vec2(0.0);
    vec2 octave_pos = pos * settings.frequency;

    for (int octave = 0; octave < settings.octave_count; octave++) {
        vec2 dnoise = simplexNoiseD(octave_pos);
        dnoise *= pow(settings.persistence, float(octave));
        accumulated_dnoise += dnoise;
        octave_pos *= settings.lacunarity;
    }
    float scale = 2.0 - pow(settings.persistence, float(settings.octave_count - 1));
    return (accumulated_dnoise/scale) * NORMALIZE_SCALE2D * settings.amplitude;
}

#define DISPLAY_NOISE 0
#define DISPLAY_DNOISE 1
#define DISPLAY_BOTH_NOISE 2
#define DISPLAY_MOVING 3

#define DISPLAY_TYPE 0

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from -1 to 1)
    vec2 uv = calculateUV(fragCoord, iResolution);
    BrownianFractalSettings fbm_settings = 
        BrownianFractalSettings(1, 2.0, 2.0, 0.5, 1.0);
    #if DISPLAY_TYPE == DISPLAY_NOISE
    float noise = accumulateSimplexNoiseV(fbm_settings, uv);
    noise = (noise+1.0)/2.0;
    vec3 color = vec3(noise);

    #elif DISPLAY_TYPE == DISPLAY_DNOISE
    vec2 dnoise = accumulateSimplexNoiseD(fbm_settings, uv);
    dnoise = normalize(dnoise);
    dnoise = (dnoise + 1.0)/2.0;
    vec3 color = vec3(dnoise,0.0);

    #elif DISPLAY_TYPE == DISPLAY_BOTH_NOISE
    vecd2 vdnoise = accumulateSimplexNoiseDV(fbm_settings, uv);
    float noise = vdnoise.v;
    noise = (noise+1.0)/2.0;
    vec2 dnoise = vdnoise.d;
    dnoise = normalize(dnoise);
    dnoise = (dnoise + 1.0)/2.0;
    dnoise *= 0.2;
    vec3 color = noise*0.8 + vec3(dnoise,0.0);

    #elif DISPLAY_TYPE == DISPLAY_MOVING
    vec3 color;
    if(uv.x < sin(iTime)*1.8){
        float noise = accumulateSimplexNoiseV(fbm_settings, uv);
        noise = (noise+1.0)/2.0;
        color = vec3(noise);
    }else{
        vec2 dnoise = accumulateSimplexNoiseD(fbm_settings, uv);
        dnoise = normalize(dnoise);
        dnoise = (dnoise + 1.0)/2.0;
        color = vec3(dnoise,0.0);
    }

    #endif

    fragColor = vec4(color,0.0);
}


173
1
задан 29 марта 2018 в 07:03 Источник Поделиться
Комментарии