후디니 VEX noise 함수별 출력 범위: noise·snoise·curlnoise
VEX noise를 0~1에 맞췄는데도 점 분포가 한쪽으로 몰리거나, 같은 값 범위인데 함수마다 결과가 달라 보이나요? noise()와 xnoise()는 둘 다 0~1 계열이지만 평균과 표준편차까지 같지는 않습니다. 이번에는 Houdini 19.5.435에서 10만 점을 직접 계산해 범위와 분포를 나눠 봅니다.
먼저 기억할 점은 출력 범위와 분포는 다른 정보라는 것입니다. 범위를 0~1로 옮기는 fit()은 값을 선형으로 바꾸지만, 낮은 값이 많은 결과를 고르게 펴지는 않습니다. 함수를 고를 때 반환 형식부터 확인하고, 범위 정규화와 분포 보정을 따로 판단해야 합니다.
1. VEX noise 함수별 범위를 10만 점에서 측정했습니다
Grid SOP로 100,000개 점을 만들고 Attribute Wrangle에서 각 점의 @P를 세 축 모두 0~64 범위의 결정적 난수 위치로 바꿨습니다. 같은 좌표를 모든 함수에 넣고, 3D 기본 인자 형태를 측정했습니다. turbulence나 period 인자는 지정하지 않았습니다.
아래 최솟값과 최댓값은 이 좌표 표본에서 관찰한 값입니다. 함수가 보장하는 전체 경계가 아닙니다. 표준편차는 100,000개 값을 기준으로 계산한 모집단 표준편차입니다.
| VEX 함수·출력 | 최솟값 | 최댓값 | 평균 | 표준편차 |
|---|---|---|---|---|
noise() | 0.104772 | 0.888085 | 0.499914 | 0.100195 |
snoise() | -1.868216 | 1.928367 | 0.029684 | 0.345475 |
onoise() | -0.959734 | 0.907123 | 0.000505 | 0.274534 |
anoise() | 0.000000 | 0.950132 | 0.133736 | 0.158298 |
xnoise() | 0.071772 | 0.921395 | 0.499931 | 0.126084 |
curlnoise() x | -1.374678 | 1.335316 | -0.001138 | 0.346436 |
curlnoise() y | -1.526677 | 1.413750 | 0.001427 | 0.345988 |
curlnoise() z | -1.358178 | 1.331809 | 0.000188 | 0.347450 |
curlnoise() 길이 | 0.002908 | 1.832374 | 0.553194 | 0.233296 |
wnoise() F1 거리 | 0.000107 | 0.871995 | 0.198750 | 0.125269 |
wnoise() F2 거리 | 0.010334 | 1.208774 | 0.340182 | 0.140121 |
표에서 먼저 보이는 건 anoise()입니다. 문서상 0~1 범위지만 이 표본의 평균은 약 0.134입니다. noise()와 xnoise()는 평균이 약 0.5로 비슷해도 표준편차가 다릅니다. 범위가 비슷하다고 값이 같은 방식으로 퍼지는 것은 아닙니다.

2. 이름이 비슷해도 반환값부터 다릅니다
SideFX 문서는 noise()를 Perlin 계열로 설명하며, 출력은 0~1이고 중앙값은 0.5라고 적습니다. 차원에 따라 분포가 달라집니다. xnoise()는 Simplex 계열이며 역시 0~1 범위, 중앙값 0.5입니다. 측정에서는 평균이 같았지만 표준편차는 각각 0.1002와 0.1261로 달랐습니다.
snoise() 문서의 경계는 대략 -1.7~1.7입니다. 실제 측정값은 -1.8682에서 1.9284까지 나와 근사 경계를 조금 벗어났습니다. 이 차이는 문서가 범위를 “대략”이라고 표현한 이유를 보여 줍니다. 그 숫자를 절대 경계로 간주해 클램프하면 일부 값이 잘릴 수 있습니다.
onoise()는 대략 -1~1, anoise()는 대략 0~1로 설명됩니다. 둘 다 3D만 지원합니다. 그러나 평균은 각각 0.0005와 0.1337이었습니다. anoise()는 범위가 0~1이라고 해서 평균 0.5인 균등한 분포가 되는 함수가 아닙니다.
curlnoise()는 숫자 하나가 아니라 발산이 없는 벡터장을 반환합니다. 그래서 x·y·z 성분을 따로 측정했습니다. 각 성분의 평균은 0 근처지만 값의 범위와 표준편차는 다릅니다. 벡터의 길이도 별도의 양입니다. 성분별로 0~1에 맞추면 방향이 바뀌므로, 움직임에 쓸 벡터라면 먼저 원하는 동작이 크기 조정인지 방향 변경인지 정하세요.
wnoise()는 단일 값을 반환하지 않습니다. 가까운 seed 점까지의 거리 F1과 두 번째 거리 F2 등을 참조 인자에 씁니다. 거리는 공간 단위이므로 위치 좌표의 스케일을 바꾸면 값도 달라집니다. F1·F2를 0~1로 맞추려면 먼저 어떤 거리 구간을 표현할지 정해야 합니다.
3. Attribute Noise SOP는 범위와 Raw 분포를 따로 고릅니다
VEX 함수와 Attribute Noise SOP는 같은 조절부가 아닙니다. SOP의 Noise Range는 출력 구간을 정합니다. Positive는 0~Amplitude, Zero Centered는 -Amplitude~+Amplitude이며, Min/Max는 양 끝값을 직접 설정합니다.
Output Raw Value는 그 구간 안의 값이 어떻게 분포할지에 관여합니다. SideFX 설명에 따르면 켜면 중앙값 부근이 더 많아지는 비균일 분포를 쓰고, 끄면 더 균등한 분포를 냅니다. 이것은 range 설정과 별개의 선택입니다.
같은 10만 점에서 Float 속성, P 위치, Element Size 1, Amplitude 1, Positive range, Fractal Type None으로 측정했습니다. 아래는 실제로 관찰한 범위·평균·표준편차입니다. Output Raw Value를 껐다 해도 모든 패턴의 평균이 정확히 0.5가 되지는 않았습니다.
| Noise Pattern | Raw On: 범위 / 평균 / SD | Raw Off: 범위 / 평균 / SD |
|---|---|---|
| Fast | 0.0334–0.9527 / 0.4940 / 0.1345 | 0.0000–1.0000 / 0.5009 / 0.2881 |
| Sparse Convolution | 0.0851–0.8702 / 0.4960 / 0.0717 | 0.0000–1.0000 / 0.5001 / 0.2879 |
| Alligator | 0.0000–0.9691 / 0.1335 / 0.1581 | 0.0696–1.0000 / 0.4970 / 0.2910 |
| Perlin | 0.0257–0.9615 / 0.4977 / 0.1197 | 0.0000–1.0000 / 0.5138 / 0.3136 |
| Simplex | 0.0000–1.0000 / 0.4972 / 0.1806 | 0.0000–1.0000 / 0.5031 / 0.3480 |
| Worley Cellular F1 | 0.0001–0.7334 / 0.1672 / 0.1054 | 0.0000–0.9999 / 0.3408 / 0.2749 |
예를 들어 Alligator는 Raw On 평균이 0.1335였지만 Off에서는 0.4970으로 바뀌었습니다. 반면 Worley Cellular F1은 Off에서도 평균이 0.3408이었습니다. Output Raw Value Off는 더 균등한 분포를 고르는 옵션이지, 모든 패턴을 완벽한 균등분포로 만드는 보증은 아닙니다.
4. 측정 분포를 비교하고 fit 범위를 정해 보세요
아래 비교기에서 함수를 고르면 전체 10만 점 실측값 중 일정 간격으로 고른 1,000개를 그려 히스토그램을 표시합니다. 최솟값·최댓값·평균·표준편차는 10만 개 전체에서 계산한 값입니다. 입력 범위와 목표 범위를 바꾸면 VEX 코드와 fit 이후 히스토그램도 함께 바뀝니다.
VEX 노이즈 분포 비교기
함수를 고르면 10만 점 실측값 중 일정 간격으로 뽑은 1,000개로 히스토그램을 그립니다. 범위와 평균은 전체 100,000개 측정값입니다.
fit은 입력 범위를 선형으로 옮기며 입력 범위 밖 값은 끝값에 고정합니다. 표본의 최솟값·최댓값은 새 씬에서 보장되는 경계가 아니니, 입력 범위를 직접 정하고 실제 속성값을 다시 확인하세요. fit은 치우친 분포를 균등하게 만들지 않습니다.
비교기에서 원본 히스토그램이 이미 한쪽으로 몰려 있다면, 출력 최소·최대만 바꾸어도 그 모양은 남습니다. 먼저 원하는 시각적 결과가 값의 범위 조정인지, 빈도 분포 조정인지 구분하세요. 값 범위를 다른 수치로 옮기는 방법은 Houdini fit·fit01·clamp로 값 범위 바꾸기 글에서도 확인할 수 있습니다.
5. Wrangle에서 fit으로 범위를 맞추는 코드
VEX Wrangle에서 목표 구간을 정할 때는 입력 끝값을 파라미터로 두세요. Wrangle의 파라미터 생성 버튼으로 input_min과 input_max를 만들면 장면마다 기준을 조절할 수 있습니다. 다음 코드는 snoise 값을 정한 입력 구간에서 0~1로 옮깁니다.
float value = snoise(@P);
float value01 = fit(value, chf("input_min"), chf("input_max"), 0.0, 1.0);
f@noise01 = value01;
같은 입력을 -1~1로 바꾸려면 출력 양 끝만 바꾸면 됩니다. 반대로 noise의 0~1 값을 -1~1로 옮기려면 입력 구간을 0~1로 지정합니다.
float value = noise(@P);
float value11 = fit(value, 0.0, 1.0, -1.0, 1.0);
f@noise11 = value11;
fit()은 지정한 입력 범위 밖의 값을 끝에 고정합니다. 따라서 input_min과 input_max는 이 글의 한 번 측정한 표본 끝값이 아니라, 현재 작업에서 허용할 값 구간으로 정하세요. 외삽이 필요하다면 efit()을 검토하세요. 입력 최소와 최대가 같으면 나눌 구간이 없으므로 먼저 예외값을 정해야 합니다.
curlnoise의 성분을 색이나 별도 스칼라 속성으로 바꿔야 한다면 성분마다 fit을 적용할 수 있습니다. 하지만 그 결과를 다시 벡터로 사용하면 방향을 바꾸게 됩니다. 유동장 방향은 유지하고 세기만 바꾸려는 목적이라면 성분별 재매핑보다 벡터 크기 조절이나 정규화를 선택하세요.
vector curl = curlnoise(@P);
vector mapped = fit(curl,
set(-1.0, -1.0, -1.0), set(1.0, 1.0, 1.0),
set(0.0, 0.0, 0.0), set(1.0, 1.0, 1.0));
v@curl01 = mapped;
이제 답은 간단합니다. 먼저 함수의 반환 형태와 분포를 확인하고, fit은 필요한 범위를 옮기는 데만 쓰세요. 분포가 치우쳤다면 range 숫자만 바꿔 해결하려 하지 말고 SOP의 Output Raw Value나 다른 분포 처리 방법을 따로 시험해야 합니다.
Houdini 19.5와 22 문서에서 다른 점
측정은 Houdini 19.5.435 hython에서 실행했습니다. 확인한 SideFX Houdini 22.0 문서에서도 VEX 함수의 정의와 위에서 말한 근사 범위는 같습니다. 다만 22.0 Attribute Noise SOP 문서에는 19.5 문서에 없는 Bias·Gain·Gamma·Contrast 보정, Perlin Cloud·Simplex Cloud·Fast Simplex Cloud 패턴과 Distortion·Stretch·Droop·Worley Details 항목이 보입니다. 따라서 화면 옵션은 버전에 따라 확인하고, 이 글의 수치는 19.5.435 표본 결과로 읽으세요.
한 줄 정리
0~1이라는 범위가 평균 0.5나 균등한 분포를 뜻하지는 않습니다. VEX noise는 범위보다 먼저 반환 형태와 분포를 확인하세요.
참고 자료
vfx 잡학지식

댓글 0
첫 댓글을 남겨보세요.