If you're seeing this message, it means we're having trouble loading external resources on our website.

웹 필터가 올바르게 작동하지 않으면 도메인 *. kastatic.org*.kasandbox.org이 차단되어 있는지 확인하세요.

주요 내용

펄린 노이즈

좋은 난수 생성기는 생성된 수 사이에 관계가 없고 어떠한 패턴도 보이지 않습니다. 계속 배우고 있듯이, 약간의 무작위성은 유기적이고 살아있는 듯한 행동을 프로그래밍 하는 데 좋습니다. 하지만 무작위성을 유일한 원칙으로 사용하는 것이 무조건 자연스러운 것은 아닙니다.
펄린 노이즈(Perline Noise)는 좀 더 자연스러운 결과를 내는 알고리즘입니다. 켄 펄린(Ken Perlin)은 1980년대에 영화 트론의 제작을 위해 노이즈 함수를 개발했고 이를 컴퓨터 그래픽에 절차적(procedural) 텍스처를 주는 데 사용했습니다. 펄린은 이것으로 1997년 아카데미 과학 기술상을 수상했습니다. 펄린 노이즈는 자연에서 볼 수 있는 구름이나 풍경, 대리석처럼 패턴이 있는 텍스처를 표현하는데 사용될 수 있습니다.
펄린 노이즈는 자연스럽게 정렬된("부드럽게") 의사 난수 시퀀스를 생성하기 때문에 보다 더 유기적인 모습을 하고 있습니다. 아래의 그래프는 시간이 흐름에 따른 펄린 노이즈를 보여줍니다. x축은 시간을 나타냅니다. 곡선의 매끄러움을 주시하세요.
코드 본질에 관한 이미지
그림 I.5: 노이즈
반면 아래 그래프는 시간에 따른 순수한 난수를 보여줍니다.
코드 본질에 관한 이미지
그림 I.6: 난수
ProcessingJS는 펄린 노이즈 알고리즘을 내장하고 있습니다: noise()함수로 말입니다. 노이즈는 일차원, 이차원, 삼차원에서 계산될 수 있으므로 noise() 함수는 하나, 둘, 혹은 세 개의 인수를 받습니다. 1차원 노이즈를 먼저 확인해봅시다.

노이즈에 관한 상세 사항

노이즈 참조를 보면 노이즈가 여러 "옥타브"에서 계산된다는 것을 알 수 있습니다. noiseDetail() 함수를 호출하면 옥타브의 개수와 각 옥타브의 상대적인 중요도를 바꿉니다. 결과적으로 이는 노이즈 함수의 성질을 바꿉니다.
임의의 x-위치에 있는 ProcessingJS 윈도우 내에 원을 그리는 것을 생각해보면 다음과 같습니다:
var x = random(0, width);
ellipse(x, 180, 16, 16);
이제 임의의 x-위치 대신 보다 "매끄러운" 펄린 노이즈의 x-위치를 생각해보겠습니다. 이렇게 하기 위해서 다음과 같이 random()noise()로 대체하면 된다고 생각할 수 있습니다:
var x = noise(0, width);
ellipse(x, 180, 16, 16);
펄린 노이즈에 따라 0부터 너비 사이의 값으로 x 값을 정하는 것은 개념적으로 정확하지만, 위는 올바른 구현 방법이 아닙니다. random() 함수의 인수가 최솟값과 최댓값을 명시하기는 하지만 noise()는 이런 방식으로 작동하지 않습니다. 대신 noise()는 어떤 순간을 나타내는 인수를 기대하고, 항상 0과 1사이의 값을 반환합니다. 1차원 펄린 노이즈는 시간에 따른 선형의 수열이라고 생각할 수도 있습니다. 다음은 입력값과 반환값의 예입니다:
시간노이즈 값
00.469
0.010.480
0.020.492
0.030.505
0.040.517
이제, ProcessingJS 내의 노이즈 값에 접근하기 위해서는, noise()함수에 특정 시간값을 전달해야합니다. 다음의 예를 살펴보겠습니다.
var n = noise(0.03);
위의 표에 따르면, noise()는 시간값 0.03에 대해 0.505를 반환합니다. 다음 프로그램은 시간 변수를 저장하고 그에 따른 노이즈 값을 draw()안에 넣습니다.
위의 코드는 같은 값을 계속해서 출력합니다. 이는 noise() 함수에 계속해서 같은 시간의 결과를 요청하고 있기 때문입니다.
시간 변수 t를 증가시키면 다른 결과를 얻을 수 있습니다.
얼마나 신속하게 t를 증가시키는지가 노이즈의 부드러움에 영향을 줍니다. 만약 시간 내에 크게 도약하면 앞으로 건너뛰게 되어 값이 훨씬 더 임의적이게 됩니다.
시간에 따른 노이즈
그림 1.7
위의 코드의 t를 0.01, 0.02, 0.05, 0.1, 0.0001로 증가하면서 여러 번 실행해 보면 다른 결과를 볼 수 있을 것입니다.

노이즈 매핑

이제 노이즈 값으로 무엇을 할지 생각해 볼 차례입니다. 0과 1사이의 값을 가지고 있으면, 원하는 대로 이를 매핑하기만 하면 됩니다.
범위의 최댓값으로 곱하는 것도 가능하겠지만, ProcessingJS에는 이제 계속해서 쓰이게 될 map()이라는 함수가 있습니다. map() 함수는 인수를 다섯 개 받습니다. 첫 번째 인수는 매핑할 값, 이 경우 n입니다. 그리고 값의 현재 범위(최소에서 최대)와 바꿀 범위를 쓰면 됩니다.
코드 본질에 관한 이미지
그림 I.8
이 경우 노이즈의 범위가 0과 1 사이라는 것을 알고 있지만 0과 현재의 너비 사이의 너비를 갖는 직사각형을 그리고자 합니다.
동일한 논리를 임의의 walker에 적용하고 펄린 노이즈에 따라 x 값과 y 값을 할당해 보면 다음과 같습니다.
위의 예제에서 추가적인 한 쌍의 변수 txty 를 사용하고 있는 것에 주목합시다.Walker 객체의 x, y 좌표를 위해 두 개의 시간 변수를 사용하기 때문입니다.
하지만 이 변수에는 조금 이상한 점이 있습니다. 왜 tx는 0에서부터 시작하고 ty 는 10,000에서 시작할까요? 이 숫자들은 임의로 선택한 것이지만, 두 개의 시간 변수는 의도적으로 다른 값에서 초기화했습니다. 왜냐하면 노이즈 함수가 결정론적이기 때문입니다. 즉, 특정 시간 t 에 대해서 항상 같은 결과를 얻습니다. 만약 xy 의 노이즈 값을 같은 시간 t 를 사용한다면, xy 의 값이 항상 같아서 Walker 객체는 항상 대각선으로만 이동할 것입니다. 그 대신, x 는 0에서 시작하고 y는 10,000에서 시작하는 것처럼 노이즈에 간격을 주면, xy가 서로 독립적으로 보이도록 할 수 있습니다.
코드 본질에 관한 이미지
그림 I.9
사실, 지금 사용한 시간의 개념은 실제로 존재하지 않습니다. 노이즈 함수가 어떻게 작동하는지를 이해하기 위한 비유였을 뿐입니다. 실제로는 공간으로 존재합니다. 위의 그래프는 1차원 공간에서 선형 구조로 노이즈 값을 표현하기 때문에, 언제든 특정 x 값을 얻을 수 있습니다. 실제 예제에서, 종종 시간을 뜻하는 t 변수 대신 xoff라는 이름의 변수를 볼 수 있을 텐데 이는 x-offset을 뜻합니다.
다음 단게에서는 약간 다른 방법으로 Walker에 노이즈를 이용해볼 것입니다. 즐거운 시간 보내세요!

본 "내추럴 시뮬레이션" 과정은 다니엘 쉬프만(Daniel Shiffman)이 저술한 "The Nature of Code"의 내용을 차용한 것이며, 본 내용물의 저작권은 Creative Commons Attribution-NonCommercial 3.0 Unported License를 적용합니다.