/************************************************************************
* noises.h - various noise-based patterns
*
* Author: Larry Gritz (gritzl@acm.org)
*
* Reference:
* _Advanced RenderMan: Creating CGI for Motion Picture_,
* by Anthony A. Apodaca and Larry Gritz, Morgan Kaufmann, 1999.
*
* $Revision: 1.1 $ $Date: 2004/03/02 04:50:34 $
*
************************************************************************/
#ifndef NOISES_H
#define NOISES_H 1
#ifndef FILTERWIDTH_H
#include "filterwidth.h" /* Needed for filterwidth and friends */
#endif
#ifndef PATTERNS_H
#include "patterns.h" /* Needed for filteredabs */
#endif
#ifndef snoise
/*
* Signed noise -- the original Perlin kind with range (-1,1) We prefer
* signed noise to regular noise mostly because its average is zero.
* We define three simple macros:
* snoise(p) - Perlin noise on either a 1-D (float) or 3-D (point) domain.
* snoisexy(x,y) - Perlin noise on a 2-D domain.
* vsnoise(p) - vector-valued Perlin noise on either 1-D or 3-D domain.
*/
#define snoise(p) (2 * (float noise(p)) - 1)
#define snoisexy(x,y) (2 * (float noise(x,y)) - 1)
#define vsnoise(p) (2 * (vector noise(p)) - 1)
#endif
/* If we know the filter size, we can crudely antialias snoise by fading
* to its average value at approximately the Nyquist limit.
*/
#define filteredsnoise(p,width) (snoise(p) * (1-smoothstep (0.2,0.75,width)))
#define filteredvsnoise(p,width) (vsnoise(p) * (1-smoothstep (0.2,0.75,width)))
/* fractional Brownian motion
* Inputs:
* p, filtwidth position and approximate inter-pixel spacing
* octaves max # of octaves to calculate
* lacunarity frequency spacing between successive octaves
* gain scaling factor between successive octaves
*/
float fBm (point p; float filtwidth;
uniform float octaves, lacunarity, gain)
{
uniform float amp = 1;
varying point pp = p;
varying float sum = 0, fw = filtwidth;
uniform float i;
for (i = 0; i < octaves; i += 1) {
#pragma nolint
sum += amp * filteredsnoise (pp, fw);
amp *= gain; pp *= lacunarity; fw *= lacunarity;
}
return sum;
}
/* Typical use of fBm: */
#define fBm_default(p) fBm (p, filterwidthp(p), 4, 2, 0.5)
/* A vector-valued antialiased fBm. */
vector
vfBm (point p; float filtwidth;
uniform float octaves, lacunarity, gain)
{
uniform float amp = 1;
varying point pp = p;
varying vector sum = 0;
varying float fw = filtwidth;
uniform float i;
for (i = 0; i < octaves; i += 1) {
#pragma nolint
sum += amp * filteredvsnoise (pp, fw);
amp *= gain; pp *= lacunarity; fw *= lacunarity;
}
return sum;
}
/* Typical use of vfBm: */
#define vfBm_default(p) vfBm (p, filterwidthp(p), 4, 2, 0.5)
/* The stuff that Ken Musgrave calls "VLNoise" */
#define VLNoise(Pt,scale) (snoise(vsnoise(Pt)*scale+Pt))
#define filteredVLNoise(Pt,fwidth,scale) \
(filteredsnoise(filteredvsnoise(Pt,fwidth)*scale+Pt,fwidth))
float
VLfBm (point p; float filtwidth;
uniform float octaves, lacunarity, gain, scale)
{
uniform float amp = 1;
varying point pp = p;
varying float sum = 0;
varying float fw = filtwidth;
uniform float i;
for (i = 0; i < octaves; i += 1) {
#pragma nolint
sum += amp * filteredVLNoise (pp, fw, scale);
amp *= gain; pp *= lacunarity; fw *= lacunarity;
}
return sum;
}
/* Typical use of vfBm: */
#define VLfBm_default(p) VLfBm (p, filterwidthp(p), 4, 2, 0.5, 1.0)
/* Antialiased turbulence. Watch out -- the abs() call introduces infinite
* frequency content, which makes our antialiasing efforts much trickier!
*/
float turbulence (point p; float filtwidth;
uniform float octaves, lacunarity, gain)
{
extern float du, dv; /* Needed for filterwidth macro */
uniform float amp = 1;
varying point pp = p;
varying float sum = 0, fw = filtwidth;
uniform float i;
for (i = 0; i < octaves; i += 1) {
#pragma nolint
float n = filteredsnoise (pp, fw);
sum += amp * filteredabs (n, fw);
amp *= gain; pp *= lacunarity; fw *= lacunarity;
}
return sum;
}
/* Typical use of turbulence: */
#define turbulence_default(p) turbulence (p, filterwidthp(p), 4, 2, 0.5)
/***************************************************************************
* Voronoi cell noise (a.k.a. Worley noise) functions
*
* These functions assume that space is filled with "features" (points
* of interest). There are interestingpatterns we can make by
* figuring out which feature we are closest to, or to what extent
* we're on the boundary between two features. Several varieties of
* these computations are below, categorized by the dimension of their
* domains, and the number of close features they are interested in.
*
* All these functions have similar inputs:
* P - position to test (for 3-D varieties; 2-D varieties use ss,tt)
* jitter - how much to jitter the cell center positions (1 is typical,
* smaller values make a more regular pattern, larger values
* make a more jagged pattern; use jitter >1 at your risk!).
* And outputs:
* f_n - distance to the nth nearest feature (f1 is closest, f2 is
* the distance to the 2nd closest, etc.)
* pos_n - the position of the nth nearest feature. For 2-D varieties,
* these are instead spos_n and tpos_n.
***************************************************************************/
/* Voronoi cell noise (a.k.a. Worley noise) -- 3-D, 1-feature version. */
void
voronoi_f1_3d (point P;
float jitter;
output float f1;
output point pos1;
)
{
point thiscell = point (floor(xcomp(P))+0.5, floor(ycomp(P))+0.5,
floor(zcomp(P))+0.5);
f1 = 1000;
uniform float i, j, k;
for (i = -1; i <= 1; i += 1) {
for (j = -1; j <= 1; j += 1) {
for (k = -1; k <= 1; k += 1) {
point testcell = thiscell + vector(i,j,k);
point pos = testcell +
jitter * (vector cellnoise (testcell) - 0.5);
vector offset = pos - P;
float dist = offset . offset; /* actually dist^2 */
if (dist < f1) {
f1 = dist; pos1 = pos;
}
}
}
}
f1 = sqrt(f1);
}
/* Voronoi cell noise (a.k.a. Worley noise) -- 3-D, 2-feature version. */
void
voronoi_f1f2_3d (point P;
float jitter;
output float f1; output point pos1;
output float f2; output point pos2;
)
{
point thiscell = point (floor(xcomp(P))+0.5, floor(ycomp(P))+0.5,
floor(zcomp(P))+0.5);
f1 = f2 = 1000;
uniform float i, j, k;
for (i = -1; i <= 1; i += 1) {
for (j = -1; j <= 1; j += 1) {
for (k = -1; k <= 1; k += 1) {
point testcell = thiscell + vector(i,j,k);
point pos = testcell +
jitter * (vector cellnoise (testcell) - 0.5);
vector offset = pos - P;
float dist = offset . offset; /* actually dist^2 */
if (dist < f1) {
f2 = f1; pos2 = pos1;
f1 = dist; pos1 = pos;
} else if (dist < f2) {
f2 = dist; pos2 = pos;
}
}
}
}
f1 = sqrt(f1); f2 = sqrt(f2);
}
/* Voronoi cell noise (a.k.a. Worley noise) -- 2-D, 1-feature version. */
void
voronoi_f1_2d (float ss, tt;
float jitter;
output float f1;
output float spos1, tpos1;
)
{
float sthiscell = floor(ss)+0.5, tthiscell = floor(tt)+0.5;
f1 = 1000;
uniform float i, j;
for (i = -1; i <= 1; i += 1) {
float stestcell = sthiscell + i;
for (j = -1; j <= 1; j += 1) {
float ttestcell = tthiscell + j;
float spos = stestcell +
jitter * (float cellnoise(stestcell, ttestcell) - 0.5);
float tpos = ttestcell +
jitter * (float cellnoise(stestcell+23, ttestcell-87) - 0.5);
float soffset = spos - ss;
float toffset = tpos - tt;
float dist = soffset*soffset + toffset*toffset;
if (dist < f1) {
f1 = dist;
spos1 = spos; tpos1 = tpos;
}
}
}
f1 = sqrt(f1);
}
/* Voronoi cell noise (a.k.a. Worley noise) -- 2-D, 2-feature version. */
void
voronoi_f1f2_2d (float ss, tt;
float jitter;
output float f1;
output float spos1, tpos1;
output float f2;
output float spos2, tpos2;
)
{
float sthiscell = floor(ss)+0.5, tthiscell = floor(tt)+0.5;
f1 = f2 = 1000;
uniform float i, j;
for (i = -1; i <= 1; i += 1) {
float stestcell = sthiscell + i;
for (j = -1; j <= 1; j += 1) {
float ttestcell = tthiscell + j;
float spos = stestcell +
jitter * (cellnoise(stestcell, ttestcell) - 0.5);
float tpos = ttestcell +
jitter * (cellnoise(stestcell+23, ttestcell-87) - 0.5);
float soffset = spos - ss;
float toffset = tpos - tt;
float dist = soffset*soffset + toffset*toffset;
if (dist < f1) {
f2 = f1; spos2 = spos1; tpos2 = tpos1;
f1 = dist; spos1 = spos; tpos1 = tpos;
} else if (dist < f2) {
f2 = dist;
spos2 = spos; tpos2 = tpos;
}
}
}
f1 = sqrt(f1); f2 = sqrt(f2);
}
#endif /* NOISES_H */