home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
gondwana.ecr.mu.oz.au/pub/
/
Graphics.tar
/
Graphics
/
atomart.tar.gz
/
atomart.tar
/
noise.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-14
|
4KB
|
211 lines
#include <stdio.h>
#include <math.h>
#include "atomart.h"
#include "macro.h"
/*
* This is an implementation of Ken Perlin's noise function as
* described in "Hypertexture, Computer Graphics, Vol 23, No.3,
* July 1989, pp 255-256". Most of the function names are as
* given in the paper. Also, I think that there may be an error
* in the paper as the given formular of OMEGA would always
* produce Zero if the actual point falls on a lattice point.
* (ie. GAMMA(i, j, k) . (u, v, w) = 0). Anyway, I added in
* a psuedo random value for the noise at each lattice point
* as well as the gradient values (as decribed in his '85 paper
* and it seems to work (Maybe not so good .... but)
*/
typedef struct {
float x;
float y;
float z;
float r;
} vector4;
static vector4 *G;
static int *P;
extern float randtable[];
#define ABS(x) ((x) < 0 ? -(x) : (x))
/*
* Hashing function
*/
#define phi(i) P[ABS((i)) % NUMPTS]
#define NUMPTS 512
/*
* W
*
* A cubic (Hermite) weighting function.
*/
static float
W(t)
float t;
{
float a = ABS(t);
a = (a < 1.0 ? a * a * (2.0 * a - 3.0) + 1.0 : 0.0);
return(a);
}
/*
* GAMMA
*
* Hashes into the lattice and returns the Gradient vector
* (and the noise value G.r) for the lattice point i, j, k.
*/
static vector4 *
GAMMA(i, j, k)
int i, j, k;
{
register int l;
l = j + phi(k);
l = phi(i + phi(l));
return(&G[l]);
}
/*
* OMEGA
*
* Evaulates the spline knot at the lattice point i, j, k,
* interpolating between it and the actual point u, v, w.
*/
static float
OMEGA(i, j, k, u, v, w)
int i, j, k;
float u, v, w;
{
float a;
vector4 *V;
V = GAMMA(i, j, k);
a = V->r + (V->x * u + V->y * v + V->z * w);
a = a * W(u) * W(v) * W(w);
return(a);
}
/*
* noise
*
* Sums up the contibutions from the spline knots (lattice points)
* Around the (hashed) value of x, y, z.
*/
float
noise(p)
vector *p;
{
float x, y, z, sum = 0.0;
register int fx = floor(p->x);
register int fy = floor(p->y);
register int fz = floor(p->z);
register int i, j, k;
for (i = fx; i <= fx + 1; i++) {
for (j = fy; j <= fy + 1; j++) {
for (k = fz; k <= fz + 1; k++) {
x = p->x - (float)i;
y = p->y - (float)j;
z = p->z - (float)k;
sum += OMEGA(i, j, k, x, y, z);
}
}
}
return(sum);
}
#define OFFSET1 1000.0
#define OFFSET2 2000.0
/*
* Vnoise
*
* A vector valued noise function.
* (Again, from the '89 paper pp 259)
*/
void
Vnoise(p, v)
vector *p, *v;
{
vector s;
s.x = p->x - OFFSET1;
s.y = p->y - OFFSET1;
s.z = p->z - OFFSET1;
v->x = noise(&s);
v->y = noise(p);
s.x = p->x + OFFSET2;
s.y = p->y + OFFSET2;
s.z = p->z + OFFSET2;
v->z = noise(&s);
}
/*
* init_noise
*
* Initialises the psuedo random gradient table G(.x, .y. z) and a
* psuedo random value at the lattice points (G.r). Also initialises
* the index table P.
*/
init_noise()
{
vector4 v;
int i, n = 0, bonk;
float a;
G = (vector4 *)smalloc(NUMPTS * sizeof(vector4));
P = (int *)smalloc(NUMPTS * sizeof(int));
i = 0;
while (n < NUMPTS) {
v.x = 2.0 * randtable[i % NUMPTS] - 1.0;
v.y = 2.0 * randtable[i++ % NUMPTS] - 1.0;
v.z = 2.0 * randtable[i++ % NUMPTS] - 1.0;
v.r = 2.0 * randtable[i++ % NUMPTS] - 1.0;
if (a = dprod(v, v) <= 1.0) {
/*
* Normalise (the x, y, z compenents of) v...
*/
a = sqrt((double)a);
if (a > 0.0) {
v.x /= a;
v.y /= a;
v.z /= a;
}
G[n].x = v.x;
G[n].y = v.y;
G[n].z = v.z;
G[n].r = v.r;
n++;
}
}
/*
* Set a random permutation of the first NUMPTS integers
*/
for (n = 0; n < NUMPTS; n++)
P[n] = n;
for (n = 0; n < NUMPTS; n++) {
i = (int)(randtable[n] * (NUMPTS - 1));
bonk = P[n];
P[n] = P[i];
P[i] = bonk;
}
}