indexing description: "2D Perlin Noise" author: "Urs Doenni" date: "$Date$" revision: "$Revision$" class EM_3D_PERLIN_NOISE inherit EM_3D_PROCEDURE EM_PERLIN_NOISE create make, make_with_interpolator feature make_with_interpolator (an_interpolator: EM_INTERPOLATOR) is -- create the object using some interpololator do make set_interpolator (an_interpolator) end evaluate_at(pos: EM_VECTOR3D): DOUBLE is -- Evaluate 3D perlin noise at 'x', 'y' local oct: INTEGER do Result := 0.0 from oct := 1 until oct > num_of_octaves loop Result := Result + perlin_noise (pos.x, pos.y, pos.z, oct) oct := oct + 1 end end set_repeat_at(x, y, z: INTEGER) is -- repeat perlin noise after -- x in x-direction and after -- y in y-direction -- y in y-direction -- If x or y are 0, then the procedure isn't repeated in this direction require valid_x: x >= 0 valid_y: y >= 0 valid_z: z >= 0 do repeat_x := x repeat_y := y repeat_z := z end repeat_x: INTEGER repeat_y: INTEGER repeat_z: INTEGER feature perlin_noise(x, y, z: DOUBLE; an_octave: INTEGER): DOUBLE is -- compute perlin noise octave 'an_octave' at (x,y) require octave_valid: an_octave >= 1 local fraq_x, fraq_y, fraq_z: DOUBLE int_x, int_y, int_z: INTEGER nx0y0z0, nx0y1z0, nx1y0z0, nx1y1z0: DOUBLE nx0y0z1, nx0y1z1, nx1y0z1, nx1y1z1: DOUBLE ix1, ix2, ix3, ix4: DOUBLE iy1, iy2: DOUBLE iz: DOUBLE factor: DOUBLE amplitude: DOUBLE mod_x, mod_y, mod_z: INTEGER do factor := 2 ^ (an_octave - 1).to_double amplitude := persistence ^ (an_octave - 1).to_double mod_x := (repeat_x * factor).floor mod_y := (repeat_y * factor).floor mod_y := (repeat_z * factor).floor int_x := (x * factor).floor int_y := (y * factor).floor int_z := (z * factor).floor fraq_x := (x * factor) - int_x fraq_y := (y * factor) - int_y fraq_z := (z * factor) - int_z int_x := modulo(int_x, mod_x) int_y := modulo(int_y, mod_y) int_z := modulo(int_z, mod_z) -- We have a cube here -- We first get the values of the corners nx0y0z0 := get_noise (int_x, int_y, int_z) nx0y1z0 := get_noise (int_x, modulo((int_y + 1), mod_y), int_z) nx1y0z0 := get_noise (modulo((int_x + 1), mod_x), int_y, int_z) nx1y1z0 := get_noise (modulo((int_x + 1), mod_x), modulo((int_y + 1), mod_y), int_z) nx0y0z1 := get_noise (int_x, int_y, modulo(int_z + 1, mod_z)) nx0y1z1 := get_noise (int_x, modulo((int_y + 1), mod_y), modulo(int_z + 1, mod_z)) nx1y0z1 := get_noise (modulo((int_x + 1), mod_x), int_y, modulo(int_z + 1, mod_z)) nx1y1z1 := get_noise (modulo((int_x + 1), mod_x), modulo((int_y + 1), mod_y), modulo(int_z + 1, mod_z)) -- Now we interpolate on the lower side in x-direction.. ix1 := interpolator.interpolate (nx0y0z0, nx1y0z0, fraq_x) ix2 := interpolator.interpolate (nx0y1z0, nx1y1z0, fraq_x) -- ... and from that in y-direction iy1 := interpolator.interpolate (ix1, ix2, fraq_y) -- Now we do the same on the upper side ix3 := interpolator.interpolate (nx0y0z1, nx1y0z1, fraq_x) ix4 := interpolator.interpolate (nx0y1z1, nx1y1z1, fraq_x) iy2 := interpolator.interpolate (ix3, ix4, fraq_y) -- And the interpolate in z-direction iz := interpolator.interpolate (iy1, iy2, fraq_z) Result := iz * amplitude ensure Result_valid: Result >= 0 and Result <= 1.0 end get_noise(an_x, an_y, a_z: INTEGER): DOUBLE is -- returns an integer value between 0 and largest_noise local x, y, z: INTEGER tmp_x, tmp_y, tmp_z: INTEGER do x := an_x y := an_y z := a_z tmp_z := perm_array.item(modulo(z, random_size).abs) tmp_y := perm_array.item(modulo(y + tmp_z, random_size).abs) tmp_x := perm_array.item(modulo(x + tmp_y, random_size).abs) Result := random_array.item (modulo(tmp_x, random_size).abs) * noise_factor ensure Result >= 0 and Result <= 1.0 end end