2012-01-13 7 views
5

2 차원지도에서 때때로 반짝임을 만드는 셰이더를 쓰고 있습니다. ("반짝임"은 단순히 밝은 색상의 픽셀 일뿐입니다.) 반짝이는 블록을 (무한한) 평면에 무작위로 균일하게 분포 시키길 원합니다.하지만 스파클링을 X 좌표와 Y 좌표를 기반으로 결정적으로 만들고 싶습니다. 좌표에서 시드를 생성하고 해당 시드에서 Java Random을 만들려고 시도했지만 시도한 결과 인식 가능한 패턴이 나타났습니다. 이 함수는 자주 (수 백만 번) 호출되기 때문에 성능이 중요합니다.X/Y 좌표에서 의사 결정 패턴을 생성하려면 어떻게해야합니까?

처음으로 충돌을 피하기 위해 소수 승수를 사용하는 hashCode() 구현을 모방하려고했습니다. 이로 인해 일련의 점이 동일한 시드를 공유하는지도에서 눈에 띄는 상흔이 생겼습니다.

나는 다음과 같이 좌표를 연결하여 씨앗을 만들려고 :

long seed = ((long) x << 32) | (long) y; 
Random rand = new Random(seed); 

이 패턴이 명백 아니지만,뿐만 아니라 패턴 데이터가 나타날 것으로 보인다. 선택한 좌표는 선상에 나타나고, 균등하게 분포하지는 않습니다.

MD5 나 다른 암호화 해싱 알고리즘은 성능에 영향을 줄 수 있으므로 사용하지 마십시오.

+1

1cm에서 많은 수의 의사 난수를 생성하고 2 차원 사각형에 플로팅하는 경우 강력한 생성기를 사용하지 않는 한 인식 가능한 '패턴'을 잘 볼 수 있습니다. k- 비행기를 찾으십시오. probbaly는 비선형 합동 의사 난수 생성기를 사용하려고합니다. –

답변

2

java.util.Random에 구현 된 linear congruential generator은 임의의 선택한 SEED에 대해 반복 가능하다는 장점이 있습니다. 이러한 선언,

private static final int SEED = 42; 
private static final int N = 128; 
private static final int MAX_X = 1024; 
private static final int MAX_Y = 1024; 
private final Random rnd = new Random(SEED); 
private final List<SparklePoint> list = new ArrayList<SparklePoint>(N); 

다음과 같이 사각형 (0, 0, MAX_X, MAX_Y)N 무작위로 선택된 포인트 (반복) 목록을 초기화 할 수 있습니다 감안할 때 :

public void init(int seed) { 
    for (int i = 0; i < N; i++) { 
     int x = rnd.nextInt(MAX_X); 
     int y = rnd.nextInt(MAX_Y); 
     list.add(new SparklePoint(x, y)); 
    } 
} 

각 지점에게 Timer 그 기간을 제공하는 것이 편리 할 수있다 동일한 시퀀스로부터 선택된다 :

private class SparklePoint implements ActionListener { 

    private static final int MAX_DELAY = 1000; 
    private final Point p; 
    private final Timer t; 
    private boolean bright; 

    public SparklePoint(int x, int y) { 
     p = new Point(x, y); 
     t = new Timer(rnd.nextInt(MAX_DELAY), this); 
     t.setRepeats(false); 
     t.start(); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     t.stop(); 
     if (bright) { 
      // darken p 
     } else { 
      // brighten p 
     } 
     bright = !bright; 
     t.setDelay(rnd.nextInt(MAX_DELAY)); 
     t.start(); 
    } 
} 
+0

도전 과제는 해당 시드를 생성하여 시작하는 것입니다. 특정 시간에지도의 작은 부분 만 그리기 때문에 저는 일정한 씨앗을 사용할 수 없습니다. 원점에서 멀리 떨어지게된다면 드로잉 할 좌표에 도달 할 때까지 랜덤 스핀을 원하지 않습니다. –

+0

아, 나는 선택된 점들의 집합이 일정하다고 생각했습니다; 뷰를 최적화하여 현재 보이는 영역 밖의 점을 무시하는 것을 볼 수 있습니다. – trashgod

3

다음은 ps에서 비트를 혼합하기위한 매우 효율적인 함수이다 eudo 무작위하지만 결정적 패션 : 그래서

public static final long xorShift64(long a) { 
    a ^= (a << 21); 
    a ^= (a >>> 35); 
    a ^= (a << 4); 
    return a; 
} 

당신이 뭔가를 할 수있는 x와 y 좌표에서 의사 난수 long 결과를 원하는 경우는 :

long mix = xorShift64(x) + Long.rotateLeft(xorShift64(y),32) + 0xCAFEBABE; 
    long result = xorShift64(mix); 

나는이 방법을 사용했습니다 전에 그래픽에서 성공적으로, 꽤 좋은 결과를 제공합니다! 난수의 품질은 java.util.Random만큼 우수하지만 훨씬 빠릅니다. ...

+0

재미있을 것 같습니다. 그러한 구조의 충돌 저항을 평가하는 기사를 알고 있습니까? (작은지도의 목적을 위해, 그다지 중요하지 않지만, 나는 호기심이 많습니다.) –

0

이것은 내가 수행 한 것 (원하는 효과 생성)이지만 확실히 완벽하지는 않습니다. 나는 두 번 밖에 nextInt() 전화를 당겨 때문에 특히 자세한 것을 제외하고

MessageDigest md5; 
try { 
    md5 = MessageDigest.getInstance("MD5"); 
} catch (NoSuchAlgorithmException e) { 
    e.printStackTrace(); 
    return null; 
} 
md5.update(new byte[] { 
    (byte)(x >>> 24), 
    (byte)(x >>> 16), 
    (byte)(x >>> 8), 
    (byte)x, 
    (byte)(z >>> 24), 
    (byte)(z >>> 16), 
    (byte)(z >>> 8), 
    (byte)z 
}, 0, 8); 
byte[] digest = md5.digest(); 
long seed = digest[0] + (digest[1] << 8) + (digest[2] << 16) + (digest[3] << 24) + (digest[4] << 32) + (digest[5] << 40) + (digest[6] << 48) + (digest[7] << 56); 
Random random = new Random(seed); 

Random의 사용은 아마도 과도한이다. 특정 범위의 값을 생성하는 데 유용하지만, 어쨌든 모듈로 산술로 수행 할 수 있어야합니다.

저는 MD5가 잘 알려진 알고리즘이고 암호화 보안이이 응용 프로그램에 중요하지 않은 것을 좋아합니다. 나는 분명히 더 빠른 (그리고 덜 지저분한) 것을 좋아할 것이다.

관련 문제