[random] GLSL을위한 랜덤 / 노이즈 기능

GPU 드라이버 공급 업체는 일반적으로 noiseXGLSL에서 구현하기 를 귀찮게하지 않기 때문에 GPU 셰이더 내에서 사용하도록 최적화 된 “그래픽 랜덤 스위스 군용 칼” 유틸리티 기능 세트를 찾고 있습니다. GLSL을 선호하지만 모든 언어가 나를 위해 코드를 작성하면 GLSL로 직접 번역해도 괜찮습니다.

특히, 나는 기대할 것이다 :

a) 의사 난수 함수 -M 차원 시드에서 계산 된 [-1,1] 또는 [0,1]에 대한 N 차원의 균일 분포 (이상적으로는 값이 있지만 시드를 억제해도 괜찮습니다) 균일 한 결과 분포를 위해 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 rand ()가 있습니다. 그 위에 좋은 N- 차원 rand ()를 만드는 방법 … “ .



답변

매우 단순한 의사 난수처럼 보이는 물건을 위해 인터넷에서 찾은이 oneliner를 사용합니다.

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

원하는 PRNG를 사용하여 노이즈 텍스처를 생성 한 다음 일반적인 방식으로 업로드하고 셰이더의 값을 샘플링 할 수도 있습니다. 원하는 경우 나중에 코드 샘플을 파낼 수 있습니다.

또한 Stefan Gustavson의 Perlin 및 Simplex 노이즈의 GLSL 구현에 대해서도이 파일 을 확인하십시오 .


답변

간단한 정수 해시 함수를 사용하고 결과를 float의 가수에 삽입 할 수 있다는 것이 나에게 발생합니다. IIRC의 GLSL 사양은 32 비트 부호없는 정수와 IEEE binary32 float 표현을 보장하므로 완벽하게 이식 가능해야합니다.

나는 지금 이것을 시도했다. 결과는 매우 좋습니다 : 시도한 모든 입력에 대해 정적 인 것처럼 보이며 패턴이 전혀 보이지 않습니다. 대조적으로 인기있는 sin / fract 스 니펫은 동일한 입력이 주어지면 GPU의 대각선을 상당히 뚜렷하게 나타냅니다.

한 가지 단점은 GLSL v3.30이 필요하다는 것입니다. 그리고 그것은 충분히 빠르지 만, 나는 경험적으로 그 성능을 정량화하지 않았습니다. AMD의 Shader Analyzer는 HD5870에서 vec2 버전에 대해 클럭 당 13.33 픽셀을 청구합니다. sin / fract 스 니펫의 경우 클럭 당 16 픽셀과 대조됩니다. 따라서 조금 느려집니다.

여기 내 구현이 있습니다. 나는 자신의 기능을 쉽게 파생시킬 수 있도록 아이디어를 다양한 순열로 남겼습니다.

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

스크린 샷 :

static.frag의 랜덤 (vec3) 출력

이미지 편집 프로그램에서 스크린 샷을 검사했습니다. 256 개의 색상이 있으며 평균값은 127입니다. 이는 분포가 균일하고 예상 범위를 포함 함을 의미합니다.


답변

Gustavson의 구현은 1D 텍스처를 사용합니다.

아닙니다. 2005 년 이후가 아닙니다. 사람들이 구 버전 다운로드를 고집하는 것뿐입니다. 제공 한 링크에있는 버전은 8 비트 2D 텍스처 만 사용합니다.

Ashima의 Ian McEwan과 새 버전은 텍스처를 사용하지 않지만 텍스처 대역폭이 많은 일반 데스크탑 플랫폼에서 속도의 약 절반 속도로 실행됩니다. 모바일 플랫폼에서 텍스처링은 종종 병목 현상으로 인해 텍스처리스 버전이 더 빠를 수 있습니다.

적극적으로 유지 관리되는 소스 저장소는 다음과 같습니다.

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

텍스처리스 및 텍스처 사용 버전의 노이즈 컬렉션이 여기 있습니다 (2D 텍스처 만 사용).

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

질문이 있으시면 언제든지 저에게 직접 이메일을 보내주십시오 (내 이메일 주소는 classicnoise*.glsl소스 에서 찾을 수 있습니다 ).


답변

골드 노이즈

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

지금 브라우저에서 골드 노이즈를보십시오!

여기에 이미지 설명을 입력하십시오

이 함수는 2017 년 9 월 9 일 현재 @appas ‘answer의 현재 함수에 대한 임의 분포를 개선했습니다.

여기에 이미지 설명을 입력하십시오

@appas 함수도 시드가 제공되지 않아 (uv는 시드가 아니고 – 모든 프레임에 동일), 낮은 정밀도 칩셋에서 작동하지 않기 때문에 불완전합니다. 골드 노이즈는 기본적으로 낮은 정밀도로 실행됩니다 (훨씬 빠름).


답변

멋진 구현 설명도 있습니다 여기에 소음 펄린 같은 외모,하지만 “어떤 설정, 즉하지 질감도 균일 한 배열을 필요로하지 않습니다. 그냥 쉐이더 소스 코드에 추가하고 당신이 원하는 목적지를 호출”고 McEwan은과 @StefanGustavson에 의해.

@dep에 연결된 Gustavson의 이전 구현 이 GLSL ES (WebGL의 셰이더 언어) 에서 지원되지 않는 1D 텍스처를 사용한다는 점에서 특히 유용합니다 .


답변

이것을 사용하십시오 :

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

OpenGL ES 2.0의 정식 단일 라이너 GLSL rand () 개선 에서 설명을 찾을 수 있습니다.


답변

GPU에 대한이 3d 노이즈 버전을 찾았습니다.

#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