# Make Z axis alternate between 'growing' and 'shrinking'...?

**URL:** <https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661>\
**Category:** Coding Questions\
**Created:** [January 26, 2025, 5:30pm UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661 "2025-01-26T17:30:06Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![RevAustin](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/revaustin/32/20368_2.png) [@RevAustin](https://discourse.processing.org/u/RevAustin)\
**Post date:** [January 26, 2025, 5:30pm UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/1 "2025-01-26T17:30:06Z")

</div>

Hi all!

I’m new to Processing and, in short, I’d like the Z axis of an object to keep ‘growing’ and ‘shrinking’ but I don’t know the best way to do this.

I thought maybe having two alternating timers might work, but that seems like several unnecessary steps after I spotted [this post](https://discourse.processing.org/t/conditions-to-make-a-circle-grow-and-shrink/43698/4) about growing and shrinking a 2D circle.

However, I can’t quite figure out if this idea can be moved over into 3D, since I have a z variable that uses fixed min and max values.

I also like frameCount/2 being used a variable/as a modifier at the end of the ‘float z’ line, as it adds a nice ‘explode’ effect but as far as I understand it, frameCount can’t be “reversed”, can it?

Here’s my code that currently rasterizes an image and rotates it on the Y axis; I’ll add the specific image at the bottom in case this helps with testing…!

```auto
PImage img;

void setup() {
  size(900,900, P3D);
  img = loadImage("SKULL FRONT.png");
  img.resize(900,0);
}

void draw() {
  background(#000000);
  fill(#FFFFFF);
  noStroke();
  sphereDetail(1);
 
  
  float tiles = 100;
  float tileSize = width/tiles;
  
  push();
  translate(width/2, height/2);
  rotateY(radians(frameCount /2));
  for (int x = 0; x < tiles; x++) {
   for(int y = 0; y < tiles; y++) {
    
    color c = img.get(int(x*tileSize), int(y*tileSize));
    float b = map(brightness(c),0,255,0,1);
    float z = map(b,0,1,-300, 300);
    
    push();
    translate(x*tileSize - width/2, y*tileSize - height/2, z);
    sphere(tileSize*b*0.8);
    pop();
     
   }
  }
  
  pop();
}

```

 ![SKULL FRONT](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/2/7/27c3bbb1b0b9c40b9550150da48c52cdaa93b06f.jpeg)

Any help greatly appreciated!

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 26, 2025, 6:47pm UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/2 "2025-01-26T18:47:33Z")

</div>

Hello @RevAustin ,

Give this a try:

```auto
 push();
  translate(width/2, height/2, 0);
  //rotateY(radians(frameCount /2));
  //rotateY(TAU/4);
  
  // Focus on this:
  float zw = 200*sin(frameCount%360*(TAU/360));
  println(zw);

  for (int x = 0; x < tiles; x++) {
   for(int y = 0; y < tiles; y++) {
    
    color c = img.get(int(x*tileSize), int(y*tileSize));
    float b = map(brightness(c),0,255,0,1);
    float z = map(b,0,1, 0, zw);
    
   push();
    translate(x*tileSize - width/2, y*tileSize - height/2, z);
    sphere(tileSize*b*0.8);
   pop();     
   }
  }
 pop()

```

`:)`

---

<div class="post-metadata">

**Author:** ![RevAustin](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/revaustin/32/20368_2.png) [@RevAustin](https://discourse.processing.org/u/RevAustin)\
**Post date:** [January 27, 2025, 9:30am UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/3 "2025-01-27T09:30:08Z")

</div>

Amazing! Thanks a bunch @glv !

I’m experimenting with generative art in Processing so I get the use of sin, and I have some understanding that % is modulo, and this can help keep values neatly constrained - is that an okay way of looking at it?

I’ve never seen TAU before, though - looking at the ref for this, am I right in thinking it’s also for keeping something (in this case, sin) constrained but to a set ratio? Trying to get my head around it haha

Thanks again!

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [January 27, 2025, 11:46am UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/4 "2025-01-27T11:46:39Z")

</div>

- TAU is just 2xPI, so TAU is a full circle (using radians instead of degrees)

see [TAU / Reference / Processing.org](https://processing.org/reference/TAU.html)

- `(TAU/360)` is one radians (1 degree measured in radians)

- `frameCount%360` is using modulo (the REST) so this results in a number from 0…360 no matter how big frameCount gets

- it looks better when you use `lights()` - nice but slow

```processing

// Img
PImage img;
// list of spheres
ArrayList <OneSphere> list = new ArrayList();

// -----------------------------------------------------------------

void setup() {
  size(900, 900, P3D);
  img = loadImage("SKULL FRONT.png");
  img.resize(900, 0);
  // make list of spheres
  analyzImage();
  // set some parameters
  sphereDetail(9);
  noStroke();
  // fill(#FFFFFF);
}//func setup

void draw() {
  background(#000000);
  lights(); // nice but slow

  translate(width/2, height/2);
  //rotateY(radians(frameCount / 1));
  rotateY(radians(1 / 3));
  //rotateY(TAU/4);

  // Focus on this:
  float zw = 200*sin(frameCount%180*(TAU/360));

  // loop over the list
  for (OneSphere oneSphere : list) {
    oneSphere.display( zw );
  }
  //
}//func draw

//-------------------------------------------------------------------

void analyzImage() {
  // runs only once
  float tiles = 100;
  float tileSize = width/tiles;

  for (int x = 0; x < tiles; x++) {
    for (int y = 0; y < tiles; y++) {

      color c = img.get(int(x*tileSize), int(y*tileSize));
      if (brightness(c)>250)
        continue;
      float b = map(brightness(c), 0, 255, 0, 1);
      float z = 0; // dummy for map(b, 0, 1, 0, zw);

      list.add (new OneSphere( x*tileSize - width/2, y*tileSize - height/2, z,
        c,
        tileSize*b*0.8));
    }//for
  }//for
}//func

// ==============================================================================

class OneSphere {

  float x, y, z;
  color col;
  float sizeSphere;

  float b;

  //---------

  // constr
  OneSphere(float x_, float y_, float z_,
    color c_, float size_) {
    x=x_;
    y=y_;
    z=z_;

    col=c_;
    b = map(brightness(c_), 0, 255, 0, 1);

    sizeSphere=size_;
  }// constr

  //---------

  void display( float zw ) {
    pushMatrix();
    float z = map(b, 0, 1, 0, zw);
    translate(x, y, z);
    fill(col);
    sphere(sizeSphere);
    popMatrix();
  }//method
  //
} // class
//

```

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 27, 2025, 11:52am UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/5 "2025-01-27T11:52:33Z")

</div>

> [@glv](#):
>
> ```auto
> float zw = 200*sin(frameCount%360*(TAU/360));
> println(zw)
> 
> ```

frameCount%360 will count from 0 to 359 and repeat.  
TAU = TWO\_PI which is in radians.  
TAU/360 divides TAU into 360 parts (in radians) which is equal to 1 degree.  
Or you could have used 0.01745329251 but the fraction provides clarity on the angle increment.

sin() requires radians:

> **[sin() / Reference](https://processing.org/reference/sin_.html)**
>
> Calculates the sine of an angle. This function expects the values of the angle parameter to be provided in radians (values from 0 to 6.28). Values are returned in the range -1 to 1.

Example here (they are using degrees and converting to radians):

> **[Sine Cosine / Examples](https://processing.org/examples/sinecosine.html)**
>
> Linear movement with sin() and cos(). Numbers between 0 and PI2 (TWO\_PI which angles roughly 6.28) are put into these functions and numbers between -1 and 1 are returned. These values are then scaled …

And you will need to know some trigonometry:

> **[Trigonometry](https://en.wikipedia.org/wiki/Trigonometry)**
>
> Trigonometry (from Ancient Greek τρίγωνον (trígōnon) 'triangle' and μέτρον (métron) 'measure') is a branch of mathematics concerned with relationships between angles and side lengths of triangles. In particular, the trigonometric functions relate the angles of a right triangle with ratios of its side lengths. The field emerged in the Hellenistic world during the 3rd century BC from applications of geometry to astronomical studies. The Greeks focused on the calculation of chords, while mat T...

> [@RevAustin](#):
>
> I’m experimenting with generative art in Processing

Have fun!

`:)`

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 27, 2025, 11:58am UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/6 "2025-01-27T11:58:49Z")

</div>

> [@Chrisir](#):
>
> `frameCount%360` is using modulo (the REST) so this results in a number from 0…360 no matter how big frameCount gets

That should be 0…359

`:)`

---

<div class="post-metadata">

**Author:** ![micycle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/micycle/32/201_2.png) [@micycle](https://discourse.processing.org/u/micycle)\
**Post date:** [January 27, 2025, 6:47pm UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/7 "2025-01-27T18:47:58Z")

</div>

I think this is what you’re after. It’s my go-to function for such a thing (although `sin()`-based approach works alright too).

```auto
public static double triangleWaveSmooth(double min, double max, double time, double timePeriod) {
	double amplitude = max - min;
	double phase = (time / timePeriod) % 1.0;
	return amplitude * smoothStep3(Math.abs(2.0 * phase - 1.0)) + min;
}

public static double smoothStep3(double x) {
	return x * x * (3 - 2 * x);
}

```

I tend to call it like this:

```auto
// smoothly oscillate back and forth between 0 and 1, taking 5s to complete one cycle.
double x = triangleWaveSmooth(0, 1, seconds(), 5);

```

Where `seconds()` is:

```auto
long nanoOffset = System.nanoTime(); // declare at program start

public double seconds() {
	return (System.nanoTime() - nanoOffset) / 1e9;
}

```

Using `seconds()` is preferred to `frameCount` because it’s framerate-independent.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 29, 2025, 1:20am UTC](https://discourse.processing.org/t/make-z-axis-alternate-between-growing-and-shrinking/45661/8 "2025-01-29T01:20:31Z")

</div>

> [@micycle](#):
>
> Using `seconds()` is preferred to `frameCount` because it’s framerate-independent.

_frameCount()_ (or a counter) is preferred when capturing frames for animations such as animated GIFs.

`:)`
