Programing

이 GLSL rand () 원 라이너의 기원은 무엇입니까?

crosscheck 2020. 9. 15. 07:16
반응형

이 GLSL rand () 원 라이너의 기원은 무엇입니까?


에서 여기 저기 언급되는 셰이더에서 사용하기위한이 의사 난수 생성기를 보았습니다 .

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

"표준"또는 "웹 어딘가에서 찾은 한 줄"이라고 다양하게 불립니다.

이 기능의 기원은 무엇입니까? 상수 값은 보이는 것처럼 임의적입니까 아니면 선택에 예술이 있습니까? 이 기능의 장점에 대한 논의가 있습니까?

편집 : 내가 본이 기능에 대한 가장 오래된 참조는 20082 월의이 아카이브 이며, 원래 페이지는 이제 웹에서 사라졌습니다. 그러나 다른 곳보다 거기에 대한 더 이상 논의가 없습니다.


매우 흥미로운 질문입니다!

나는 대답을 입력하는 동안 이것을 알아 내려고 노력하고있다 :) 먼저 그것을 가지고 노는 쉬운 방법 : 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

그런 다음 여기에서 무엇을하려고하는지 생각해 봅시다. 두 개의 입력 좌표 x, y에 대해 "무작위 숫자"를 반환합니다. 이제 이것은 임의의 숫자가 아닙니다. 동일한 x, y를 입력 할 때마다 동일합니다. 해시 함수입니다!

함수가하는 첫 번째 일은 2d에서 1d로 이동하는 것입니다. 그 자체로는 흥미롭지 않지만 일반적으로 반복되지 않도록 숫자가 선택됩니다. 또한 거기에 부동 소수점 추가가 있습니다. y 또는 x에서 더 많은 비트가 있지만 숫자는 바로 선택되어 혼합됩니다.

그런 다음 블랙 박스 sin () 함수를 샘플링합니다. 이것은 구현에 따라 많이 달라집니다!

마지막으로 분수를 곱하고 취하여 sin () 구현의 오류를 증폭합니다.

나는 이것이 일반적인 경우에 좋은 해시 함수라고 생각하지 않습니다. sin ()은 GPU에서 수치 적으로 블랙 박스입니다. 거의 모든 해시 함수를 가져 와서 변환함으로써 훨씬 더 나은 것을 구성 할 수 있어야합니다. 어려운 부분은 CPU 해싱에 사용되는 일반적인 정수 연산을 부동 소수점 연산 (반 또는 32 비트) 또는 고정 소수점 연산으로 바꾸는 것이지만 가능해야합니다.

다시 말하지만, 해시 함수로서의 실제 문제는 sin ()이 블랙 박스라는 것입니다.


그 기원은 아마도 다음과 같은 논문 일 것입니다 : "Y = [(a + x) sin (bx)] mod 1의 도움으로 난수 생성에 관하여", WJJ Rey, 22 차 유럽 통계 학자 회의 및 7 차 빌니우스 확률 이론 회의 및 수학적 통계, 1998 년 8 월

편집 :이 문서의 사본을 찾을 수없고 "TestU01"참조가 명확하지 않을 수 있으므로 다음은 의사 C의 TestU01에 설명 된 체계입니다.

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

여기서 유일한 권장 상수 값은 B1입니다.

이것은 스트림 용입니다. 1D 해시 'n'으로 변환하면 정수 그리드가됩니다. 그래서 제 생각에는 누군가 이것을보고 't'를 간단한 함수 f (x, y)로 변환했습니다. 위의 원래 상수를 사용하면 다음이 생성됩니다.

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
}

상수 값은 임의적입니다. 특히 값이 매우 크고 소수에서 몇 개의 소수가 떨어져 있습니다.

a modulus over 1 of a hi amplitude sinus multiplied by 4000 is a periodic function. it's like a window blind or a corrugated metal made very small because it's multiplied by 4000, and turned at an angle by the dot product.

as the function is 2-D, the dot product has the effect of turning the periodic function at an oblique relative to X and Y axis. By 13/79 ratio approximately. It is inefficient, you can actually achieve the same by doing sinus of (13x + 79y) this will also achieve the same thing I think with less maths..

If you find the period of the function in both X and Y, you can sample it so that it will look like a simple sine wave again.

Here is a picture of it zoomed in graph

I don't know the origin but it is similar to many others, if you used it in graphics at regular intervals it would tend to produce moire patterns and you could see it's eventually goes around again.


Maybe it's some non-recurrent chaotic mapping, then it could explain many things, but also can be just some arbitrary manipulation with large numbers.

EDIT: Basically, the function fract(sin(x) * 43758.5453) is a simple hash-like function, the sin(x) provides smooth sin interpolation between -1 to 1, so sin(x) * 43758.5453 will be interpolation from -43758.5453 to 43758.5453. This is a quite huge range, so even small step in x will provide large step in result and really large variation in fractional part. The "fract" is needed to get values in range -0.99... to 0.999... . Now, when we have something like hash function we should create function for production hash from the vector. The simplest way is call "hash" separetly for x any y component of the input vector. But then, we will have some symmetrical values. So, we should get some value from the vector, the approach is find some random vector and find "dot" product to that vector, here we go: fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); Also, according to the selected vector, its lenght should be long engough to have several peroids of the "sin" function after "dot" product will be computed.

참고URL : https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner

반응형