ฟังก์ชั่นสุ่ม / เสียงรบกวนสำหรับ GLSL


179

ในฐานะที่เป็นผู้ผลิต GPU คนขับรถมักจะไม่รำคาญที่จะดำเนินการnoiseXใน GLSL ฉันมองหา"กราฟิกสุ่มมีดทหารสวิส"ชุดยูทิลิตี้ฟังก์ชั่นที่ดีที่สุดโดยเฉพาะอย่างยิ่งกับการใช้งานภายใน shaders GPU ฉันชอบ GLSL แต่รหัสภาษาใด ๆ ที่จะทำเพื่อฉันฉันตกลงกับการแปลเป็นของตัวเองเพื่อ GLSL

โดยเฉพาะฉันคาดหวัง:

a) ฟังก์ชั่นสุ่มหลอก - N-dimension, การกระจายแบบสม่ำเสมอเหนือ [-1,1] หรือสูงกว่า [0,1], คำนวณจากเมล็ด M-dimension (เป็นการดีที่มีค่าใด ๆ แต่ฉันก็โอเคกับการยับยั้งเมล็ด เพื่อ, พูด, 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.

b) เสียงรบกวนอย่างต่อเนื่องเช่น Perlin Noise - อีกครั้ง, การกระจายแบบ N-มิติ, + - พร้อมชุดค่าที่ จำกัด และดูดี (ตัวเลือกบางอย่างเพื่อกำหนดค่าลักษณะที่ปรากฏเช่นระดับ Perlin อาจมีประโยชน์เช่นกัน) ฉันคาดหวังลายเซ็นเช่น:

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

ฉันไม่ค่อยชอบทฤษฎีการสร้างตัวเลขแบบสุ่มดังนั้นฉันเลยอยากไปหาวิธีแก้ปัญหาที่ทำไว้ล่วงหน้าแต่ฉันก็ขอขอบคุณคำตอบเช่น"ที่นี่เป็น 1D แรนด์ที่ดีและมีประสิทธิภาพมากและให้ฉันอธิบาย คุณวิธีที่จะทำให้ N-มิติแรนด์ (ดี) ด้านบนของมัน ..."

คำตอบ:


263

สำหรับสิ่งที่ดูหลอกง่ายมากฉันใช้ oneliner นี้ที่ฉันพบบนอินเทอร์เน็ตที่ไหนสักแห่ง:

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

นอกจากนี้คุณยังสามารถสร้างพื้นผิวเสียงโดยใช้สิ่งที่คุณต้องการ PRNG จากนั้นอัปโหลดตามปกติและตัวอย่างค่าใน shader ของคุณ ฉันสามารถขุดตัวอย่างโค้ดได้ในภายหลังหากคุณต้องการ

นอกจากนี้ให้ตรวจสอบไฟล์นี้สำหรับการใช้งาน GLSL ของเสียง Perlin และ Simplex โดย Stefan Gustavson


14
คุณใช้vec2 coอย่างไร? มันเป็นช่วงหรือไม่ เมล็ดพันธุ์?
Ross

12
ระวังต่ำแม่นยำจุดลอยตัว shaders ชิ้นส่วนที่มีขั้นตอนวิธีนี้ (เช่น S3 ของ ARM Mali): stackoverflow.com/questions/11293628/... github.com/ashima/webgl-noiseโครงการไม่ได้ดูเหมือนจะมีปัญหา lowp
PT

4
FWIW ฟังก์ชั่นที่อธิบายที่นี่จะกล่าวถึงในรายละเอียดเพิ่มเติมที่นี่
Loomchild

3
FYI: การแจกแจงของฟังก์ชันนั้นแย่มาก
ธารา

3
ฉัน newb ใน GLSL, ใครสามารถอธิบายได้ว่าทำไมco.xyถูกนำมาใช้แทนco?
kelin

83

มันเกิดขึ้นกับฉันว่าคุณสามารถใช้ฟังก์ชันแฮชจำนวนเต็มอย่างง่ายและแทรกผลลัพธ์ลงใน Mantant ของ float IIRC ข้อมูลจำเพาะ GLSL รับประกันจำนวนเต็มที่ไม่ได้ลงชื่อ 32 บิตและการแทนค่าทศนิยม IEEE binary32 float ดังนั้นจึงควรพกพาได้อย่างสมบูรณ์แบบ

ฉันได้ลองทำสิ่งนี้แล้ว ผลลัพธ์เป็นสิ่งที่ดีมาก: ดูเหมือนว่าจะคงที่กับทุกอินพุตที่ฉันพยายามไม่มีรูปแบบที่มองเห็นได้เลย ในทางตรงกันข้ามความนิยมตัวอย่างของ sin / fract มีเส้นทแยงมุมที่เด่นชัดบน GPU ของฉันเนื่องจากอินพุตเดียวกัน

ข้อเสียอย่างหนึ่งคือต้องมี GLSL v3.30 และถึงแม้ว่ามันจะดูเร็วพอ แต่ฉันก็ไม่ได้ทำการคำนวณเชิงประจักษ์ เครื่องวิเคราะห์ Shader ของ AMD อ้างว่า 13.33 พิกเซลต่อนาฬิกาสำหรับรุ่น vec2 ใน HD5870 คมชัดด้วย 16 พิกเซลต่อนาฬิกาสำหรับตัวอย่างข้อมูล sin / 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 );
}

ภาพหน้าจอ:

เอาต์พุตของการสุ่ม (vec3) ใน static.frag

ฉันตรวจสอบภาพหน้าจอในโปรแกรมแก้ไขภาพ มี 256 สีและค่าเฉลี่ยคือ 127 หมายถึงการกระจายที่สม่ำเสมอและครอบคลุมช่วงที่คาดหวัง


17
+1 สำหรับแนวคิดและการนำไปปฏิบัติที่ดี ฉันจะถามการอ้างสิทธิ์ว่าเนื่องจากมี 256 สีและค่าเฉลี่ยคือ 127 การกระจายจะต้องเหมือนกัน (ในความหมายที่เข้มงวด) มันอาจจะเหมือนกัน แต่ฉันยังไม่คิดว่าเรารู้ เช่นการกระจายตัวของเส้นโค้งระฆังอาจมีค่าเฉลี่ยและจำนวนสีเท่ากัน แต่จะไม่สม่ำเสมอ
LarsH

โหวตสิ่งนี้ด้วยเหตุผลที่ได้รับจาก @LarsH
Autumnsault

ดีพอสำหรับการใช้งานส่วนใหญ่ที่ไม่ต้องการความสม่ำเสมอ :-)
itmuckel

5
ดูเหมือนว่าจะเป็นชุดที่ดีมากโดยการรับรู้ของฮิสโตแกรมของฉัน .... ฉันว่ามันดีพอสำหรับการใช้งานส่วนใหญ่ที่ต้องการความสม่ำเสมอเช่นกัน (ค่าเดียวที่ดูเหมือนว่าจะถูกสร้างขึ้นน้อยกว่าค่าอื่น ๆ คือ 0 และ 255)
leviathanbadger

ขอบคุณ ความน่าจะเป็นของฉันเป็นสนิม เมื่อดูที่ชุดคำสั่ง GCN แล้วสิ่งนี้ควรจะเร็วบนฮาร์ดแวร์รุ่นใหม่เนื่องจากสนับสนุนการดำเนินการบิตฟิลด์โดยตรงในชุดคำสั่ง การทดสอบที่ฉันทำบนฮาร์ดแวร์รุ่นเก่า
Spatial

73

การใช้งานของ Gustavson ใช้พื้นผิว 1D

ไม่มันไม่ใช่ตั้งแต่ปี 2005 เป็นเพียงแค่ผู้คนยืนยันที่จะดาวน์โหลดเวอร์ชันเก่า รุ่นที่อยู่ในลิงค์ที่คุณให้ไว้จะใช้พื้นผิว 2D 8 บิตเท่านั้น

เวอร์ชันใหม่โดย Ian McEwan จาก Ashima และตัวฉันเองไม่ได้ใช้พื้นผิว แต่ทำงานที่ความเร็วประมาณครึ่งหนึ่งบนแพลตฟอร์มเดสก์ท็อปทั่วไปที่มีแบนด์วิธพื้นผิวจำนวนมาก บนแพลตฟอร์มมือถือรุ่นที่ไม่มีพื้นผิวนั้นอาจเร็วกว่าเพราะพื้นผิวมักจะเป็นคอขวดที่สำคัญ

แหล่งเก็บข้อมูลที่เราดูแลอย่างแข็งขันคือ:

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

คอลเลกชันของเสียงรบกวนทั้งแบบที่เป็นพื้นผิวและแบบใช้พื้นผิวอยู่ที่นี่ (ใช้พื้นผิว 2D เท่านั้น):

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

หากคุณมีคำถามใด ๆ โปรดส่งอีเมลถึงฉันโดยตรง (สามารถพบที่อยู่อีเมลของฉันในclassicnoise*.glslแหล่งที่มา)


4
ใช่การใช้งานที่ฉันอ้างถึงรหัสของคุณบน davidcornette.com ที่ @dep เชื่อมโยงใช้พื้นผิว 1D: glBindTexture(GL_TEXTURE_1D, *texID);ฯลฯ ไม่ชัดเจนว่าคุณหมายถึง "ลิงก์ที่คุณให้" เนื่องจากคุณอ้างจากคำตอบของฉัน แต่คำตอบนั้นไม่ได้เชื่อมโยงกับการใช้งานของคุณ ฉันจะอัปเดตคำตอบของฉันเพื่อชี้แจงสิ่งที่ฉันอ้างถึงและสะท้อนถึงข้อมูลใหม่ที่คุณได้รับ การทำให้คนเป็น "ยืนยัน" ในการดาวน์โหลดเวอร์ชันเก่าเป็นการบิดเบือนที่ไม่ให้เครดิตคุณ
LarsH

1
ป.ล. คุณอาจต้องการเขียนถึง David Cornette (เขามีข้อมูลติดต่อที่davidcornette.com ) และขอให้เขาเปลี่ยนลิงค์ของเขาในdavidcornette.com/glsl/links.htmlเพื่อเชื่อมโยงไปยัง repo แหล่งที่มาของคุณ ฉันจะส่งอีเมลถึงเขาด้วย
LarsH

1
PPS คุณช่วยอธิบายได้ไหมว่าเวอร์ชั่นใดที่ใช้พื้นผิว 2D 8 บิตเท่านั้น? เสียงเหมือนมันอาจจะเป็นตัวเลือกที่ดีสำหรับบางแพลตฟอร์ม ...
LarsH

31

เสียงทอง

// Gold Noise ©2015 dcerisano@standard3d.com
// - based on the Golden Ratio
// - uniform normalized distribution
// - fastest static noise generator function (also runs at low precision)

float PHI = 1.61803398874989484820459;  // Φ = Golden Ratio   

float gold_noise(in vec2 xy, in float seed){
       return fract(tan(distance(xy*PHI, xy)*seed)*xy.x);
}

ดู Gold Noise ในเบราว์เซอร์ของคุณตอนนี้!

ป้อนคำอธิบายรูปภาพที่นี่

ฟังก์ชันนี้ปรับปรุงการกระจายแบบสุ่มบนฟังก์ชันปัจจุบันในคำตอบ @appas ณ วันที่ 9 กันยายน 2017:

ป้อนคำอธิบายรูปภาพที่นี่

ฟังก์ชั่น @appas ยังไม่สมบูรณ์เนื่องจากไม่มีการจัดหาเมล็ดพันธุ์ (uv ไม่ใช่เมล็ด - เหมือนกันสำหรับทุกเฟรม) และไม่ทำงานกับชิปเซ็ตที่มีความแม่นยำต่ำ เสียงทองจะทำงานที่ความแม่นยำต่ำโดยค่าเริ่มต้น (เร็วกว่ามาก)


ขอขอบคุณที่โพสต์สิ่งนี้ คุณจะลองโพสต์เวอร์ชั่นที่รันได้หรือไม่เช่นที่ shadertoy.com เพื่อให้ผู้คนสามารถทดลองใช้ในเบราว์เซอร์ได้
LarsH

@snb Shadertoy.com กำลังได้รับการบำรุงรักษาในเดือนนี้มีความอดทน นอกจากนี้ฉันยังบันทึกไว้อย่างชัดเจนถึงข้อกำหนดสำหรับค่าเมล็ดที่ไม่มีเหตุผลในรหัสที่นั่น เนื่องจากเสียงทองส่งคืนสเกลาร์การสร้างเวกเตอร์ด้วยมันเล็กน้อยและบันทึกไว้ในรหัสด้วย
Dominic Cerisano

7
ฉันไม่คิดว่ามันจะแตกต่างจากฟังก์ชั่นเสียงรบกวนอื่น ๆ อะไรที่คุณพิสูจน์ว่ามีคุณสมบัติพิเศษ เพียงเพราะคุณใช้ตัวเลขจำนวนอตรรกยะไม่ได้ทำให้เป็นพิเศษ
M.kazem Akhgary

2
@Dominic: "มันมีการกระจายที่เหนือกว่าไปยังฟังก์ชั่นที่คล้ายกัน": นี่จะต้องมีการพิสูจน์ ผิวสีแทน () เป็นสิ่งที่ไม่ดี ทั้ง tan () ใกล้ pi / 2 และ sqrt () ใกล้ศูนย์มีแนวโน้มที่จะให้ผลลัพธ์ที่แตกต่างกันในฮาร์ดแวร์ที่แตกต่างกันเนื่องจากเศษส่วน (ไม่ใช่เชิงเส้น * ใหญ่) ทั้งหมดใช้บิตที่มีนัยสำคัญน้อยกว่า ค่าอินพุตที่น้อยหรือสูงจะส่งผลกระทบเช่นกัน นอกจากนี้การเปลี่ยนแปลงบิตอาจแตกต่างกันมากเกินไปขึ้นอยู่กับสถานที่
Fabrice NEYRET

2
หมายเหตุ: ปัจจุบัน GLSL มีจำนวนเต็มดังนั้นจึงไม่มีเหตุผลใดที่จะไม่ใช้เครื่องกำเนิดแฮชแบบ "ร้ายแรง" อีกต่อไปเมื่อต้องการการกระจายคุณภาพ (และการเปลี่ยนแปลง) ด้วยการแสดงที่คล้ายกัน (ยกเว้นอุปกรณ์ที่ต่ำมาก)
Fabrice NEYRET

12

นอกจากนี้ยังมีการนำไปใช้งานที่ดีที่อธิบายไว้ที่นี่โดย McEwan และ @StefanGustavson ซึ่งดูเหมือนว่าเสียง Perlin แต่ "ไม่ต้องการการตั้งค่าใด ๆ เช่นไม่ใช่พื้นผิวหรือชุดอาร์เรย์เพียงแค่เพิ่มลงในซอร์สโค้ด shader ของคุณแล้วโทรไปที่ใดก็ได้"

มีประโยชน์มากโดยเฉพาะอย่างยิ่งเนื่องจากการใช้งานก่อนหน้าของ Gustavson ซึ่ง @dep ที่เชื่อมโยงใช้ใช้พื้นผิว 1D ซึ่งไม่ได้รับการสนับสนุนใน GLSL ES (ภาษา shader ของ WebGL)


1
นี่คือคำตอบที่ดีที่สุดสำหรับ OP ของ b) คำขอประเภทเสียงรบกวน! นี่คือการเชื่อมโยงโดยตรงgithub.com/ashima/webgl-noise มีรุ่น 2d, 3d และ 4d พร้อมเป็นรหัส GLSL 120
user362515

3

ใช้สิ่งนี้:

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 แรนด์ () แบบมาตรฐานสำหรับ Canonical สำหรับ OpenGL ES 2.0


ฉันอ่านบทความ แต่ยังไม่แน่ใจว่าเป็น 3.14 ในmodการประมาณของ pi หรือไม่?
Kaan E.

2

เพิ่งค้นพบเสียงรบกวน 3 มิติสำหรับ 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

1
Gold Noise (ด้านบน) นั้นเร็วที่สุดอย่างเห็นได้ชัดเนื่องจากมีการดำเนินการน้อยกว่ามากและทำการแฮชเพียงครั้งเดียว - อันนี้เรียกว่า hash fuction 8 ครั้งในขณะที่ดำเนินการเชิงเส้นเชิงซ้อนซ้อน (lerps) นอกจากนี้อันนี้มีการกระจายที่ด้อยกว่าโดยเฉพาะที่ความแม่นยำต่ำ
Dominic Cerisano

1
โอ้จุดที่ดีมันเป็นกราฟประเภทเสียง perlin จาก shadertoh โดย Inigo Quilez Nice code โดมินิคป่วยตรวจสอบ l8r
com.prehensible

@ Fabrice คุณดูเหมือนจะไม่เข้าใจคำถามของ OP คำตอบของฉันรหัสของฉันหรือความคิดเห็นของฉัน .. เสียงทองนั้นมีความต่อเนื่องตามคำจำกัดความของ OP - มันยอมรับยูวีและเมล็ดพืชและพิสูจน์ด้วยการให้ shader ทุกอย่างเกี่ยวกับความคิดเห็นของคุณผิด คุณใช้ฟังก์ชันแฮชที่สับสนด้วยฟังก์ชั่นสุ่มเสียงรบกวนหลอก พวกเขาไม่เหมือนกัน ฟังก์ชั่นเสียงรบกวนนั้นไม่มีข้อกำหนดในการสร้างตัวระบุเฉพาะเช่นฟังก์ชันแฮช (จุดที่แท้จริงของการแฮช)
Dominic Cerisano

ได้โปรดได้โปรดโปรดโดมินิคอ่านเพิ่มเติมและเรียนรู้เพิ่มเติมก่อนอ้างสิทธิ์เกี่ยวกับคำศัพท์ที่คุณคิดว่าคุณเข้าใจในขณะที่ไม่ใช่กรณี ไม่เพียง แต่คำศัพท์เหล่านี้มีความแม่นยำอย่างสมบูรณ์และให้คำจำกัดความเป็นอย่างดีรวมทั้งฉันทำงานในสาขานี้ แต่ OP ยังพิสูจน์ให้เห็นว่าเขาเข้าใจเงื่อนไขโดยตัวอย่างที่เขาให้มา คำแนะนำ: "ต่อเนื่อง" + "เสียง" + "ชอบ Perlin" en.wikipedia.org/wiki/Perlin_noise
Fabrice NEYRET

ต่อเนื่องเป็นกรณีของการเพิ่มข้อประโยคฟังก์ชั่นเสียงรบกวนหลายวงและลดลงหลังจากที่วิธีการบางอย่างเพราะการปัดเศษบิตโดยเฉพาะอย่างยิ่งสำหรับกราฟิก พวกมันเป็นเพียงการติดต่อสื่อสารจากคุณใช้เวลาของคุณสำหรับการวิจัยที่สำคัญ
com.prehensible

1

รูปแบบตรงและขรุขระของ 1d Perlin โดยหลักแล้วจะเป็น lfo zigzag แบบสุ่ม

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 บนเว็บไซต์กวดวิชาเจ้าของ shadertoy inigo quilez perlin และ voronoi และอื่น ๆ เขามีการใช้งานและรหัสที่รวดเร็วสำหรับพวกเขา


1

แฮช: ทุกวันนี้ webGL2.0 มีอยู่ดังนั้นจำนวนเต็มจึงมีอยู่ใน (w) GLSL -> สำหรับแฮชแบบพกพาที่มีคุณภาพ (ในราคาใกล้เคียงกับแฮชแบบลอยตัวที่น่าเกลียด) ตอนนี้เราสามารถใช้เทคนิคการแฮช "ร้ายแรง" ได้ IQ นำไปใช้ใน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));
}

0

โปรดดูตัวอย่างด้านล่างวิธีเพิ่มเสียงสีขาวให้กับพื้นผิวที่แสดงผล การแก้ปัญหาคือการใช้พื้นผิวที่สอง: เสียงที่เป็นต้นฉบับและเสียงสีขาวบริสุทธิ์เช่นนี้: เสียงสีขาวของ wiki

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);

0

ฉันแปลหนึ่งในการนำ 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);
}

ฉันแปลจากภาคผนวก B จากบทที่ 2 ของ Ken Perlin's Noise Hardware ที่แหล่งข้อมูลนี้:

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

นี่คือร่มเงาสาธารณะที่ฉันทำกับ Shader 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

ฉันขอแนะนำหนังสือของ shaders เพราะมันไม่เพียง แต่ให้คำอธิบายที่ดีแบบโต้ตอบของเสียง แต่แนวคิด shader อื่น ๆ เช่นกัน

แก้ไข:

อาจสามารถปรับโค้ดที่แปลให้เหมาะสมโดยใช้ฟังก์ชันการเร่งด้วยฮาร์ดแวร์ที่มีอยู่ใน GLSL จะอัปเดตโพสต์นี้ถ้าฉันลงเอยด้วยการทำเช่นนี้


นอกจากนี้ฉันค่อนข้างแน่ใจว่า Perlin / Simplex Noise ยังคงหลอกหลอก จากสิ่งที่ฉันจำได้สิ่งที่น่าสนใจคือคุณสามารถเลเยอร์และ "ซูม" เสียงในระดับต่าง ๆ เพื่อให้ดูเหมือนราบรื่นมาก อย่าอ้างฉันในสิ่งนั้น แต่มีบางอย่างที่ต้องคิด
Andrew Meservy

@Zibri น่าเสียดายที่ฉันไม่คุ้นเคยกับคำสั่ง C หรือ. sh ตรง แต่ดูเหมือนว่าฟังก์ชั่นนี้เป็นเพียงตัวสร้างตัวเลขแบบหลอกและไม่ใช่ฟังก์ชั่นเสียงรบกวน โปรดทราบว่า glsl pixel shaders ทำงานโดยตรงบน gpu คุณจะไม่สามารถเข้าถึงไลบรารีเพิ่มเติมหรือความสามารถของ CPU ที่อาจมีอยู่ใน C.
Andrew Meservy

Book Of Shaders มีคำอธิบายที่ดีเกี่ยวกับวิธีที่ Simplex Noise เป็น Perlin Noise รุ่นที่มีประสิทธิภาพมากขึ้นเนื่องจากการบิดเบือนตารางและการคำนวณที่จำเป็นน้อยลงต่อจุด คุ้มค่ากับการอ่านอย่างแน่นอน
Andrew Meservy

ดูบทเกี่ยวกับการเคลื่อนไหวเศษส่วนสีน้ำตาลและ voronoise
Andrew Meservy

Andrew Meservy: ไม่จำเป็นต้องใช้ห้องสมุด ... ฟังก์ชั่นเสียงรบกวนของฉันนั้นง่ายมาก: 2 64 บิต int คือสถานะ x (n) และ x (n-1) สูตรที่ง่ายและรวดเร็วคือ x (n + 1) = ROTR ( x (n) + x (n-1), 8) หากคุณโคลนคอมไพล์ของฉันและเรียกใช้คุณจะเห็นมันในการดำเนินการ
Zibri
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.