펄린 노이즈(Perlin Noise)

원문 URL : http://freespace.virgin.net/hugo.elias/models/m_perlin.htm


펄린 노이즈 활용

  • 랜덤 지형 생성
  • 특정 매질의 느낌이 나는 랜덤한 텍스쳐 생성
  • 풀이나 식물군 배치
  • 나뭇가지 움직임
  • 바람, 파도의 움직임 등등
활용을 보면 알겠지만 랜덤한 데이터를 필요로 할 때 사용된다.
 


노이즈 함수 

노이즈 함수 == 시드기반의 난수 생성기




노이즈 함수를 이용해서 Y축값을 랜덤하게 생성한 그래프


위의 그래프를 부드럽게 보간한 그래프


정의

  • 진폭(Amplitude) : 파동의 최대 높이값
  • 진동수(Frequency) : 단위시간내에 일어난 진동의 횟수 (1 / 파장)



싸인파

진폭 : 최대 높이값
파장 : 같은 높이값이 다시 나올떄 까지의 거리
진동수 : 1 / 파장


노이즈파

진폭 : 최대값 - 최소값(랜덤한 빨간점 기준)
파장 : 빨간점 사이의 거리
진동수 : 1 / 파장


노이즈 함수를 이용한 파동



                      



                     



                     


펄린 노이즈 함수를 이용한 파동

위에 노이즈 함수의 합 == 펄린 노이즈 함수

Large, Medium, Small의 변화가 섞여 있어 우리가 원하는 다양한 결과를 보여준다.

이 기법을 2D로 적용시켜보자.

     


2D로 만든 각각의 노이즈들을 합치면 자연스러운 값을 얻을 수 있다.























지속성(Persistence)

다양한 결과를 위해 진폭과 진동수의 적절한 수정이 필요.

지속성이란 값을 도입하여 간략화 해보자.

이 값은 프랙탈로 유명한 멘델브로트란 사람이 만들었다고 한다.

frequency = 2i
amplitude = persistencei

빈도수는 2의 승수로 올라가고 진폭을 지속성의 승수를 적용하여 처리한다.

Frequency12481632
  
Persistence = 1/4+++++=
Amplitude:11/41/161/641/2561/1024result
  
Persistence = 1/2+++++=
Amplitude:11/21/41/81/161/32result
  
Persistence = 1 / root2+++++=
Amplitude:11/1.4141/21/2.8281/41/5.656result
  
Persistence = 1+++++=
Amplitude:111111result


옥타브(Octaves)

노이즈 함수들이 더해지는 정도

어느정도를 더할지는 자유지만 지속성이 1보다 크면 모르겠지만 대부분 1보다 작으면 금방 작아지므로 매우 작은 결과값들이 더해질 것이기 때문에 적정선을 찾으면 좋겠다.



노이즈 함수 만들기

일반 난수생성기는 생성할 때 마다 다른 값을 리턴해주지만 우리가 만들 노이즈 함수는 같은 시드값을 넘겨주면 같은 값을 넘겨주는 함수이다.

그러한 함수중에 하나는 다음과 같다.

function IntNoise(32-bit integer: x)			 

    x = (x<<13) ^ x;
    return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);    

  end IntNoise function

위의 함수는 하나의 예이고 소수를 이용해서 적절히 값을 만들어 낼 수 있을 것이다. 
하지만 테스트는 어느정도 필요할 것 같다.


보간

노이즈 함수를 만들었으면 구한 값을 보간하여 부드럽게 만들 필요가 있다.

선형보간

간단한 대신 결과가 너무 간단하게 나온다.


  function Linear_Interpolate(a, b, x)
	return  a*(1-x) + b*x
  end of function


코사인보간

선형보간보다 부드럽지만 연산이 느릴 수 있다.


function Cosine_Interpolate(a, b, x) ft = x * 3.1415927 f = (1 - cos(ft)) * .5 return a*(1-f) + b*f end of function


삼차곡선보간

결과가 매우 부드럽게 나오는 보간법으로 속도가 느릴 수 있다. 코사인보간과 비교했을 때 결과가 좋을 수도 있고 나쁠 수도 있다.

function Cubic_Interpolate(v0, v1, v2, v3,x)
	P = (v3 - v2) - (v0 - v1)
	Q = (v0 - v1) - P
	R = v2 - v0
	S = v1

	return Px3 + Qx2 + Rx + S
  end of function


부드러운 노이즈

보간으로도 어느정도 부드럽게 얻어낼 수 있지만 한계가 있다.

이미지 필터링과 같은 방식으로 이웃 값들을 얻어와 평균을 내는 방식을 사용해 더 부드러운 값을 얻어낸다.


1차원 처리

function Noise(x)
    .
    .
  end function

  function SmoothNoise_1D(x)

    return Noise(x)/2  +  Noise(x-1)/4  +  Noise(x+1)/4

  end function

2차원 처리

function Noise(x, y)
    .
    .
  end function

  function SmoothNoise_2D(x>, y)
    
    corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16
    sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8
    center  =  Noise(x, y) / 4

    return corners + sides + center


  end function



최종 결과물

지금까지 구현한 것을 모두 합쳐보자.


1차원 펄린 노이즈

function Noise1(integer x)
    x = (x<<13) ^ x;
    return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);    
  end function


  function SmoothedNoise_1(float x)
    return Noise(x)/2  +  Noise(x-1)/4  +  Noise(x+1)/4
  end function


  function InterpolatedNoise_1(float x)

      integer_X    = int(x)
      fractional_X = x - integer_X

      v1 = SmoothedNoise1(integer_X)
      v2 = SmoothedNoise1(integer_X + 1)

      return Interpolate(v1 , v2 , fractional_X)

  end function


  function PerlinNoise_1D(float x)

      total = 0
      p = persistence
      n = Number_Of_Octaves - 1

      loop i from 0 to n

          frequency = 2i
          amplitude = pi

          total = total + InterpolatedNoisei(x * frequency) * amplitude

      end of i loop

      return total

  end function


2차원 펄린 노이즈

function Noise1(integer x, integer y)
    n = x + y * 57
    n = (n<<13) ^ n;
    return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);    
  end function

  function SmoothNoise_1(float x, float y)
    corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16
    sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8
    center  =  Noise(x, y) / 4
    return corners + sides + center
  end function

  function InterpolatedNoise_1(float x, float y)

      integer_X    = int(x)
      fractional_X = x - integer_X

      integer_Y    = int(y)
      fractional_Y = y - integer_Y

      v1 = SmoothedNoise1(integer_X,     integer_Y)
      v2 = SmoothedNoise1(integer_X + 1, integer_Y)
      v3 = SmoothedNoise1(integer_X,     integer_Y + 1)
      v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1)

      i1 = Interpolate(v1 , v2 , fractional_X)
      i2 = Interpolate(v3 , v4 , fractional_X)

      return Interpolate(i1 , i2 , fractional_Y)

  end function


  function PerlinNoise_2D(float x, float y)

      total = 0
      p = persistence
      n = Number_Of_Octaves - 1

      loop i from 0 to n

          frequency = 2i
          amplitude = pi

          total = total + InterpolatedNoisei(x * frequency, y * frequency) * amplitude

      end of i loop

      return total

  end function


원본 글을 참고하여 간단하게 펄린 노이즈에 대해서 정리해 보았다.

다양한 곳에 많이 사용되는 것이니까 개념을 잘 읽혀놓고

노이즈를 만드는 함수나 툴킷 클래스를 만들어 놓으면 유용하게 사용할 수 있을 것이다.






Posted by 게임 프로그래머 MSPark의 블로그 msparkms