[comp.graphics] Pixar's noise function

coy@ssc-vax.UUCP (Stephen B Coy) (03/29/89)

[...]

Hi there,
	Last night I saw the article in Byte about the Renderman
standard.  In the sample source code the displacement function, dent(),
calls a function called noise().  Noise() takes a point as its
parameter and returns a float in the range 0..1.  The article says
this is a semi-random value that changes slowly over the surface of
the object.  My question:  Does anyone out there know what this
noise function really is?  Are you willing to share this info/source
with the rest of us?  Please?

	Thanks in advance for any responses.

Stephen Coy
uw-beaver!ssc-vax!coy

ps  Anyone have any decent marble texture functions you'd like to
    share?

aaa@pixar.UUCP (Tony Apodaca) (03/30/89)

In article <2553@ssc-vax.UUCP> coy@ssc-vax.UUCP (Stephen B Coy) writes:
>	Last night I saw the article in Byte about the Renderman
>standard.  In the sample source code the displacement function, dent(),
>calls a function called noise()...
>          ...My question:  Does anyone out there know what this
>noise function really is?

	Three-dimensional simulated natural textures using pseudorandom
functions were simultaneously and independently developed by Darwyn
Peachey and Ken Perlin in 1984-5.  Both have papers in the 1985
Siggraph Proceedings describing their systems.  Perlin, in particular,
describes in detail how noise() is implemented and can be used creatively
to describe large classes of natural phenomena.  Conceptually, noise()
is a "stochastic three-dimensional function which is statistically
invariant under rotation and translation and has a narrow bandpass
limit in frequency" (paraphrased from [Perlin1985]).  This means that
you put three-space points in, and you get values back which are basically
random.  But if you put other nearby points in, you get values that are
very similar.  The differences are still random, but the maximum rate of
change is controlled so that you can avoid aliasing.  If you put a set
of points in from a different region of space, you will get values out
which have "the same amount" of randomness.
	If you have ever been interested in realistic computer graphics, do
whatever it takes to get a look at Perlin's paper.  In 1985, his pictures
were absolutely astounding.  In 1989, they are STILL astounding.

>ps  Anyone have any decent marble texture functions you'd like to
>    share?

	Perlin's paper has a simple marble texture function:

/* assume marble_color() is a color lookup table function */
float turbulence(point p) {
	float t=0, scale=1;
	while(scale > pixelsize) {
		t += abs(noise(p / scale)*scale);
		scale /= 2;
	}
	return t;
}
color marble(point p) {
	float x = xcomp(p) + turbulence(p);
	return marble_color(sin(x));
}
-- 
UUCP:		{sun,ucbvax}!pixar!aaa		Tony Apodaca
ARPA,BITNET:	aaa%pixar.uucp@sun.com		Pixar, San Rafael, CA, USA

bullerj@handel.colostate.edu (Jon Buller) (03/31/89)

In article <3599@pixar.UUCP> aaa@pixar.UUCP (Tony Apodaca) writes:
>In article <2553@ssc-vax.UUCP> coy@ssc-vax.UUCP (Stephen B Coy) writes:
>>          ...My question:  Does anyone out there know what this
>>noise function really is?
>
>	Three-dimensional simulated natural textures using pseudorandom
>functions were simultaneously and independently developed by Darwyn
>Peachey and Ken Perlin in 1984-5.  Both have papers in the 1985
>Siggraph Proceedings describing their systems.  Perlin, in particular,
>describes in detail how noise() is implemented and can be used creatively

   [A description of the properties of the noise function goes here...]

>	If you have ever been interested in realistic computer graphics, do
>whatever it takes to get a look at Perlin's paper.  In 1985, his pictures
>were absolutely astounding.  In 1989, they are STILL astounding.

	No kidding, some of those pictures are INCREDIBLE.

     Here is my code for a look-alike to the Pixar Noise function, and while
I can't say anything about exactly what Pixar's looks like, I think this is
probably close.  After reading the 1985 SIGGRAPH papers on 3d texturing,
(and seeing my prof's code to do a similar thing) I wrote this.  It uses a
quadratic B-Spline instead of the cubic Hermite interpolant implied in the
paper.  Also note that DNoise is just the x, y, and z derivatives of Noise
(which are also B-Splines).  The hashing functions are from Knuth's Art of
Computer Programming (I don't remember which volume though).

I know the code is Pascal, and all of you will hate it, but I belive I write
better Pascal than C...  One final note, this was Lightspeed Pascal 2.0 for
the Macintosh, but things have been reformatted slighly to get it on the net.
I hope this is what you all wanted.  Enjoy,

Jon
bullerj@handel.cs.colostate.edu          ...!ncar!ccncsu!handel!bullerj
(These are my ideas (and code), nobody else SHOULD want these bugs)
I'm just trying to graduate.  Apple, Pixar, HP, etc. take note, I would like
your job offers, I have tired of the university life.

(* ---------- cut here ---------- cut here ---------- cut here ---------- *)

const
   MaxPts = 512;  { Must be 2^n}
   MPM1 = MaxPts - 1;
type
   PtsTyp = array[0..MaxPts] of Extended;
var
   Points: PtsTyp;


function Noise (Loc: Vect;
                Pts: PtsTyp): Extended;
   const
      P1 = 173;
      P2 = 263;   {Reasonable numbers to (attempt to) avoid diagonal repetition}
      P3 = 337;
      phi = 0.618033988749894842;   {phi = (Sqrt(5)-1)/2}
   var
      xi, yi, zi: Integer;
      xa, xb, xc, ya, yb, yc, za, zb, zc: Integer;
      xf, yf, zf: Extended;
      x2, x1, x0, y2, y1, y0, z2, z1, z0: Extended;
      p000, p100, p200, p010, p110, p210, p020, p120, p220: Extended;
      p001, p101, p201, p011, p111, p211, p021, p121, p221: Extended;
      p002, p102, p202, p012, p112, p212, p022, p122, p222: Extended;
begin
   xi := Trunc(Loc[1]);
   xa := Trunc(P1 * (xi * phi - Trunc(xi * phi)));
   xb := Trunc(P1 * ((xi + 1) * phi - Trunc((xi + 1) * phi)));
   xc := Trunc(P1 * ((xi + 2) * phi - Trunc((xi + 2) * phi)));

   yi := Trunc(Loc[2]);
   ya := Trunc(P2 * (yi * phi - Trunc(yi * phi)));
   yb := Trunc(P2 * ((yi + 1) * phi - Trunc((yi + 1) * phi)));
   yc := Trunc(P2 * ((yi + 2) * phi - Trunc((yi + 2) * phi)));

   zi := Trunc(Loc[3]);
   za := Trunc(P3 * (zi * phi - Trunc(zi * phi)));
   zb := Trunc(P3 * ((zi + 1) * phi - Trunc((zi + 1) * phi)));
   zc := Trunc(P3 * ((zi + 2) * phi - Trunc((zi + 2) * phi)));

   p000 := Pts[BitAnd(xa + ya + za, MPM1)];{p000 := Pts[(xa+ya+za) mod MaxPts]}
   p100 := Pts[BitAnd(xb + ya + za, MPM1)];
   p200 := Pts[BitAnd(xc + ya + za, MPM1)];
   p010 := Pts[BitAnd(xa + yb + za, MPM1)];
   p110 := Pts[BitAnd(xb + yb + za, MPM1)];
   p210 := Pts[BitAnd(xc + yb + za, MPM1)];
   p020 := Pts[BitAnd(xa + yc + za, MPM1)];
   p120 := Pts[BitAnd(xb + yc + za, MPM1)];
   p220 := Pts[BitAnd(xc + yc + za, MPM1)];
   p001 := Pts[BitAnd(xa + ya + zb, MPM1)];
   p101 := Pts[BitAnd(xb + ya + zb, MPM1)];
   p201 := Pts[BitAnd(xc + ya + zb, MPM1)];
   p011 := Pts[BitAnd(xa + yb + zb, MPM1)];
   p111 := Pts[BitAnd(xb + yb + zb, MPM1)];
   p211 := Pts[BitAnd(xc + yb + zb, MPM1)];
   p021 := Pts[BitAnd(xa + yc + zb, MPM1)];
   p121 := Pts[BitAnd(xb + yc + zb, MPM1)];
   p221 := Pts[BitAnd(xc + yc + zb, MPM1)];
   p002 := Pts[BitAnd(xa + ya + zc, MPM1)];
   p102 := Pts[BitAnd(xb + ya + zc, MPM1)];
   p202 := Pts[BitAnd(xc + ya + zc, MPM1)];
   p012 := Pts[BitAnd(xa + yb + zc, MPM1)];
   p112 := Pts[BitAnd(xb + yb + zc, MPM1)];
   p212 := Pts[BitAnd(xc + yb + zc, MPM1)];
   p022 := Pts[BitAnd(xa + yc + zc, MPM1)];
   p122 := Pts[BitAnd(xb + yc + zc, MPM1)];
   p222 := Pts[BitAnd(xc + yc + zc, MPM1)];

   xf := Loc[1] - xi;
   x1 := xf * xf;
   x2 := 0.5 * x1;
   x1 := 0.5 + xf - x1;
   x0 := 0.5 - xf + x2;

   yf := Loc[2] - yi;
   y1 := yf * yf;
   y2 := 0.5 * y1;
   y1 := 0.5 + yf - y1;
   y0 := 0.5 - yf + y2;

   zf := Loc[3] - zi;
   z1 := zf * zf;
   z2 := 0.5 * z1;
   z1 := 0.5 + zf - z1;
   z0 := 0.5 - zf + z2;

   Noise := z0 * (y0 * (x0 * p000 + x1 * p100 + x2 * p200) +
                  y1 * (x0 * p010 + x1 * p110 + x2 * p210) +
                  y2 * (x0 * p020 + x1 * p120 + x2 * p220)) +
            z1 * (y0 * (x0 * p001 + x1 * p101 + x2 * p201) +
                  y1 * (x0 * p011 + x1 * p111 + x2 * p211) +
                  y2 * (x0 * p021 + x1 * p121 + x2 * p221)) +
            z2 * (y0 * (x0 * p002 + x1 * p102 + x2 * p202) +
                  y1 * (x0 * p012 + x1 * p112 + x2 * p212) +
                  y2 * (x0 * p022 + x1 * p122 + x2 * p222));
end;


function Turb (Size: Integer;
               ScaleFactor: Extended;
               Loc: Vect;
               Pts: PtsTyp): Extended;
   var
      Scale, Result: Extended;
      Cur: Integer;
begin
   Result := Noise(Loc, Pts);
   Scale := 1.0;

   Cur := 1;
   while Cur < Size do begin
      Cur := BSL(Cur, 1);          {Cur := Cur * 2}
      Scale := Scale * ScaleFactor;
      Loc := Scale_Vect(2.0, Loc);
      Result := Result + Noise(Loc, Pts) * Scale;
   end;
   Turb := Result;
end;


function DNoise (Loc: Vect;
                 Pts: PtsTyp): Vect;
   const
      P1 = 173;
      P2 = 263;
      P3 = 337;
      phi = 0.618033988749894842;
   var
      xi, yi, zi: Integer;
      xa, xb, xc, ya, yb, yc, za, zb, zc: Integer;
      xf, yf, zf: Extended;
      x2, x1, x0, y2, y1, y0, z2, z1, z0: Extended;
      xd2, xd1, xd0, yd2, yd1, yd0, zd2, zd1, zd0: Extended;
      p000, p100, p200, p010, p110, p210, p020, p120, p220: Extended;
      p001, p101, p201, p011, p111, p211, p021, p121, p221: Extended;
      p002, p102, p202, p012, p112, p212, p022, p122, p222: Extended;
begin
   xi := Trunc(Loc[1]);
   xa := Trunc(P1 * (xi * phi - Trunc(xi * phi)));
   xb := Trunc(P1 * ((xi + 1) * phi - Trunc((xi + 1) * phi)));
   xc := Trunc(P1 * ((xi + 2) * phi - Trunc((xi + 2) * phi)));

   yi := Trunc(Loc[2]);
   ya := Trunc(P2 * (yi * phi - Trunc(yi * phi)));
   yb := Trunc(P2 * ((yi + 1) * phi - Trunc((yi + 1) * phi)));
   yc := Trunc(P2 * ((yi + 2) * phi - Trunc((yi + 2) * phi)));

   zi := Trunc(Loc[3]);
   za := Trunc(P3 * (zi * phi - Trunc(zi * phi)));
   zb := Trunc(P3 * ((zi + 1) * phi - Trunc((zi + 1) * phi)));
   zc := Trunc(P3 * ((zi + 2) * phi - Trunc((zi + 2) * phi)));

   p000 := Pts[BitAnd(xa + ya + za, MPM1)];
   p100 := Pts[BitAnd(xb + ya + za, MPM1)];
   p200 := Pts[BitAnd(xc + ya + za, MPM1)];
   p010 := Pts[BitAnd(xa + yb + za, MPM1)];
   p110 := Pts[BitAnd(xb + yb + za, MPM1)];
   p210 := Pts[BitAnd(xc + yb + za, MPM1)];
   p020 := Pts[BitAnd(xa + yc + za, MPM1)];
   p120 := Pts[BitAnd(xb + yc + za, MPM1)];
   p220 := Pts[BitAnd(xc + yc + za, MPM1)];
   p001 := Pts[BitAnd(xa + ya + zb, MPM1)];
   p101 := Pts[BitAnd(xb + ya + zb, MPM1)];
   p201 := Pts[BitAnd(xc + ya + zb, MPM1)];
   p011 := Pts[BitAnd(xa + yb + zb, MPM1)];
   p111 := Pts[BitAnd(xb + yb + zb, MPM1)];
   p211 := Pts[BitAnd(xc + yb + zb, MPM1)];
   p021 := Pts[BitAnd(xa + yc + zb, MPM1)];
   p121 := Pts[BitAnd(xb + yc + zb, MPM1)];
   p221 := Pts[BitAnd(xc + yc + zb, MPM1)];
   p002 := Pts[BitAnd(xa + ya + zc, MPM1)];
   p102 := Pts[BitAnd(xb + ya + zc, MPM1)];
   p202 := Pts[BitAnd(xc + ya + zc, MPM1)];
   p012 := Pts[BitAnd(xa + yb + zc, MPM1)];
   p112 := Pts[BitAnd(xb + yb + zc, MPM1)];
   p212 := Pts[BitAnd(xc + yb + zc, MPM1)];
   p022 := Pts[BitAnd(xa + yc + zc, MPM1)];
   p122 := Pts[BitAnd(xb + yc + zc, MPM1)];
   p222 := Pts[BitAnd(xc + yc + zc, MPM1)];

   xf := Loc[1] - xi;
   x1 := xf * xf;
   x2 := 0.5 * x1;
   x1 := 0.5 + xf - x1;
   x0 := 0.5 - xf + x2;
   xd2 := xf;
   xd1 := 1.0 - xf - xf;
   xd0 := xf - 1.0;

   yf := Loc[2] - yi;
   y1 := yf * yf;
   y2 := 0.5 * y1;
   y1 := 0.5 + yf - y1;
   y0 := 0.5 - yf + y2;
   yd2 := yf;
   yd1 := 1.0 - yf - yf;
   yd0 := yf - 1.0;

   zf := Loc[3] - zi;
   z1 := zf * zf;
   z2 := 0.5 * z1;
   z1 := 0.5 + zf - z1;
   z0 := 0.5 - zf + z2;
   zd2 := zf;
   zd1 := 1.0 - zf - zf;
   zd0 := zf - 1.0;

   DNoise[1] := z0 * (y0 * (xd0 * p000 + xd1 * p100 + xd2 * p200) +
                      y1 * (xd0 * p010 + xd1 * p110 + xd2 * p210) +
                      y2 * (xd0 * p020 + xd1 * p120 + xd2 * p220)) +
                z1 * (y0 * (xd0 * p001 + xd1 * p101 + xd2 * p201) +
                      y1 * (xd0 * p011 + xd1 * p111 + xd2 * p211) +
                      y2 * (xd0 * p021 + xd1 * p121 + xd2 * p221)) +
                z2 * (y0 * (xd0 * p002 + xd1 * p102 + xd2 * p202) +
                      y1 * (xd0 * p012 + xd1 * p112 + xd2 * p212) +
                      y2 * (xd0 * p022 + xd1 * p122 + xd2 * p222));
                                  
   DNoise[2] := z0 * (yd0 * (x0 * p000 + x1 * p100 + x2 * p200) +
                      yd1 * (x0 * p010 + x1 * p110 + x2 * p210) +
                      yd2 * (x0 * p020 + x1 * p120 + x2 * p220)) +
                z1 * (yd0 * (x0 * p001 + x1 * p101 + x2 * p201) +
                      yd1 * (x0 * p011 + x1 * p111 + x2 * p211) +
                      yd2 * (x0 * p021 + x1 * p121 + x2 * p221)) +
                z2 * (yd0 * (x0 * p002 + x1 * p102 + x2 * p202) +
                      yd1 * (x0 * p012 + x1 * p112 + x2 * p212) +
                      yd2 * (x0 * p022 + x1 * p122 + x2 * p222));
                                  
   DNoise[3] := zd0 * (y0 * (x0 * p000 + x1 * p100 + x2 * p200) +
                       y1 * (x0 * p010 + x1 * p110 + x2 * p210) +
                       y2 * (x0 * p020 + x1 * p120 + x2 * p220)) +
                zd1 * (y0 * (x0 * p001 + x1 * p101 + x2 * p201) +
                       y1 * (x0 * p011 + x1 * p111 + x2 * p211) +
                       y2 * (x0 * p021 + x1 * p121 + x2 * p221)) +
                zd2 * (y0 * (x0 * p002 + x1 * p102 + x2 * p202) +
                       y1 * (x0 * p012 + x1 * p112 + x2 * p212) +
                       y2 * (x0 * p022 + x1 * p122 + x2 * p222));
   DNoise[4] := 0.0;
end;


function DTurb (Size: Integer;
                ScaleFactor: Extended;
                Loc: Vect;
                Pts: PtsTyp): Vect;
   var
      Result: Vect;
      Scale: Extended;
      Cur: Integer;
begin
   Result := DNoise(Loc, Pts);
   Scale := 1.0;

   Cur := 1;
   while Cur < Size do begin
      Cur := BSL(Cur, 1);
      Scale := Scale * ScaleFactor;
      Loc := Scale_Vect(2.0, Loc);
      Result := Add_Vect(Result, Scale_Vect(Scale, DNoise(Loc, Pts)));
   end;
   DTurb := Result;
end;
-------------------------------------------------------------------------------
Jon Buller                                      FROM fortune IMPORT quote;
..!ccncsu!handel!bullerj                       FROM lawyers IMPORT disclaimer;

jamesa@arabian.Sun.COM (James D. Allen) (04/06/89)

In article <3599@pixar.UUCP>, aaa@pixar.UUCP (Tony Apodaca) writes:
> In article <2553@ssc-vax.UUCP> coy@ssc-vax.UUCP (Stephen B Coy) writes:
> >	Last night I saw the article in Byte about the Renderman
> >standard.  In the sample source code the displacement function, dent(),
> >calls a function called noise()...
> >          ...My question:  Does anyone out there know what this
> >noise function really is?
> 
> ... Conceptually, noise()
> is a "stochastic three-dimensional function which is statistically
> invariant under rotation and translation and has a narrow bandpass
> limit in frequency" (paraphrased from [Perlin1985]).  This means that
> you put three-space points in, and you get values back which are basically
> random.  But if you put other nearby points in, you get values that are
> very similar.  The differences are still random, but the maximum rate of
> change is controlled so that you can avoid aliasing.  If you put a set
> of points in from a different region of space, you will get values out
> which have "the same amount" of randomness.

	Anyone willing to post a detailed description of such an
	algorithm?  (Jon Buller posted one, but I couldn't figure it out:
	what is `Pts'?)
> -- 
> UUCP:		{sun,ucbvax}!pixar!aaa		Tony Apodaca
> ARPA,BITNET:	aaa%pixar.uucp@sun.com		Pixar, San Rafael, CA, USA

-James Allen

bullerj@handel.colostate.edu (Jon Buller) (04/07/89)

In article <97699@sun.Eng.Sun.COM> jamesa@arabian.Sun.COM (James D. Allen) writes:
>In article <3599@pixar.UUCP>, aaa@pixar.UUCP (Tony Apodaca) writes:
>> In article <2553@ssc-vax.UUCP> coy@ssc-vax.UUCP (Stephen B Coy) writes:
>> >          ...My question:  Does anyone out there know what this
>> >noise function really is?
>> 
>> ... Conceptually, noise()
>> is a "stochastic three-dimensional function which is statistically
>> invariant under rotation and translation and has a narrow bandpass
>> limit in frequency" (paraphrased from [Perlin1985]).  This means that
>> you put three-space points in, and you get values back which are basically
>> random.  But if you put other nearby points in, you get values that are
>> very similar.  The differences are still random, but the maximum rate of
>> change is controlled so that you can avoid aliasing.  If you put a set
>> of points in from a different region of space, you will get values out
>> which have "the same amount" of randomness.
>
>	Anyone willing to post a detailed description of such an
>	algorithm?  (Jon Buller posted one, but I couldn't figure it out:
>	what is `Pts'?)

Sorry about not really describing my program to anyone, I know what it does,
and I never expected anyone else to see it (isn't it obvious) :-)

What it does is:  pass a location in space, and an array of random numbers
(this is 'Pts').  I fill the array with 0.0 .. 1.0 but any values or range
will work.  (I have other textures which color based on distance to the nearest
point of a random set, hence the name, It has 4 values per entry at times.)

Step 1: change the location to a group of points to interpolate.  This is
where xa,xb,xc,...zc come in, any location with the same coords (when trunc'ed)
will produce the same xa...zc values, making the same values for the
interpolation at the end.  These xa..zc are then hashed in to the 'Pts' array
to produce p000...P222, these 27 random numbers are then interpolated with
a Quadratic 3d B-Spline (the long ugly formula at the end).  The variables
based on xf,yf, and zf (I belive they are x0..z2) are the B-Spline basis
functions (notice to get DNoise, just take the (partial) deriveatives(sp?) of
the basis functions and re-evaluate the spline).

Step 2: now you have a value that is always smaller than the largest random
number in 'Pts' (equal to in the odd case that major bunches of the numbers are
also the maximum in the range).  By the same argument, all numbers returned are
larger than the smallest number in the array. (this can be handy if you don't
want to have to clip your values to some limit.)

I hope this explains the use of the routine better.  Sorry I didn't realize
that earlier.  If you have any other questions about it, mail them to me, and
I'll do my best to explain it.

Jon

-------------------------------------------------------------------------------
Jon Buller                                      FROM fortune IMPORT quote;
..!ccncsu!handel!bullerj                       FROM lawyers IMPORT disclaimer;

dirks@alligator.cis.ohio-state.edu (william r dirks) (04/14/89)

I implemented Jon Buller's noise functions the other night.  (Thanks
Jon, I've been looking for a decent noise function for a long time.)
Anyway, I rendered a polygon situated in the x-y plane with DNoise()
added to the normal vectors to make a bumpy-looking surface.  But I
noticed there were discontinuities in the "bumps."

Studying the image, I noticed that where x and y were both positive
the bumps were continuous, where x was negative and y was positive
there were lines of discontinuity parallel to the y-axis, where x was
positive and y was negative the lines were parallel to the x-axis, and
where both x and y were negative the two sets of lines intersected to
form squares.

On a hunch I changed all the trunc()'s in the source to floor()'s.

And presto!! Continuous bumps everywhere!

Now I can make bumpy surfaces that look just like Perlin's!  I traced
a bumpy glass last night.  I don't know why a glass would be bumpy, but
it looks cool as hell!

(The difference between trunc() and floor(), of course, is that trunc()
rounds toward 0, but floor() always rounds down.  So these functions
are the same for positive numbers, but different for negative ones.)

 __________________________________________________________________________
| Name:           Bill Dirks                                               |
| Address:        dirks@baloo.eng.ohio-state.edu                           |
| Bumper Sticker: "STOP ME AND ASK ME ABOUT MY RAY-TRACER"                 |
| Quote:          "Survival and preservation must cancel out programming." |
|                      -- Star Trek, "What Are Little Girls Made Of?"      |
| Disclaimer:     #include <stddisclaimer.h>                               |
`=========================================================================='

bullerj@handel.colostate.edu (Jon Buller) (04/14/89)

In article <43327@tut.cis.ohio-state.edu> william r dirks <dirks@cis.ohio-state.edu> writes:
>Anyway, I rendered a polygon situated in the x-y plane with DNoise()
>added to the normal vectors to make a bumpy-looking surface.  But I
>noticed there were discontinuities in the "bumps."
>
>Studying the image, I noticed that where x and y were both positive
>the bumps were continuous, where x was negative and y was positive
>there were lines of discontinuity parallel to the y-axis, where x was
>positive and y was negative the lines were parallel to the x-axis, and
>where both x and y were negative the two sets of lines intersected to
>form squares.
>
>On a hunch I changed all the trunc()'s in the source to floor()'s.
>
>And presto!! Continuous bumps everywhere!

    I wish I could do that, my compiler doesn't have a built in Floor,
and I haven't had the time to hack one up from the Mac toolbox and SANE
(IEEE math pkg) calls, oh well, I'll have to settle for only using 
X, Y, and Z >= 0.0  One other thing you might notice, Noise is C1 continuous,
DNoise is only C0.  This means that DNoise will have creases in it (along
the planes of the random grid.  To see this, crank out a square: 0<X<5, 0<Y<5,
Z=0.  You will see smooth regions within each unit square, and creases btween
squares.  To aviod this, use a cubic B-Spline, or cubic Hermite (as hinted to
in the SIGGRAPH procedings) the problem there, is that you either need more
data points (64 instead of 27) for the B-Spline, or deravative info at each
point of the grid (a normal plane, 4 floats instead of 1).  This would take too
muh time for me to code up to be worth it, and would probably run too much
slower (10min for a 200x200 pixel picture now, ug.)  If somebody wants to give
me a cray-3 to play with, I'll write more accurate (and slower) code, until
then... 8-)
-------------------------------------------------------------------------------
Jon Buller                                      FROM fortune IMPORT quote;
..!ccncsu!handel!bullerj                       FROM lawyers IMPORT disclaimer;

malloy@nprdc.arpa (Sean Malloy) (04/16/89)

In article <1648@ccncsu.ColoState.EDU> bullerj@handel.colostate.edu.UUCP (Jon Buller) writes:
|In article <43327@tut.cis.ohio-state.edu> william r dirks <dirks@cis.ohio-state.edu> writes:
|>On a hunch I changed all the trunc()'s in the source to floor()'s.
|>
|>And presto!! Continuous bumps everywhere!
|
|    I wish I could do that, my compiler doesn't have a built in Floor,
|and I haven't had the time to hack one up from the Mac toolbox and SANE
|(IEEE math pkg) calls, oh well, I'll have to settle for only using 
|X, Y, and Z >= 0.0

If I understand the problem correctly, writing a floor() function is
extremely simple:

int floor(x)
double x;
{
  if (x >= 0.0) return(trunc(x));
           else return(trunc(x)+1);
}


 Sean Malloy					| "The proton absorbs a photon
 Navy Personnel Research & Development Center	| and emits two morons, a
 San Diego, CA 92152-6800			| lepton, a boson, and a
 malloy@nprdc.navy.mil				| boson's mate. Why did I ever
						| take high-energy physics?"

bullerj@handel.colostate.edu (Jon Buller) (04/17/89)

In article <1771@skinner.nprdc.arpa> malloy@nprdc.arpa (Sean Malloy) writes:
>If I understand the problem correctly, writing a floor() function is
>extremely simple:

>int floor(x)
>double x;
>{
>  if (x >= 0.0) return(trunc(x));
>           else return(trunc(x)+1);
>}

> Sean Malloy					| "The proton absorbs a photon
> Navy Personnel Research & Development Center	| and emits two morons, a
> San Diego, CA 92152-6800			| lepton, a boson, and a
> malloy@nprdc.navy.mil				| boson's mate. Why did I ever
>						| take high-energy physics?"
                                     I like this      ^^^^^^      8-)

Well, that almost works, if x = -1.0, floor = -1.0, your_func = 0.0
(you meant return(trunc(x)-1); didn't you?) in this case, your_func = -2.0,
this ---->  ^^^^^^^^    will work if x is NOT an integer, will break if it is,
and it is admittedly a simple thing to fix, but as I said before, I've been
LAZY.  I can't use the thing in a render quite yet, so I haven't bothered.

-------------------------------------------------------------------------------
Jon Buller                                      FROM fortune IMPORT quote;
..!ccncsu!handel!bullerj                       FROM lawyers IMPORT disclaimer;

peter@celia.UUCP (Peter Farson) (04/22/89)

In article <1669@ccncsu.ColoState.EDU> bullerj@handel.colostate.edu.UUCP (Jon Buller) writes:
>In article <1771@skinner.nprdc.arpa> malloy@nprdc.arpa (Sean Malloy) writes:
>>If I understand the problem correctly, writing a floor() function is
>>extremely simple:
>
>>int floor(x)
>>double x;
>>{
>>  if (x >= 0.0) return(trunc(x));
>>           else return(trunc(x)+1);
>>}
>
>
>Well, that almost works, if x = -1.0, floor = -1.0, your_func = 0.0
>(you meant return(trunc(x)-1); didn't you?) in this case, your_func = -2.0,
>this ---->  ^^^^^^^^    will work if x is NOT an integer, will break if it is,
>and it is admittedly a simple thing to fix, but as I said before, I've been
>LAZY.  I can't use the thing in a render quite yet, so I haven't bothered.
>
	
	How about:

int floor(x)
double x;
{
if (x >= 0.0) return(trunc(x));
    else return(trunc(x-.999999));
    }

The only problem with this is with the accuracy of the .999999 constant.
Ideally you would want a floating point binary constant with all bits set
to 1 in the mantissa, to the precision of the binary floating point format
of the machine.  Any error in this value should not be too big a deal though in
most cases - it just causes values that are very close to an integer to
be treated as though they are an integer (-1.00000001 being mistaken for
-1.0000000000, for example).  But there is one pitfall: if there are too
many decimal digits in this constant for the machine's precision,
it might get rounded up to 1.00, which would make the function return
incorrect results for negative integers.


-- 
Can a bee be said to be                Peter Farson
An entire bee if                       celia!peter@tis.llnl.gov
Half the bee is not a bee              ...{ihnp4,ames}!lll-tis!celia!peter
Due to some ancient injury?

malloy@nprdc.arpa (Sean Malloy) (04/24/89)

In article <465@celia.UUCP> celia!peter@tis.llnl.gov (Peter Farson) writes:
>	How about:
>
>int floor(x)
>double x;
>{
>if (x >= 0.0) return(trunc(x));
>    else return(trunc(x-.999999));
>    }
>

Looking back at my original (and slightly broken) solution, the
corrected function would be:

int floor(x)
double x;
{
  if ((x >= 0.0)||(x == trunc(x)) return(trunc(x));
      else return(trunc(x)+1);
}


 Sean Malloy					| "The proton absorbs a photon
 Navy Personnel Research & Development Center	| and emits two morons, a
 San Diego, CA 92152-6800			| lepton, a boson, and a
 malloy@nprdc.navy.mil				| boson's mate. Why did I ever
						| take high-energy physics?"

platt@cs.swarthmore.edu (Steve Platt) (04/24/89)

Off the top of my head,

int floor(x)
double x;
{  if (x>=0) return(trunc(x));
      else return(-trunc(-x));
}

seems to do the trick.