سؤال

كما GPU سائق البائعين لا تهتم عادة لتنفيذ noiseX في GLSL, أنا أبحث عن "الرسومات العشوائية سكين الجيش السويسري" وظيفة الأداة مجموعة, ويفضل أن يكون الأمثل للاستخدام في غضون GPU تظليل.أنا أفضل GLSL ، ولكن رمز أي لغة سوف تفعل بالنسبة لي ، أنا موافق مع ترجمتها بنفسي إلى GLSL.

على وجه التحديد, أتوقع:

أ) شبه عشوائي وظائف - الابعاد, توزيع موحد على [-1,1] أو أكثر [0,1], تحسب من M-الأبعاد البذور (من الناحية المثالية أي قيمة ، ولكن أنا موافق مع وجود البذور النفس إلى 0..1 موحدة نتيجة التوزيع).شيء من هذا القبيل:

float random  (T seed);
vec2  random2 (T seed);
vec3  random3 (T seed);
vec4  random4 (T seed);
// T being either float, vec2, vec3, vec4 - ideally.

ب) المستمر الضوضاء مثل بيرلين الضوضاء مرة أخرى, الابعاد, +- توزيع موحد ، مع تقييد مجموعة من القيم, حسنا, تبدو جيدة (بعض الخيارات لتكوين ظهور مثل بيرلين مستويات يمكن أن تكون مفيدة جدا).أتوقع التوقيعات مثل:

float noise  (T coord, TT seed);
vec2  noise2 (T coord, TT seed);
// ...

أنا لست كثيرا في الجيل رقم عشوائي النظرية, لذلك أود أن معظم بفارغ الصبر الذهاب مسبقة الصنع الحل, ولكن أود أن نقدر أيضا إجابات مثل "هنا جيدة جدا وفعالة 1D راند () ، اسمحوا لي أن أشرح لكم كيفية جعل جيدة الابعاد راند() على أعلى من ذلك..." .

هل كانت مفيدة؟

المحلول

بالنسبة للأشياء البسيطة المظهر الكاذبة ، أستخدم هذا oneliner الذي وجدته على الإنترنت في مكان ما:

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

يمكنك أيضًا إنشاء نسيج ضوضاء باستخدام أي prng تريده ، ثم قم بتحميل ذلك بطريقة طبيعية وتذوق القيم الموجودة في تظليلك ؛ يمكنني حفر نموذج رمز لاحقًا إذا كنت ترغب في ذلك.

أيضا ، تحقق من هذا الملف لتطبيقات GLSL من ضوضاء Perlin و Simplex ، بقلم ستيفان غوستافسون.

نصائح أخرى

يستخدم تطبيق Gustavson نسيج 1D

لا ، لا ، ليس منذ عام 2005. إنه يصر الناس على تنزيل الإصدار القديم. يستخدم الإصدار الموجود على الرابط الذي قدمته سوى قوام ثنائي الأبعاد 8 بت فقط.

لا يستخدم الإصدار الجديد لـ Ian McEwan من Ashima وأنا نسيجًا ، ولكنه يعمل بنحو نصف السرعة على منصات سطح المكتب النموذجية مع الكثير من النطاق الترددي للملمس. على المنصات المحمولة ، قد تكون النسخة النصية أسرع لأن التنسيق غالبًا ما يكون عنق الزجاجة.

مستودع المصدر الذي تم الحفاظ عليه بنشاط هو:

https://github.com/ashima/webgl-noise

مجموعة من كل من الإصدارات غير المألوفة واستخدام الملمس من الضوضاء موجودة هنا (باستخدام القوام ثنائي الأبعاد فقط):

http://www.itn.liu.se/~stegu/simplexnoise/glsl-noise-vs-noise.zip

إذا كان لديك أي أسئلة محددة ، فلا تتردد في إرسال بريد إلكتروني لي مباشرة (يمكن العثور على عنوان بريدي الإلكتروني في classicnoise*.glsl مصادر.)

يحدث لي ذلك هل يمكن استخدام بسيط صحيح وظيفة تجزئة وإدراج يؤدي إلى تعويم هو العشري.IIRC على GLSL المواصفات ضمانات 32-بت غير الصحيحه و IEEE binary32 تطفو التمثيل لذلك ينبغي أن يكون تماما المحمولة.

أعطى هذه محاولة فقط الآن.النتائج جيدة جدا:يبدو تماما مثل ثابت مع كل المدخلات حاولت أي أنماط مرئية على الإطلاق.في المقابل شعبية الخطيئة/fract مقتطف وقد وضوحا إلى حد ما الخطوط القطرية على GPU تعطى نفس المدخلات.

عيب واحد هو أنه يتطلب GLSL v3.30.و على الرغم من أنه يبدو سريع بما فيه الكفاية, لم تجريبيا كميا أدائها.AMD تظليل محلل المطالبات 13.33 بكسل لكل ساعة من أجل vec2 النسخة على HD5870.على النقيض مع 16 بكسل في الساعة الخطيئة/fract مقتطف.لذلك هو بالتأكيد أبطأ قليلا.

هنا هو بلدي التنفيذ.تركته في التباديل المختلفة من فكرة أن تجعل من السهل استخلاص المهام الخاصة بك من.

/*
    static.frag
    by Spatial
    05 July 2013
*/

#version 330 core

uniform float time;
out vec4 fragment;



// A single iteration of Bob Jenkins' One-At-A-Time hashing algorithm.
uint hash( uint x ) {
    x += ( x << 10u );
    x ^= ( x >>  6u );
    x += ( x <<  3u );
    x ^= ( x >> 11u );
    x += ( x << 15u );
    return x;
}



// Compound versions of the hashing algorithm I whipped together.
uint hash( uvec2 v ) { return hash( v.x ^ hash(v.y)                         ); }
uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z)             ); }
uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); }



// Construct a float with half-open range [0:1] using low 23 bits.
// All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0.
float floatConstruct( uint m ) {
    const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask
    const uint ieeeOne      = 0x3F800000u; // 1.0 in IEEE binary32

    m &= ieeeMantissa;                     // Keep only mantissa bits (fractional part)
    m |= ieeeOne;                          // Add fractional part to 1.0

    float  f = uintBitsToFloat( m );       // Range [1:2]
    return f - 1.0;                        // Range [0:1]
}



// Pseudo-random value in half-open range [0:1].
float random( float x ) { return floatConstruct(hash(floatBitsToUint(x))); }
float random( vec2  v ) { return floatConstruct(hash(floatBitsToUint(v))); }
float random( vec3  v ) { return floatConstruct(hash(floatBitsToUint(v))); }
float random( vec4  v ) { return floatConstruct(hash(floatBitsToUint(v))); }





void main()
{
    vec3  inputs = vec3( gl_FragCoord.xy, time ); // Spatial and temporal inputs
    float rand   = random( inputs );              // Random per-pixel value
    vec3  luma   = vec3( rand );                  // Expand to RGB

    fragment = vec4( luma, 1.0 );
}

لقطة:

Output of random(vec3) in static.frag

أنا فتشت الصورة في برنامج تحرير الصور.هناك 256 ألوان متوسط قيمة 127 ، وهذا يعني توزيع موحد ويغطي النطاق المتوقع.

ضوضاء الذهب

// Gold Noise ©2015 dcerisano@standard3d.com 
//  - based on the Golden Ratio, PI and Square Root of Two
//  - superior distribution
//  - fastest noise generator function
//  - works with all chipsets (including low precision)

float PHI = 1.61803398874989484820459 * 00000.1; // Golden Ratio   
float PI  = 3.14159265358979323846264 * 00000.1; // PI
float SQ2 = 1.41421356237309504880169 * 10000.0; // Square Root of Two

float gold_noise(in vec2 coordinate, in float seed){
    return fract(tan(distance(coordinate*(seed+PHI), vec2(PHI, PI)))*SQ2);
}

شاهد ضوضاء الذهب في متصفحك الآن!

enter image description here

لقد تحسنت هذه الوظيفة التوزيع العشوائي على الوظيفة الحالية في إجابة appas اعتبارًا من 9 سبتمبر 2017:

enter image description here

وظيفة appas غير مكتملة أيضًا ، بالنظر إلى عدم توفر البذور (UV ليست بذرة - نفس الشيء لكل إطار) ، ولا تعمل مع شرائح منخفضة الدقة. يعمل ضوضاء الذهب بدقة منخفضة بشكل افتراضي (أسرع بكثير).

هناك أيضا لطيفة تنفيذ وصفها هنا قبل McEwan و @StefanGustavson يشبه بيرلين الضوضاء ، ولكن "لا تتطلب أي إعداد ، أيلا القوام ولا زي المصفوفات.فقط إضافة إلى تظليل الكود المصدري والذي يطلق عليه في أي مكان تريد".

هذا مفيد جدا ، خاصة أن غوستافسون في وقت سابق تنفيذ @dep المرتبطة يستخدم 1D الملمس ، وهو غير معتمدة في GLSL ES (تظليل لغة WebGL).

لقد وجدت للتو هذا الإصدار من الضوضاء ثلاثية الأبعاد ل GPU ، وهو ما هو أسرع الإصدار المتاح:

#ifndef __noise_hlsl_
#define __noise_hlsl_

// hash based 3d value noise
// function taken from https://www.shadertoy.com/view/XslGRr
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

// ported from GLSL to HLSL

float hash( float n )
{
    return frac(sin(n)*43758.5453);
}

float noise( float3 x )
{
    // The noise function returns a value in the range -1.0f -> 1.0f

    float3 p = floor(x);
    float3 f = frac(x);

    f       = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0 + 113.0*p.z;

    return lerp(lerp(lerp( hash(n+0.0), hash(n+1.0),f.x),
                   lerp( hash(n+57.0), hash(n+58.0),f.x),f.y),
               lerp(lerp( hash(n+113.0), hash(n+114.0),f.x),
                   lerp( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}

#endif

نسخة مستقيمة ، خشنة من 1D Perlin ، أساسا lfo متعرج عشوائي.

half  rn(float xx){         
    half x0=floor(xx);
    half x1=x0+1;
    half v0 = frac(sin (x0*.014686)*31718.927+x0);
    half v1 = frac(sin (x1*.014686)*31718.927+x1);          

    return (v0*(1-frac(xx))+v1*(frac(xx)))*2-1*sin(xx);
}

لقد عثرت أيضًا على 1-2-3-4D Perlin Noise على موقع Tutorial INIGO Quilez Perlin ، و Voronoi وما إلى ذلك ، لديه تطبيقات ورموز سريعة كاملة لهم.

التجزئة: في الوقت الحاضر WebGL2.0 هل هناك أعداد صحيحة متوفرة في (W) GLSL. -> بالنسبة لجودة التجزئة المحمولة (بتكلفة مماثلة من تجزئة العائم القبيح) ، يمكننا الآن استخدام تقنيات التجزئة "الخطيرة". نفذ الذكاء بعض في https://www.shadertoy.com/view/xlxcw4 (و اكثر)

على سبيل المثال:

  const uint k = 1103515245U;  // GLIB C
//const uint k = 134775813U;   // Delphi and Turbo Pascal
//const uint k = 20170906U;    // Today's date (use three days ago's dateif you want a prime)
//const uint k = 1664525U;     // Numerical Recipes

vec3 hash( uvec3 x )
{
    x = ((x>>8U)^x.yzx)*k;
    x = ((x>>8U)^x.yzx)*k;
    x = ((x>>8U)^x.yzx)*k;

    return vec3(x)*(1.0/float(0xffffffffU));
}

استخدم هذا:

highp float rand(vec2 co)
{
    highp float a = 12.9898;
    highp float b = 78.233;
    highp float c = 43758.5453;
    highp float dt= dot(co.xy ,vec2(a,b));
    highp float sn= mod(dt,3.14);
    return fract(sin(sn) * c);
}

لا تستخدم هذا:

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

يمكنك العثور على التفسير في التحسينات على الكنسي الواحد GLSL RAND () لـ OpenGL ES 2.0

يرجى الاطلاع أدناه على مثال على كيفية إضافة ضوضاء بيضاء إلى الملمس المقدم. الحل هو استخدام قوامين: الضوضاء البيضاء الأصلية والنقية ، مثل هذا: ويكي الضوضاء البيضاء

private static final String VERTEX_SHADER =
    "uniform mat4 uMVPMatrix;\n" +
    "uniform mat4 uMVMatrix;\n" +
    "uniform mat4 uSTMatrix;\n" +
    "attribute vec4 aPosition;\n" +
    "attribute vec4 aTextureCoord;\n" +
    "varying vec2 vTextureCoord;\n" +
    "varying vec4 vInCamPosition;\n" +
    "void main() {\n" +
    "    vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
    "    gl_Position = uMVPMatrix * aPosition;\n" +
    "}\n";

private static final String FRAGMENT_SHADER =
        "precision mediump float;\n" +
        "uniform sampler2D sTextureUnit;\n" +
        "uniform sampler2D sNoiseTextureUnit;\n" +
        "uniform float uNoseFactor;\n" +
        "varying vec2 vTextureCoord;\n" +
        "varying vec4 vInCamPosition;\n" +
        "void main() {\n" +
                "    gl_FragColor = texture2D(sTextureUnit, vTextureCoord);\n" +
                "    vec4 vRandChosenColor = texture2D(sNoiseTextureUnit, fract(vTextureCoord + uNoseFactor));\n" +
                "    gl_FragColor.r += (0.05 * vRandChosenColor.r);\n" +
                "    gl_FragColor.g += (0.05 * vRandChosenColor.g);\n" +
                "    gl_FragColor.b += (0.05 * vRandChosenColor.b);\n" +
        "}\n";

يحتوي الجزء المشترك على معلمة unoisefactor التي يتم تحديثها على كل عرض حسب التطبيق الرئيسي:

float noiseValue = (float)(mRand.nextInt() % 1000)/1000;
int noiseFactorUniformHandle = GLES20.glGetUniformLocation( mProgram, "sNoiseTextureUnit");
GLES20.glUniform1f(noiseFactorUniformHandle, noiseFactor);

لقد ترجمت أحد تطبيقات Java في Ken Perlin إلى GLSL واستخدمتها في مشاريع زوجين في Shadertoy.

فيما يلي تفسير GLSL الذي قمت به:

int b(int N, int B) { return N>>B & 1; }
int T[] = int[](0x15,0x38,0x32,0x2c,0x0d,0x13,0x07,0x2a);
int A[] = int[](0,0,0);

int b(int i, int j, int k, int B) { return T[b(i,B)<<2 | b(j,B)<<1 | b(k,B)]; }

int shuffle(int i, int j, int k) {
    return b(i,j,k,0) + b(j,k,i,1) + b(k,i,j,2) + b(i,j,k,3) +
        b(j,k,i,4) + b(k,i,j,5) + b(i,j,k,6) + b(j,k,i,7) ;
}

float K(int a, vec3 uvw, vec3 ijk)
{
    float s = float(A[0]+A[1]+A[2])/6.0;
    float x = uvw.x - float(A[0]) + s,
        y = uvw.y - float(A[1]) + s,
        z = uvw.z - float(A[2]) + s,
        t = 0.6 - x * x - y * y - z * z;
    int h = shuffle(int(ijk.x) + A[0], int(ijk.y) + A[1], int(ijk.z) + A[2]);
    A[a]++;
    if (t < 0.0)
        return 0.0;
    int b5 = h>>5 & 1, b4 = h>>4 & 1, b3 = h>>3 & 1, b2= h>>2 & 1, b = h & 3;
    float p = b==1?x:b==2?y:z, q = b==1?y:b==2?z:x, r = b==1?z:b==2?x:y;
    p = (b5==b3 ? -p : p); q = (b5==b4 ? -q : q); r = (b5!=(b4^b3) ? -r : r);
    t *= t;
    return 8.0 * t * t * (p + (b==0 ? q+r : b2==0 ? q : r));
}

float noise(float x, float y, float z)
{
    float s = (x + y + z) / 3.0;  
    vec3 ijk = vec3(int(floor(x+s)), int(floor(y+s)), int(floor(z+s)));
    s = float(ijk.x + ijk.y + ijk.z) / 6.0;
    vec3 uvw = vec3(x - float(ijk.x) + s, y - float(ijk.y) + s, z - float(ijk.z) + s);
    A[0] = A[1] = A[2] = 0;
    int hi = uvw.x >= uvw.z ? uvw.x >= uvw.y ? 0 : 1 : uvw.y >= uvw.z ? 1 : 2;
    int lo = uvw.x <  uvw.z ? uvw.x <  uvw.y ? 0 : 1 : uvw.y <  uvw.z ? 1 : 2;
    return K(hi, uvw, ijk) + K(3 - hi - lo, uvw, ijk) + K(lo, uvw, ijk) + K(0, uvw, ijk);
}

لقد ترجمته من التذييل ب من الفصل 2 من أجهزة ضوضاء كين بيرلين في هذا المصدر:

https://www.csee.umbc.edu/~olano/s2002c36/ch02.pdf

فيما يلي ظلال عامة قمت بها على Tader Toy التي تستخدم وظيفة الضوضاء المنشورة:

https://www.shadertoy.com/view/3slxzm

تشمل بعض المصادر الجيدة الأخرى التي وجدتها حول موضوع الضوضاء أثناء بحثي:

https://thebookofshaders.com/11/

https://mzucker.github.io/html/perlin-noise-math-faq.html

https://rmarcus.info/blog/2018/03/04/perlin-noise.html

http://flafla2.github.io/2014/08/09/perlinnoise.html

https://mrl.nyu.edu/~perlin/noise/

https://rmarcus.info/blog/assets/perlin/perlin_paper.pdf

https://developer.nvidia.com/gpugems/gpugems/gpugems_ch05.html

أوصي بشدة كتاب التظليل لأنه لا يوفر تفسيرًا تفاعليًا رائعًا للضوضاء ، ولكن أيضًا مفاهيم التظليل الأخرى أيضًا.

تعديل:

قد تكون قادرة على تحسين الكود المترجم باستخدام بعض الوظائف المسلسة للأجهزة المتوفرة في GLSL. سيتم تحديث هذا المنشور إذا انتهى بي الأمر إلى القيام بذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top