Bu GLSL rand () tek astarın kökeni nedir?


95

Bu sözde rastgele sayı oluşturucuyu, burada ve orada web'de belirtilen gölgelendiricilerde kullanmak için gördüm :

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

Çeşitli şekillerde "kanonik" veya "web'de bir yerde bulduğum tek satırlık" olarak adlandırılır.

Bu işlevin kökeni nedir? Sabit değerler göründükleri kadar gelişigüzel mi yoksa seçimlerinde bazı sanat var mı? Bu işlevin yararları hakkında herhangi bir tartışma var mı?

DÜZENLEME: Bu işleve rastladığım en eski referans , Şubat '08'den gelen bu arşivdir , orijinal sayfa şu anda web'den kaldırılıyor. Ama orada başka hiçbir yerde olduğundan daha fazla tartışma yok.


Prosedürel olarak oluşturulmuş arazi oluşturmak için kullanılan bir gürültü işlevidir. buna benzer en.wikipedia.org/wiki/Perlin_noise
Shai UI

Yanıtlar:


42

Çok ilginç soru!

Cevabı yazarken bunu anlamaya çalışıyorum :) İlk önce onunla oynamanın kolay bir yolu: http://www.wolframalpha.com/input/?i=plot%28+mod%28+sin%28x*12.9898 +% 2B + y * 78.233% 29 + * + 43758.5453% 2C1% 29x% 3D0..2% 2C + y% 3D0..2% 29

O zaman burada ne yapmaya çalıştığımızı düşünelim: İki giriş koordinatı x, y için bir "rastgele sayı" döndürürüz. Şimdi bu rastgele bir sayı değil. Aynı x, y'yi her girdiğimizde aynıdır. Bu bir hash işlevi!

Fonksiyonun yaptığı ilk şey 2d'den 1d'ye gitmektir. Bu kendi başına ilginç değil, ancak sayılar tipik olarak tekrarlamayacak şekilde seçildi. Ayrıca orada bir kayan nokta eklememiz var. Y veya x'ten birkaç bit daha olacaktır, ancak sayılar doğru seçilebilir, böylece bir karışım yapar.

Sonra bir kara kutu sin () işlevini örnekliyoruz. Bu, uygulamaya büyük ölçüde bağlı olacaktır!

Son olarak, kesiri çarpıp alarak sin () uygulamasındaki hatayı güçlendirir.

Genel durumda bunun iyi bir hash fonksiyonu olduğunu düşünmüyorum. Sin (), sayısal olarak GPU'da bir kara kutudur. Hemen hemen her hash işlevini alıp dönüştürerek çok daha iyi bir tane oluşturmak mümkün olmalıdır. İşin zor kısmı, cpu hashinginde kullanılan tipik tamsayı işlemini float (yarım veya 32bit) veya sabit nokta işlemlerine dönüştürmektir, ancak bu mümkün olmalıdır.

Yine, bunun bir hash fonksiyonu olarak gerçek problemi, sin () 'in bir kara kutu olmasıdır.


1
Bu, kökeni hakkındaki soruyu yanıtlamaz, ancak bunun gerçekten cevap verilebilir olduğunu düşünmüyorum. Bu cevabı açıklayıcı grafik nedeniyle kabul edeceğim.
Grumdrig

20

Kökeni muhtemelen kağıttır: "y = [(a + x) sin (bx)] mod 1 yardımıyla rastgele sayıların üretilmesi üzerine", WJJ Rey, 22. Avrupa İstatistikçiler Toplantısı ve 7. Vilnius Olasılık Teorisi Konferansı ve Matematiksel İstatistik, Ağustos 1998

DÜZENLEME: Bu makalenin bir kopyasını bulamadığım için ve "TestU01" referansı net olmayabilir, işte sözde C'deki TestU01'de açıklanan şema:

#define A1 ???
#define A2 ???
#define B1 pi*(sqrt(5.0)-1)/2
#define B2 ???

uint32_t n;   // position in the stream

double next() {
  double t = fract(A1     * sin(B1*n));
  double u = fract((A2+t) * sin(B2*t));
  n++;
  return u;
} 

burada önerilen tek sabit değer B1'dir.

Bunun bir akış için olduğuna dikkat edin. 1B karma 'n'ye dönüştürme tamsayı ızgarası olur. Tahminime göre birisi bunu gördü ve 't'yi basit bir f (x, y) fonksiyonuna dönüştürdü. Yukarıdaki orijinal sabitleri kullanarak şunu verir:

float hash(vec2 co){
  float t = 12.9898*co.x + 78.233*co.y; 
  return fract((A2+t) * sin(t));  // any B2 is folded into 't' computation
}

3
Gerçekten çok ilginç! Google Kitaplar'da hem ona hem de dergiye atıfta bulunan bir makale buldum , ancak konuşmanın veya makalenin kendisinin dergiye dahil edilmediği anlaşılıyor.
Grumdrig

1
Ayrıca, sorduğum fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * (co.xy + vec2(43758.5453, SOMENUMBER))işlevin makalenin ilgili olduğu işleve uymak için geri dönmesi gerektiği başlıktan anlaşılıyor .
Grumdrig

Bu gerçekten de fonksiyonun kullanımının kökeni Ve eğer bir şey daha, sihirli sayılar kökeni meselesi (seçimi ave b) üzerinden kullanılan ve kalıntıların üzerinde, ancak alıntı kağıt kullanılmış olabilir.
Grumdrig

Artık kağıdı da bulamıyorum. (düzenleme: yukarıda bağlantılı aynı makale)
MB Reynolds

Cevabı daha fazla bilgi ile güncelleyin.
MB Reynolds

8

sabit değerler, özellikle çok büyük olmaları ve asal sayılardan birkaç ondalık uzakta olmaları nedeniyle keyfidir.

4000 ile çarpılan yüksek genlikli sinüsün 1'in üzerindeki bir modül periyodik bir fonksiyondur. 4000 ile çarpıldığı ve iç çarpım tarafından bir açıyla döndürüldüğü için çok küçük yapılmış bir pencere panjuru veya oluklu metal gibidir.

fonksiyon 2-D olduğu için, iç çarpım periyodik fonksiyonu X ve Y eksenine göre eğik olarak döndürme etkisine sahiptir. Yaklaşık 13/79 oranında. Verimsizdir, aslında aynı şeyi (13x + 79y) sinüs yaparak elde edebilirsiniz, bu da düşündüğüm şeyi daha az matematikle başaracaktır ..

Fonksiyonun periyodunu hem X hem de Y'de bulursanız, tekrar basit bir sinüs dalgası gibi görünmesi için onu örnekleyebilirsiniz.

İşte grafiğe yakınlaştırılmış bir resmi

Kökeni bilmiyorum ama diğerlerine benziyor, eğer onu düzenli aralıklarla grafiklerde kullanırsanız hareli desenler üretme eğiliminde olur ve sonunda tekrar döndüğünü görebilirsiniz.


Ancak GPU'larda X ve Y 0,1 aralığındadır ve grafiğinizi değiştirirseniz bu çok daha rastgele görünür. Bunun bir cümle gibi geldiğini biliyorum ama aslında bir soru çünkü matematik eğitimim 18 yaşında bitti.
Strings

Biliyorum, sadece yakınlaştırdım, böylece rastgele işlevin bu formda olduğunu görebiliyorsunuz, ancak sırtların çok hızlı değişiyor olması dışında, değişiklikleri görmek için küçük yakınlaştırmanız gerek ... puan aldığınızı hayal edebilirsiniz sırtlarda 1'den 1'e x ve y değerleri için 0'dan 1'e kadar oldukça rastgele sayılar verecektir.
aliential

Oh, anlıyorum ve bu, özünde bir günah işlevi kullanan herhangi bir rastgele sayı üretimi için çok mantıklı görünüyor
Dizeler

2
bu aslında doğrusal bir zikzaktır ve günahın küçük bir çeşitleme eklediği varsayılır, sanki biri önünüzde bir kart destesini birden 10'a çok hızlı bir şekilde döndürüyor ve sizin denemeniz gerekiyormuş gibi Sonunda kartlardan bir sayı kalıbı alırsa, bunlar rasgele sayılar olurdu, çünkü kartların ne kadar hızlı döndüğüne göre tam bir eşzamanlamayla kartları seçerek sadece bir desen elde edebilecek kadar hızlı titreşirdi.
aliential

Sadece bir not, bunu yapmak daha hızlı olmaz (13x + 79y)çünkü dot(XY, AB)onun nokta ürünü olarak, tarif tam olarak ne yapacak hangix,y dot 13, 79 = (13x + 79y)
whn

1

Belki tekrar etmeyen kaotik bir haritalamadır, o zaman birçok şeyi açıklayabilir, ama aynı zamanda sadece büyük sayılarla keyfi bir manipülasyon olabilir.

DÜZENLEME: Temel olarak, frak (sin (x) * 43758.5453) fonksiyonu basit bir hash benzeri fonksiyondur, sin (x) -1 ile 1 arasında pürüzsüz sin enterpolasyonu sağlar, bu nedenle sin (x) * 43758.5453 - 43758.5453 ila 43758.5453. Bu oldukça büyük bir aralıktır, bu nedenle x'teki küçük adım bile sonuçta büyük adım ve kesirli kısımda gerçekten büyük varyasyon sağlayacaktır. -0.99 ... ila 0.999 ... aralığındaki değerleri elde etmek için "frak" gereklidir. Şimdi, hash fonksiyonu gibi bir şeye sahip olduğumuzda, vektörden üretim hashı için fonksiyon yaratmalıyız. En basit yol, giriş vektörünün herhangi bir y bileşeni için ayrı ayrı "hash" çağrısı yapmaktır. Ama sonra simetrik değerlere sahip olacağız. Yani, vektörden bir değer almalıyız, yaklaşım rastgele bir vektör bulmak ve bu vektöre "nokta" çarpımı bulmaktır, işte başlıyoruz: fract (sin (nokta (co.xy, vec2 (12.9898,78.233))) * 43758.5453); Ayrıca, seçilen vektöre göre, "nokta" çarpım hesaplandıktan sonra uzunluğu "sin" fonksiyonunun birkaç peroidine sahip olacak şekilde uzun olmalıdır.


ama sonra 4e5 de çalışmalı, neden 43758.5453 sihirli sayısının olduğunu anlamıyorum. (ayrıca, rand (0) = 0'dan kaçınmak için x'i bazı kesirli sayılarla dengeleyebilirim.
Fabrice NEYRET

1
4e5 ile kesirli bitlerin çok fazla varyasyonunu elde edemeyeceğinizi düşünüyorum, bu size her zaman aynı değeri verecektir. Bu nedenle, iki koşulun yeterince büyük olması ve fraksiyonel parçaların yeterince iyi varyasyonuna sahip olması gerekir.
Roman

"sana hep aynı değeri verecek" derken ne demek istiyorsun? (Her zaman aynı rakamları alacağını kastediyorsanız, ilk önce hala kaotiktirler, ikincisi, float 10 ^ p olarak değil m * 2 ^ p olarak saklanır, bu nedenle * 4e5 hala bitleri karıştırır).
Fabrice NEYRET

4 * 10 ^ 5 sayısının üstel bir temsilini yazdığınızı sanıyordum, bu nedenle sin (x) * 4e5 size çok kaotik bir sayı vermeyecek. Sin dalgasından gelen kesirli bitlerin size de iyi bir chatoic vereceğine katılıyorum.
Roman

Ancak, o zaman x aralığına bağlıdır, yani fonksiyonun küçük (-0.001, 0.001) ve büyük değerler (-1, 1) için sağlam olması gerekir mi? Frak (sin (x /1000.0) * 43758.5453) ile farkı görmeyi deneyebilirsiniz; ve frak (sin (x /1000.0) * 4e5); burada x [-1., 1.] aralığında. İkinci varyantta görüntü daha monoton olacaktır (en azından gölgelendiricide farkı görüyorum). Ancak genel olarak, 4e5'i hala kullanabileceğinizi ve yeterince iyi sonuç alabileceğinizi kabul ediyorum.
Roman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.