Hi,
I present here a new noise function called "flow noise". This is an
extension to the usual Perlin noise method, which allows for
pseudo-physical animation of turbulence by rotating the noise base
vectors. From the original author of this code, Stefan Gustavson:
* This is an implementation of Perlin "simplex noise" over two dimensions
* (x,y) and three dimensions (x,y,z). One extra parameter 't' rotates the
* underlying gradients of the grid, which gives a swirling, flow-like
* motion. The derivative is returned, to make it possible to do pseudo-
* advection and implement "flow noise", as presented by Ken Perlin and
* Fabrice Neyret at Siggraph 2001.
*
* When not animated and presented in one octave only, this noise
* looks exactly the same as the plain version of simplex noise.
* It's nothing magical by itself, although the extra animation
* parameter 't' is useful. Fun stuff starts to happen when you
* do fractal sums of several octaves, with different rotation speeds
* and an advection of smaller scales by larger scales (or even the
* other way around it you feel adventurous).
*
* The gradient rotations that can be performed by this noise function
* and the true analytic derivatives are required to do flow noise.
* You can't do it properly with regular Perlin noise.
I made a small test video some time ago to demonstrate the effect:
http://vimeo.com/8929215
While probably not being very useful for textures, it can be a great
method of "faking" physical turbulence effects for fluids, particles,
etc. For this reason i replaced the BLI_gTurbulence function in the
turbulence effector with the new BLI_flowTurbulence function. Note
that this function takes two additional parameters: angle and
advection.
Angle (as described above) is the main animation parameter, which can
be animated to produce whirling motion. If left at a constant, the
resulting (basic) noise is the same as Perlin noise, thus the old
behaviour of the effector can easily be reproduced (even though the
actual function uses simplex noise, see below).
Advection causes an additional shift (or force field strength in terms
of the effector) in the direction of the derivative with respect to
angle. This causes a quite interesting "clumping" effect (or the
opposite for negative factors).
In the DSOnoises package this code was adapted from, there are a
couple of other noise methods, which could be easily merged into
Blender, although they are probably not that interesting:
- simplex noise has the same effect as Perlin noise, but is more
efficient, especially for 3 and 4 dimensions (and above ...)
- 4D noise is another way of generating animatable noise by using the
4th dimension as a variable parameter.
- 2D versions are also available
I prepared a small demo file to show the new effects:
http://www.pasteall.org/blend/1828
There are three cubes with particles: the leftmost is a static
turbulence field as it worked before (but using the new function), the
middle one has additional rotation, and the right one some advection
on top of that. If performance drops too low in realtime playback
(each cube has 5000 particles), you can either enable layers 2,3,4
respectively or bake the particles. One minor issue i had was that
apparently extrapolation modes for f-curves are not yet implemented
(confirm?), so that animating a continuously changing flow rotation is
a bit nasty.
Hope you like this and it can be included into svn.
Regards
phonybone
Index: release/scripts/ui/properties_physics_field.py
===================================================================
--- release/scripts/ui/properties_physics_field.py (revision 26838)
+++ release/scripts/ui/properties_physics_field.py (working copy)
@@ -113,6 +113,14 @@
col.prop(field, "use_coordinates")
col.prop(field, "root_coordinates")
col.prop(field, "force_2d")
+
+ elif field.type == 'TURBULENCE':
+ basic_force_field_settings_ui(self, context, field)
+
+ col = split.column()
+ col.prop(field, "flow_rotation")
+ col.prop(field, "flow_advection")
+
else:
basic_force_field_settings_ui(self, context, field)
Index: source/blender/blenkernel/intern/effect.c
===================================================================
--- source/blender/blenkernel/intern/effect.c (revision 26838)
+++ source/blender/blenkernel/intern/effect.c (working copy)
@@ -918,9 +918,10 @@
else {
VECADD(temp, efd->vec_to_point2, efd->nor2);
}
- force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2,0,2);
- force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2,0,2);
- force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2,0,2);
+ #define M_2PI 6.283185307
+ force[0] = -1.0f + 2.0f * BLI_flowTurbulence(pd->f_size, temp[0], temp[1], temp[2], pd->flow_rotation*M_2PI, pd->flow_advection, 2, 0);
+ force[1] = -1.0f + 2.0f * BLI_flowTurbulence(pd->f_size, temp[1], temp[2], temp[0], pd->flow_rotation*M_2PI, pd->flow_advection, 2, 0);
+ force[2] = -1.0f + 2.0f * BLI_flowTurbulence(pd->f_size, temp[2], temp[0], temp[1], pd->flow_rotation*M_2PI, pd->flow_advection, 2, 0);
mul_v3_fl(force, strength * efd->falloff);
break;
case PFIELD_DRAG:
Index: source/blender/makesdna/DNA_object_force.h
===================================================================
--- source/blender/makesdna/DNA_object_force.h (revision 26838)
+++ source/blender/makesdna/DNA_object_force.h (working copy)
@@ -108,6 +108,10 @@
struct RNG *rng; /* random noise generator for e.g. wind */
float f_noise; /* noise of force */
int seed; /* noise random seed */
+
+ /* flow noise parameters */
+ float flow_rotation;
+ float flow_advection;
} PartDeflect;
typedef struct EffectorWeights {
Index: source/blender/makesrna/intern/rna_object_force.c
===================================================================
--- source/blender/makesrna/intern/rna_object_force.c (revision 26838)
+++ source/blender/makesrna/intern/rna_object_force.c (working copy)
@@ -1170,6 +1170,18 @@
RNA_def_property_ui_text(prop, "Noise", "Noise of the force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+ prop= RNA_def_property(srna, "flow_rotation", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "flow_rotation");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation of flow noise");
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+
+ prop= RNA_def_property(srna, "flow_advection", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "flow_advection");
+ RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_text(prop, "Advection", "Advection of flow noise");
+ RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
+
prop= RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_range(prop, 1, 128);
RNA_def_property_ui_text(prop, "Seed", "Seed of the noise");
Index: source/blender/blenlib/BLI_noise.h
===================================================================
--- source/blender/blenlib/BLI_noise.h (revision 26838)
+++ source/blender/blenlib/BLI_noise.h (working copy)
@@ -56,6 +56,9 @@
/* newnoise: cellNoise & cellNoiseV (for vector/point/color) */
float cellNoise(float x, float y, float z);
void cellNoiseV(float x, float y, float z, float *ca);
+/* flow noise */
+float BLI_flowNoise3(float x, float y, float z, float angle, float *dnoise_dx, float *dnoise_dy, float *dnoise_dz);
+float BLI_flowTurbulence(float noisesize, float x, float y, float z, float angle, float advection, int oct, int hard);
#ifdef __cplusplus
Index: source/blender/blenlib/intern/noise.c
===================================================================
--- source/blender/blenlib/intern/noise.c (revision 26838)
+++ source/blender/blenlib/intern/noise.c (working copy)
@@ -215,7 +215,7 @@
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}
-/* instead of adding another permutation array, just use hash table defined above */
+/* instead of adding another hashutation array, just use hash table defined above */
static float newPerlin(float x, float y, float z)
{
int A, AA, AB, B, BA, BB;
@@ -1855,3 +1855,297 @@
/****************/
/* musgrave end */
/****************/
+
+/* Flow noise
+ * This code was copied & modified from Stefan Gustavson's ([email protected])
+ * DSOnoises package, available under GNU GPL here: http://webstaff.itn.liu.se/~stegu/aqsis/DSOs/DSOnoises.html
+ */
+
+/*
+ * This is an implementation of Perlin "simplex noise" over two dimensions
+ * (x,y) and three dimensions (x,y,z). One extra parameter 't' rotates the
+ * underlying gradients of the grid, which gives a swirling, flow-like
+ * motion. The derivative is returned, to make it possible to do pseudo-
+ * advection and implement "flow noise", as presented by Ken Perlin and
+ * Fabrice Neyret at Siggraph 2001.
+ *
+ * When not animated and presented in one octave only, this noise
+ * looks exactly the same as the plain version of simplex noise.
+ * It's nothing magical by itself, although the extra animation
+ * parameter 't' is useful. Fun stuff starts to happen when you
+ * do fractal sums of several octaves, with different rotation speeds
+ * and an advection of smaller scales by larger scales (or even the
+ * other way around it you feel adventurous).
+ *
+ * The gradient rotations that can be performed by this noise function
+ * and the true analytic derivatives are required to do flow noise.
+ * You can't do it properly with regular Perlin noise.
+ *
+ */
+
+#define FLOW_NOISE_FASTFLOOR(x) ( ((x)>0) ? ((int)x) : (((int)x)-1) )
+
+/*
+ * For 3D, we define two orthogonal vectors in the desired rotation plane.
+ * These vectors are based on the midpoints of the 12 edges of a cube,
+ * they all rotate in their own plane and are never coincident or collinear.
+ * A larger array of random vectors would also do the job, but these 12
+ * (including 4 repeats to make the array length a power of two) work better.
+ * They are not random, they are carefully chosen to represent a small
+ * isotropic set of directions for any rotation angle.
+ */
+
+/* a = sqrt(2)/sqrt(3) = 0.816496580 */
+#define a 0.81649658f
+
+static float grad3u[16][3] = {
+ { 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 1.0f }, // 12 cube edges
+ { -1.0f, 0.0f, 1.0f }, { 0.0f, -1.0f, 1.0f },
+ { 1.0f, 0.0f, -1.0f }, { 0.0f, 1.0f, -1.0f },
+ { -1.0f, 0.0f, -1.0f }, { 0.0f, -1.0f, -1.0f },
+ { a, a, a }, { -a, a, -a },
+ { -a, -a, a }, { a, -a, -a },
+ { -a, a, a }, { a, -a, a },
+ { a, -a, -a }, { -a, a, -a }
+};
+
+static float grad3v[16][3] = {
+ { -a, a, a }, { -a, -a, a },
+ { a, -a, a }, { a, a, a },
+ { -a, -a, -a }, { a, -a, -a },
+ { a, a, -a }, { -a, a, -a },
+ { 1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 0.0f },
+ { -1.0f, 1.0f, 0.0f }, { -1.0f, -1.0f, 0.0f },
+ { 1.0f, 0.0f, 1.0f }, { -1.0f, 0.0f, 1.0f }, // 4 repeats to make 16
+ { 0.0f, 1.0f, -1.0f }, { 0.0f, -1.0f, -1.0f }
+};
+
+#undef a
+
+static void gradrot3( int hash, float sin_t, float cos_t, float *gx, float *gy, float *gz ) {
+ int h = hash & 15;
+ float gux = grad3u[h][0];
+ float guy = grad3u[h][1];
+ float guz = grad3u[h][2];
+ float gvx = grad3v[h][0];
+ float gvy = grad3v[h][1];
+ float gvz = grad3v[h][2];
+ *gx = cos_t * gux + sin_t * gvx;
+ *gy = cos_t * guy + sin_t * gvy;
+ *gz = cos_t * guz + sin_t * gvz;
+ return;
+}
+
+static float graddotp3( float gx, float gy, float gz, float x, float y, float z ) {
+ return gx * x + gy * y + gz * z;
+}
+
+/* Skewing factors for 3D simplex grid:
+ * F3 = 1/3
+ * G3 = 1/6 */
+#define FLOW_NOISE_F3 0.333333333
+#define FLOW_NOISE_G3 0.166666667
+
+float BLI_flowNoise3( float _x, float _y, float _z, float angle,
+ float *dnoise_dx, float *dnoise_dy, float *dnoise_dz )
+{
+ /* TODO the pattern seems to repeat for something like z+0.5*x+0.5*y < 0
+ * This is a workaround, which provides a quick fix, but should be fixed in the main code - phonybone
+ */
+ float x = (_x < 0.0f ? 512.0f - fmod(-_x, 512.0f) : _x);
+ float y = (_y < 0.0f ? 512.0f - fmod(-_y, 512.0f) : _y);
+ float z = (_z < 0.0f ? 512.0f - fmod(-_z, 512.0f) : _z);
+ /* end workaround */
+
+ float n0, n1, n2, n3; /* Noise contributions from the four simplex corners */
+ float noise; /* Return value */
+ float gx0, gy0, gz0, gx1, gy1, gz1; /* Gradients at simplex corners */
+ float gx2, gy2, gz2, gx3, gy3, gz3;
+ float sin_t, cos_t; /* Sine and cosine for the gradient rotation angle */
+
+ /* Skew the input space to determine which simplex cell we're in */
+ float s = (x+y+z)*FLOW_NOISE_F3; /* Very nice and simple skew factor for 3D */
+ float xs = x+s;
+ float ys = y+s;
+ float zs = z+s;
+ int i = FLOW_NOISE_FASTFLOOR(xs);
+ int j = FLOW_NOISE_FASTFLOOR(ys);
+ int k = FLOW_NOISE_FASTFLOOR(zs);
+
+ float t = (float)(i+j+k)*FLOW_NOISE_G3;
+ float X0 = i-t; /* Unskew the cell origin back to (x,y,z) space */
+ float Y0 = j-t;
+ float Z0 = k-t;
+ float x0 = x-X0; /* The x,y,z distances from the cell origin */
+ float y0 = y-Y0;
+ float z0 = z-Z0;
+
+ /* For the 3D case, the simplex shape is a slightly irregular tetrahedron.
+ * Determine which simplex we are in. */
+ int i1, j1, k1; /* Offsets for second corner of simplex in (i,j,k) coords */
+ int i2, j2, k2; /* Offsets for third corner of simplex in (i,j,k) coords */
+
+ float x1, y1, z1, x2, y2, z2, x3, y3, z3;
+ int ii, jj, kk;
+ float t0, t20, t40, t1, t21, t41, t2, t22, t42, t3, t23, t43;
+
+ sin_t = sin( angle );
+ cos_t = cos( angle );
+
+ if(x0>=y0) {
+ if(y0>=z0)
+ { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } /* X Y Z order */
+ else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } /* X Z Y order */
+ else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } /* Z X Y order */
+ }
+ else { // x0<y0
+ if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } /* Z Y X order */
+ else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } /* Y Z X order */
+ else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } /* Y X Z order */
+ }
+
+ /* A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
+ * a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
+ * a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
+ * c = 1/6. */
+
+ x1 = x0 - i1 + FLOW_NOISE_G3; /* Offsets for second corner in (x,y,z) coords */
+ y1 = y0 - j1 + FLOW_NOISE_G3;
+ z1 = z0 - k1 + FLOW_NOISE_G3;
+ x2 = x0 - i2 + 2.0f * FLOW_NOISE_G3; /* Offsets for third corner in (x,y,z) coords */
+ y2 = y0 - j2 + 2.0f * FLOW_NOISE_G3;
+ z2 = z0 - k2 + 2.0f * FLOW_NOISE_G3;
+ x3 = x0 - 1.0f + 3.0f * FLOW_NOISE_G3; /* Offsets for last corner in (x,y,z) coords */
+ y3 = y0 - 1.0f + 3.0f * FLOW_NOISE_G3;
+ z3 = z0 - 1.0f + 3.0f * FLOW_NOISE_G3;
+
+ /* Wrap the integer indices at 256, to avoid indexing hash[] out of bounds */
+ ii = i % 256;
+ jj = j % 256;
+ kk = k % 256;
+
+ /* Calculate the contribution from the four corners */
+ t0 = 0.6f - x0*x0 - y0*y0 - z0*z0;
+ if(t0 < 0.0f) n0 = t0 = t20 = t40 = gx0 = gy0 = gz0 = 0.0f;
+ else {
+ gradrot3( hash[ii + hash[jj + hash[kk]]], sin_t, cos_t, &gx0, &gy0, &gz0 );
+ t20 = t0 * t0;
+ t40 = t20 * t20;
+ n0 = t40 * graddotp3( gx0, gy0, gz0, x0, y0, z0 );
+ }
+
+ t1 = 0.6f - x1*x1 - y1*y1 - z1*z1;
+ if(t1 < 0.0f) n1 = t1 = t21 = t41 = gx1 = gy1 = gz1 = 0.0f;
+ else {
+ gradrot3( hash[ii + i1 + hash[jj + j1 + hash[kk + k1]]], sin_t, cos_t, &gx1, &gy1, &gz1 );
+ t21 = t1 * t1;
+ t41 = t21 * t21;
+ n1 = t41 * graddotp3( gx1, gy1, gz1, x1, y1, z1 );
+ }
+
+ t2 = 0.6f - x2*x2 - y2*y2 - z2*z2;
+ if(t2 < 0.0f) n2 = t2 = t22 = t42 = gx2 = gy2 = gz2 = 0.0f;
+ else {
+ gradrot3( hash[ii + i2 + hash[jj + j2 + hash[kk + k2]]], sin_t, cos_t, &gx2, &gy2, &gz2 );
+ t22 = t2 * t2;
+ t42 = t22 * t22;
+ n2 = t42 * graddotp3( gx2, gy2, gz2, x2, y2, z2 );
+ }
+
+ t3 = 0.6f - x3*x3 - y3*y3 - z3*z3;
+ if(t3 < 0.0f) n3 = t3 = t23 = t43 = gx3 = gy3 = gz3 = 0.0f;
+ else {
+ gradrot3( hash[ii + 1 + hash[jj + 1 + hash[kk + 1]]], sin_t, cos_t, &gx3, &gy3, &gz3 );
+ t23 = t3 * t3;
+ t43 = t23 * t23;
+ n3 = t43 * graddotp3( gx3, gy3, gz3, x3, y3, z3 );
+ }
+
+ /* Add contributions from each corner to get the final noise value.
+ * The result is scaled to return values in the range [-1,1] */
+ noise = 28.0f * (n0 + n1 + n2 + n3);
+
+ /* Compute derivative, if requested by supplying non-null pointers
+ * for the last three arguments */
+ if( ( dnoise_dx != 0 ) && ( dnoise_dy != 0 ) && ( dnoise_dz != 0 ))
+ {
+ /* A straight, unoptimised calculation would be like:
+ * *dnoise_dx = -8.0f * t20 * t0 * x0 * graddotp3(gx0, gy0, gz0, x0, y0, z0) + t40 * gx0;
+ * *dnoise_dy = -8.0f * t20 * t0 * y0 * graddotp3(gx0, gy0, gz0, x0, y0, z0) + t40 * gy0;
+ * *dnoise_dz = -8.0f * t20 * t0 * z0 * graddotp3(gx0, gy0, gz0, x0, y0, z0) + t40 * gz0;
+ * *dnoise_dx += -8.0f * t21 * t1 * x1 * graddotp3(gx1, gy1, gz1, x1, y1, z1) + t41 * gx1;
+ * *dnoise_dy += -8.0f * t21 * t1 * y1 * graddotp3(gx1, gy1, gz1, x1, y1, z1) + t41 * gy1;
+ * *dnoise_dz += -8.0f * t21 * t1 * z1 * graddotp3(gx1, gy1, gz1, x1, y1, z1) + t41 * gz1;
+ * *dnoise_dx += -8.0f * t22 * t2 * x2 * graddotp3(gx2, gy2, gz2, x2, y2, z2) + t42 * gx2;
+ * *dnoise_dy += -8.0f * t22 * t2 * y2 * graddotp3(gx2, gy2, gz2, x2, y2, z2) + t42 * gy2;
+ * *dnoise_dz += -8.0f * t22 * t2 * z2 * graddotp3(gx2, gy2, gz2, x2, y2, z2) + t42 * gz2;
+ * *dnoise_dx += -8.0f * t23 * t3 * x3 * graddotp3(gx3, gy3, gz3, x3, y3, z3) + t43 * gx3;
+ * *dnoise_dy += -8.0f * t23 * t3 * y3 * graddotp3(gx3, gy3, gz3, x3, y3, z3) + t43 * gy3;
+ * *dnoise_dz += -8.0f * t23 * t3 * z3 * graddotp3(gx3, gy3, gz3, x3, y3, z3) + t43 * gz3;
+ */
+ float temp0, temp1, temp2, temp3;
+ temp0 = t20 * t0 * graddotp3( gx0, gy0, gz0, x0, y0, z0 );
+ *dnoise_dx = temp0 * x0;
+ *dnoise_dy = temp0 * y0;
+ *dnoise_dz = temp0 * z0;
+ temp1 = t21 * t1 * graddotp3( gx1, gy1, gz1, x1, y1, z1 );
+ *dnoise_dx += temp1 * x1;
+ *dnoise_dy += temp1 * y1;
+ *dnoise_dz += temp1 * z1;
+ temp2 = t22 * t2 * graddotp3( gx2, gy2, gz2, x2, y2, z2 );
+ *dnoise_dx += temp2 * x2;
+ *dnoise_dy += temp2 * y2;
+ *dnoise_dz += temp2 * z2;
+ temp3 = t23 * t3 * graddotp3( gx3, gy3, gz3, x3, y3, z3 );
+ *dnoise_dx += temp3 * x3;
+ *dnoise_dy += temp3 * y3;
+ *dnoise_dz += temp3 * z3;
+ *dnoise_dx *= -8.0f;
+ *dnoise_dy *= -8.0f;
+ *dnoise_dz *= -8.0f;
+ /* This corrects a bug in the original implementation */
+ *dnoise_dx += t40 * gx0 + t41 * gx1 + t42 * gx2 + t43 * gx3;
+ *dnoise_dy += t40 * gy0 + t41 * gy1 + t42 * gy2 + t43 * gy3;
+ *dnoise_dz += t40 * gz0 + t41 * gz1 + t42 * gz2 + t43 * gz3;
+ *dnoise_dx *= 28.0f; /* Scale derivative to match the noise scaling */
+ *dnoise_dy *= 28.0f;
+ *dnoise_dz *= 28.0f;
+ }
+ return noise;
+}
+
+float BLI_flowTurbulence(float noisesize, float x, float y, float z, float angle, float advection, int oct, int hard)
+{
+ float sum, t, amp=1, adv_amp=advection, fscale=1;
+ int i;
+ float dx, dy, dz, adv_x=0.0f, adv_y=0.0f, adv_z=0.0f;
+
+ if (noisesize!=0.0) {
+ noisesize = 1.0/noisesize;
+ x *= noisesize;
+ y *= noisesize;
+ z *= noisesize;
+ }
+
+ sum = 0.0f;
+ if (hard) {
+ for (i=0; i<=oct; i++, amp*=0.5, adv_amp*=0.5f, fscale*=2) {
+ t = BLI_flowNoise3(fscale*x + adv_x, fscale*y + adv_y, fscale*z + adv_z, angle, &dx, &dy, &dz);
+ adv_x -= dx*adv_amp; adv_y -= dy*adv_amp; adv_z -= dz*adv_amp;
+ sum += t * amp;
+ }
+ } else {
+ for (i=0; i<=oct; i++, amp*=0.5, fscale*=2) {
+ t = 0.5f*(1.0f + BLI_flowNoise3(fscale*x + adv_x, fscale*y + adv_y, fscale*z + adv_z, angle, &dx, &dy, &dz));
+ adv_x -= dx*adv_amp; adv_y -= dy*adv_amp; adv_z -= dz*adv_amp;
+ sum += t * amp;
+ }
+ }
+
+ sum *= ((float)(1<<oct)/(float)((1<<(oct+1))-1));
+
+ return sum;
+}
+/*
+ * Flow noise end
+ */
_______________________________________________
Bf-committers mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-committers