Các chức năng ngẫu nhiên / tiếng ồn cho GLSL


179

Vì các nhà cung cấp trình điều khiển GPU thường không bận tâm triển khai noiseXtrong GLSL, tôi đang tìm một bộ chức năng tiện ích "con dao quân đội ngẫu nhiên đồ họa" , tốt nhất là được tối ưu hóa để sử dụng trong các trình tạo bóng GPU. Tôi thích GLSL, nhưng mã bất kỳ ngôn ngữ nào sẽ làm cho tôi, tôi ổn với việc tự dịch nó sang GLSL.

Cụ thể, tôi mong đợi:

a) Các hàm giả ngẫu nhiên - Phân phối N chiều, phân bố đồng đều trên [-1,1] hoặc hơn [0,1], được tính từ hạt M chiều (lý tưởng là bất kỳ giá trị nào, nhưng tôi ổn với hạt giống bị hạn chế to, giả sử, 0..1 để phân phối kết quả thống nhất). Cái gì đó như:

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) Tiếng ồn liên tục như Tiếng ồn Perlin - một lần nữa, N-chiều, + - phân phối đồng đều, với tập hợp các giá trị bị ràng buộc và, nhìn tốt (một số tùy chọn để định cấu hình bề ngoài như mức Perlin cũng có thể hữu ích). Tôi mong đợi chữ ký như:

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

Tôi không quan tâm nhiều đến lý thuyết tạo số ngẫu nhiên, vì vậy tôi rất háo hức tìm kiếm một giải pháp được tạo sẵn , nhưng tôi cũng đánh giá cao các câu trả lời như "đây là một rand 1D rất tốt, hiệu quả và để tôi giải thích bạn làm thế nào để tạo một rand N-chiều tốt () trên đầu trang của nó ... " .

Câu trả lời:


263

Đối với các công cụ tìm kiếm giả đơn giản, tôi sử dụng oneliner mà tôi tìm thấy trên internet ở đâu đó:

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

Bạn cũng có thể tạo kết cấu nhiễu bằng bất kỳ PRNG nào bạn thích, sau đó tải nó lên theo cách thông thường và lấy mẫu các giá trị trong trình đổ bóng của bạn; Tôi có thể khai thác một mẫu mã sau nếu bạn muốn.

Ngoài ra, hãy xem tệp này để biết các triển khai GLSL của nhiễu Perlin và Simplex, của Stefan Gustavson.


14
Làm thế nào để bạn sử dụng vec2 co? nó là phạm vi? hạt giống?
Ross

12
Cảnh giác với các shader mảnh dấu phẩy động có độ chính xác thấp với thuật toán này (ví dụ: ARM Mali của S3): stackoverflow.com/questions/11293628/ . Các github.com/ashima/webgl-noise dự án dường như không có lowp vấn đề này.
PT

4
FWIW, chức năng được mô tả ở đây được thảo luận chi tiết hơn ở đây .
Loomchild

3
FYI: Sự phân phối của chức năng đó thật kinh khủng.
Tara

3
Tôi là người mới trong GLSL, có ai có thể giải thích tại sao co.xyđược sử dụng, thay vì cokhông?
kelin

83

Nó xảy ra với tôi rằng bạn có thể sử dụng hàm băm số nguyên đơn giản và chèn kết quả vào mantissa của float. IIrc, thông số GLSL đảm bảo các số nguyên không dấu 32 bit và biểu diễn float nhị phân IEEE32 để nó có thể di động hoàn hảo.

Tôi đã thử cái này ngay bây giờ. Kết quả rất tốt: nó trông giống hệt như tĩnh với mọi đầu vào tôi đã thử, không có mẫu nào có thể nhìn thấy cả. Ngược lại, đoạn sin / fract phổ biến có các đường chéo khá rõ ràng trên GPU của tôi với cùng các đầu vào.

Một nhược điểm là nó yêu cầu GLSL v3.30. Và mặc dù nó có vẻ đủ nhanh, nhưng tôi chưa định lượng được hiệu suất của nó. Trình phân tích Shader của AMD tuyên bố 13,33 pixel mỗi đồng hồ cho phiên bản vec2 trên HD5870. Tương phản với 16 pixel mỗi đồng hồ cho đoạn hình sin / fract. Vì vậy, nó chắc chắn là chậm hơn một chút.

Đây là triển khai của tôi. Tôi đã để nó trong nhiều hoán vị của ý tưởng để làm cho nó dễ dàng hơn để lấy được các chức năng của riêng bạn từ đó.

/*
    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 );
}

Ảnh chụp màn hình:

Đầu ra ngẫu nhiên (vec3) trong static.frag

Tôi đã kiểm tra ảnh chụp màn hình trong một chương trình chỉnh sửa hình ảnh. Có 256 màu và giá trị trung bình là 127, nghĩa là phân phối đồng đều và bao phủ phạm vi dự kiến.


17
+1 cho một ý tưởng tốt và thực hiện. Tôi sẽ đặt câu hỏi cho rằng vì có 256 màu và giá trị trung bình là 127, phân phối phải đồng nhất (theo nghĩa chặt chẽ). Nó có thể là đồng phục, nhưng tôi không nghĩ chúng ta biết điều đó. Ví dụ: phân phối đường cong chuông có thể có cùng số lượng và màu trung bình, nhưng sẽ không đồng nhất.
LarsH

Bỏ phiếu này vì lý do được đưa ra bởi @LarsH.
Autumnsault

Chà, nó đủ tốt cho hầu hết các ứng dụng không cần sự đồng nhất. :-)
itmuckel

5
Nó dường như rất đồng đều, theo nhận thức của tôi về biểu đồ .... Tôi nói rằng nó đủ tốt cho hầu hết các ứng dụng cũng cần sự đồng nhất. (Các giá trị duy nhất dường như được tạo ra ít hơn các giá trị khác là 0 và 255)
leviathanbadger

Cảm ơn. Xác suất của tôi là gỉ. Đã xem xét tập lệnh GCN, điều này sẽ rất nhanh trên phần cứng mới hơn vì chúng trực tiếp hỗ trợ các hoạt động của bitfield trong các tập lệnh của chúng. Các thử nghiệm tôi đã chạy trên phần cứng cũ.
Không gian

73

Việc triển khai của Gustavson sử dụng kết cấu 1D

Không, không, kể từ năm 2005. Chỉ là mọi người khăng khăng tải xuống phiên bản cũ. Phiên bản trên liên kết bạn cung cấp chỉ sử dụng họa tiết 2D 8 bit.

Phiên bản mới của Ian McEwan của Ashima và bản thân tôi không sử dụng kết cấu, nhưng chạy với tốc độ khoảng một nửa trên các nền tảng máy tính để bàn thông thường với nhiều băng thông kết cấu. Trên nền tảng di động, phiên bản không họa tiết có thể nhanh hơn vì kết cấu thường là một nút cổ chai đáng kể.

Kho lưu trữ nguồn được duy trì tích cực của chúng tôi là:

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

Một bộ sưu tập của cả hai phiên bản nhiễu không kết cấu và sử dụng kết cấu có ở đây (chỉ sử dụng họa tiết 2D):

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

Nếu bạn có bất kỳ câu hỏi cụ thể nào, vui lòng gửi email trực tiếp cho tôi (địa chỉ email của tôi có thể được tìm thấy trong các classicnoise*.glslnguồn.)


4
Có, việc triển khai mà tôi đang đề cập đến, mã của bạn trên davidcornette.com mà @dep liên kết đến, có sử dụng kết cấu 1D không, glBindTexture(GL_TEXTURE_1D, *texID);v.v. nhưng câu trả lời đó không liên kết đến việc thực hiện của bạn. Tôi sẽ cập nhật câu trả lời của mình để làm rõ những gì tôi đang đề cập và phản ánh thông tin mới mà bạn đã cung cấp. Đặc trưng của mọi người là "khăng khăng" khi tải xuống phiên bản cũ là một biến dạng không làm bạn tin tưởng.
LarsH

1
PS Bạn có thể muốn viết thư cho David Cornette (anh ấy có thông tin liên hệ tại davidcornette.com ) và yêu cầu anh ấy thay đổi liên kết của mình trên davidcornette.com/glsl/links.html để liên kết với repo nguồn của bạn. Tôi cũng sẽ gửi email cho anh ấy.
LarsH

1
PPS Bạn có thể làm rõ, phiên bản nào chỉ sử dụng họa tiết 2D 8 bit? Âm thanh như nó có thể là một lựa chọn tốt cho một số nền tảng nhất định ...
LarsH

31

Tiếng ồn vàng

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

Xem Tiếng ồn vàng trong trình duyệt của bạn ngay bây giờ!

nhập mô tả hình ảnh ở đây

Hàm này đã cải thiện phân phối ngẫu nhiên so với hàm hiện tại trong câu trả lời của @appas kể từ ngày 9 tháng 9 năm 2017:

nhập mô tả hình ảnh ở đây

Hàm @appas cũng không đầy đủ, do không có hạt giống được cung cấp (uv không phải là hạt giống - cho mọi khung hình) và không hoạt động với các chipset có độ chính xác thấp. Tiếng ồn vàng chạy ở độ chính xác thấp theo mặc định (nhanh hơn nhiều).


Cảm ơn đã đăng bài này. Bạn có xem xét việc đăng một phiên bản có thể chạy được không, ví dụ như tại shadertoy.com, để mọi người có thể dùng thử trên trình duyệt?
LarsH

@snb Shadertoy.com đang được bảo trì trong tháng này, hãy kiên nhẫn. Ngoài ra tôi đã ghi lại rõ ràng yêu cầu về giá trị hạt giống phi lý trong mã ở đó. Vì nhiễu vàng trả về một vô hướng, việc xây dựng các vectơ với nó là không đáng kể và cũng được ghi lại trong mã.
Đaminh Cerisano

7
Tôi không nghĩ rằng điều này là khác biệt so với các chức năng tiếng ồn khác. những gì bạn chứng minh rằng điều này có tính chất đặc biệt. chỉ vì bạn sử dụng một loạt các số vô tỷ không làm cho nó trở nên đặc biệt.
M.kazem Akhÿ

2
@Dominic: "Nó có phân phối vượt trội cho các chức năng tương tự": điều này đã được chứng minh. tan () là thực sự điều hòa. cả tan () gần pi / 2 và sqrt () gần 0 đều rất có khả năng tạo ra kết quả khác nhau trên các phần cứng khác nhau vì tất cả các phép chia (phi tuyến tính * lớn) đều dựa trên các bit ít quan trọng hơn. Giá trị đầu vào nhỏ hoặc cao cũng sẽ tác động đến nó. Ngoài ra, động lực học bit có thể thay đổi rất nhiều tùy thuộc vào vị trí.
Fabrice NEYRET

2
Lưu ý: Ngày nay GLSL có số nguyên, vì vậy không còn lý do nào để không sử dụng trình tạo hàm băm dựa trên "nghiêm trọng" khi cần phân phối chất lượng (và động lực học), với hiệu suất tương tự. (ngoại trừ các thiết bị rất thấp).
Fabrice NEYRET

12

Ngoài ra còn có một triển khai tốt đẹp được mô tả ở đây bởi McEwan và @StefanGustavson trông giống như tiếng ồn Perlin, nhưng "không yêu cầu bất kỳ thiết lập nào, tức là không kết cấu cũng như mảng thống nhất. Chỉ cần thêm nó vào mã nguồn shader của bạn và gọi nó bất cứ nơi nào bạn muốn".

Điều đó rất tiện dụng, đặc biệt là việc triển khai trước đó của Gustavson, mà @dep liên kết đến, sử dụng kết cấu 1D, không được hỗ trợ trong GLSL ES (ngôn ngữ đổ bóng của WebGL).


1
Đây là câu trả lời tốt nhất cho yêu cầu loại tiếng ồn b) của OP! Đây là một liên kết trực tiếp github.com/ashima/webgl-noise . Có các phiên bản 2d, 3d và 4d sẵn sàng dưới dạng mã GLSL 120.
dùng362515

3

Sử dụng cái này:

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

Đừng dùng cái này:

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

Bạn có thể tìm thấy lời giải thích trong phần Cải tiến cho GLSL rand () chính quy cho OpenGL ES 2.0


Tôi đọc lướt qua bài viết nhưng tôi vẫn không chắc chắn, là 3,14 trong modmột xấp xỉ của pi?
Kaan E.

2

Chỉ tìm thấy phiên bản tiếng ồn 3d cho GPU này, tất cả đều là phiên bản nhanh nhất hiện có:

#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
Tiếng ồn vàng (ở trên) rõ ràng là nhanh nhất, vì nó có ít hoạt động hơn và chỉ thực hiện một hàm băm - cái này gọi hàm băm của nó 8 lần, trong khi thực hiện phép nội suy tuyến tính lồng nhau (lerps). Ngoài ra, cái này có phân phối kém hơn đặc biệt là ở độ chính xác thấp.
Đaminh Cerisano

1
Ồ, điểm hay, đó là biểu đồ loại nhiễu perlin từ shadertoh của Inigo Quilez. Mã đẹp Dominic ill kiểm tra nó l8r
com.p Hiểu được

@Fabrice Bạn dường như không hiểu câu hỏi của OP, câu trả lời của tôi, mã của tôi hoặc nhận xét của tôi .. Tiếng ồn vàng liên tục theo định nghĩa của OP - nó chấp nhận uv và hạt giống và chứng minh bằng cách cung cấp một shader. Tất cả mọi thứ về nhận xét của bạn là sai. Bạn tiếp tục nhầm lẫn các hàm băm với các hàm nhiễu ngẫu nhiên giả. Chúng không giống nhau. Các hàm nhiễu không có yêu cầu tạo các mã định danh duy nhất như hàm băm (toàn bộ điểm băm thực tế).
Đaminh Cerisano

Xin vui lòng, xin vui lòng, Dominic, đọc thêm và tìm hiểu thêm trước khi yêu cầu những điều về các điều khoản bạn nghĩ rằng bạn hiểu trong khi đó không phải là trường hợp. Không chỉ các thuật ngữ này là hoàn toàn chính xác và được xác định rõ ràng trong lứa tuổi, cộng với tôi làm việc trong lĩnh vực này, nhưng OP cũng chứng minh rằng anh ta hiểu các thuật ngữ bằng các ví dụ mà anh ta đưa ra sau đó. Gợi ý: "liên tục" + "tiếng ồn" + "như Perlin". vi.wikipedia.org/wiki/Perlin_noir
Fabrice NEYRET

Liên tục là một trường hợp thêm một mệnh đề vòng lặp, nhiều hàm nhiễu lặp và suy giảm sau một cách nhất định vì làm tròn bit đặc biệt là cho đồ họa. Các bạn chỉ là một sự cố truyền thông từ bạn, hãy sử dụng thời gian của bạn cho nghiên cứu quan trọng.
com.p hiểu được

1

Một phiên bản thẳng, lởm chởm của 1d Perlin, về cơ bản là một lfo zigzag ngẫu nhiên.

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

Tôi cũng đã tìm thấy tiếng ồn 1-2-3-4d trên trang web hướng dẫn của chủ sở hữu shadertoy inigo quilez perlin, và voronoi, v.v., anh ta có đầy đủ các mã triển khai và mã cho họ.


1

hàm băm: Ngày nay webGL2.0 đã có nên số nguyên có sẵn trong (w) GLSL. -> đối với hàm băm di động chất lượng (với chi phí tương tự so với băm nổi xấu xí) giờ đây chúng ta có thể sử dụng các kỹ thuật băm "nghiêm trọng". IQ đã triển khai một số trong https://www.shadertoy.com/view/XlXcW4 (và hơn thế nữa)

Ví dụ:

  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

Vui lòng xem bên dưới một ví dụ về cách thêm nhiễu trắng vào kết cấu được hiển thị. Giải pháp là sử dụng hai kết cấu: tiếng ồn trắng nguyên bản và thuần túy, như thế này: tiếng ồn trắng 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";

Đoạn được chia sẻ chứa tham số uNatyFactor được cập nhật trên mỗi kết xuất bởi ứng dụng chính:

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

0

Tôi đã dịch một trong những triển khai Java của Ken Perlin sang GLSL và sử dụng nó trong một vài dự án trên ShaderToy.

Dưới đây là giải thích GLSL tôi đã làm:

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

Tôi đã dịch nó từ Phụ lục B từ Chương 2 của Phần cứng tiếng ồn của Ken Perlin tại nguồn này:

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

Đây là một sắc thái công khai tôi đã làm trên Shader Toy sử dụng chức năng tiếng ồn được đăng:

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

Một số nguồn tốt khác tôi tìm thấy về chủ đề tiếng ồn trong quá trình nghiên cứu của tôi bao gồm:

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_apers.pdf

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

Tôi đánh giá cao cuốn sách về shader vì nó không chỉ cung cấp một lời giải thích tương tác tuyệt vời về tiếng ồn, mà cả các khái niệm shader khác nữa.

BIÊN TẬP:

Có thể tối ưu hóa mã được dịch bằng cách sử dụng một số chức năng tăng tốc phần cứng có sẵn trong GLSL. Sẽ cập nhật bài viết này nếu tôi kết thúc việc này.


Ngoài ra, tôi khá chắc chắn rằng Perlin / Simplex Noise vẫn là giả ngẫu nhiên. Từ những gì tôi nhớ lại, điều thú vị là bạn có thể tạo lớp và "phóng to" tiếng ồn ở các mức khác nhau để làm cho nó có vẻ rất liền mạch. Đừng trích dẫn tôi về điều đó, nhưng một cái gì đó để suy nghĩ.
Andrew Meservy

@Zibri Thật không may, tôi không quen thuộc lắm với các lệnh C hoặc .sh thẳng. Nhưng có vẻ như hàm này chỉ đơn giản là một bộ tạo số giả ngẫu nhiên chứ không phải là hàm nhiễu. Ngoài ra, hãy nhớ rằng các shader pixel glsl chạy trực tiếp trên gpu. Bạn sẽ không có quyền truy cập vào bất kỳ thư viện hoặc khả năng CPU bổ sung nào có thể có trong C.
Andrew Meservy

Book Of Shader có một lời giải thích tuyệt vời về cách Simplex Noise là phiên bản hiệu quả hơn của Perlin Noise do làm lệch lưới và tính toán ít cần thiết hơn cho mỗi điểm. Chắc chắn giá trị đọc.
Andrew Meservy

cũng xem các chương về chuyển động của fractal brownian và voronoise
Andrew Meservy

Andrew Meservy: không cần thư viện ... hàm tiếng ồn của tôi rất đơn giản: 2 int 64 bit là trạng thái x (n) và x (n-1). Công thức đơn giản và nhanh là x (n + 1) = ROTR ( x (n) + x (n-1), 8). nếu bạn sao chép git của tôi và chạy nó, bạn sẽ thấy nó hoạt động.
Zibri
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.