 # P3D Vector Spherical Geometry Ball

I want to create a Ball that could go bigger and smaller according to the Music Frequency. (I don’t want to use the sphere(), because it doesn’t create the dot points)
I made it work. But, it is a little bit laggy. At the moment, I could reduce the rows and cols or decrease the player analysis rate to relieve the situation. But, it is still laggy.
I think the main program is the three loops that I had. I tried to minimize them, but I have no idea what I can do.

Just a little bit more, instead of making the whole ball bigger and smaller. If there is anyway that I could make them like a “wave”? Something like perlin noise.

``````/***** IMPORT LIBRARIES *****/
import peasy.*;               // Import Peasy Cam Library. Peasy Cam is a camera library.
import ddf.minim.analysis.*;  // Import Minim Music Library
import ddf.minim.*;           // Import Minim Music Library

/***** Define Some variables ****/
PeasyCam cam;
Minim       minim;
AudioPlayer player;
FFT         fft;

PVector[][]  globe;           // Create a Vector array to save all
int total = 50;               // Rows and Cols of the ball
float angle;                  // Auto Rotate Ball
float c;                      // HSB Dynamic Color

void setup()
{
size(displayWidth, displayHeight, P3D); // Windows Size Not Correct
cam = new PeasyCam(this, 600);          // Cam Size 600. Initial
minim = new Minim(this);                // Initial Minim

globe = new PVector[total+1][total+1];
player.loop();
fft = new FFT( player.bufferSize(), player.sampleRate() );
}

void draw()
{
/***** Basic Setups *****/
background (0);
fft.forward( player.mix ); // Play the music forward

/***** START DRAWING THE BALL *****/
angle += PI/18;             // + 10 Degree
rotateX(PI/2);              // Rotate the Ball along the X
rotateY(angle);             // Rotate the Ball along the Y with 10 degree
colorMode(HSB);             // Set Color Mode to HSB
if (c >= 255)               // Increase the c
{
c = 0;
} else
{
c++;
}
stroke(c, 255, 255);         // Hue/Saturation/Brightness. Change the HUE and keep Saturation and Brighness 255
float r = 200;               // Radius of the ball
for (int a = 0; a < fft.specSize(); a++)
{
/*****

Complicated Spherical Geometry Calculation
From YouTube The Coding Train: Spherical Geometry.

*****/
for (int i = 0; i < total+1; i++)
{
float lon = map(i, 0, total, -PI, PI);
for (int j = 0; j < total+1; j++)
{

float lat = map(j, 0, total, -HALF_PI, HALF_PI);
float x = r * sin(lon) * cos(lat);
float y = r * sin(lon) * sin(lat);
float z = r * cos(lon);
globe [i][j] = new PVector(x, y, z);

/*****
Returns the Perlin noise value at specified coordinates.
Perlin noise is a random sequence generator producing a more natural,
harmonic succession of numbers than that of the standard random() function.
*****/
point(x*noise(fft.getFreq(a)), y*noise(fft.getFreq(a)), z*noise(fft.getFreq(a)));
}
}
}
}
``````

65 * 51 * 51 loop might give you that LAG

try more easy first:

``````import peasy.*;               // Import Peasy Cam Library camera library.
import ddf.minim.*;           // Import Minim Music Library
import ddf.minim.analysis.*;

PeasyCam cam;
Minim       minim;
AudioPlayer player;
FFT         fft;

void setup_sound() {
minim = new Minim(this);
player.loop();
fft = new FFT( player.bufferSize(), player.sampleRate() );
println("fft.specSize: "+fft.specSize());
}

int total = 25;
float r0 =30, zoom = 0.5;

void setup() {
size(500, 500, P3D);
stroke(200, 0, 0);  //noStroke();
strokeWeight(5);
noFill();
setup_sound();
cam = new PeasyCam(this, 100);
}

void draw() {
background(200, 200, 0);
fft.forward( player.mix );
surface.setTitle(nf(frameRate, 0, 1)+"FPS");
ball();
}

void ball() {
float r=0;
for (int i = 0; i < total; i++) {
float lon = map(i, 0, total, -PI, PI);
for (int j = 0; j < total; j++) {
r = r0 + zoom * fft.getBand(j);//(i+i*j);
float lat = map(j, 0, total, -HALF_PI, HALF_PI);
float x = r * sin(lon) * cos(lat);
float y = r * sin(lon) * sin(lat);
float z = r * cos(lon);
point(x, y, z);
}
}
}

``````

works here ( Win10 / Processing 3.5.3 / medium hardware ) with 50 FPS
i try stay as close as possible to your example, but actually not get why the
sound analysis FFT must again mixed with noise, so i skipped that

1 Like

A lot of stuff is constant and could be pre-calculated in setup ().

Eg lon
lat
and sin * cos

Hence you can store them in a class (Arraylist of it) and derive from there. Especially map and sin and cos are slow. It’s called look up table. Can be faster.

Only r is really variable

1 Like

I made one version of this idea with a class and an ArrayList of it (not showing here).

Then I shortened this to an Array of PVector:

``````
// https://discourse.processing.org/t/p3d-vector-spherical-geometry-ball/14083/3

import peasy.*;               // Import Peasy Cam Library camera library.
import ddf.minim.*;           // Import Minim Music Library
import ddf.minim.analysis.*;  // Import

PeasyCam    cam;
Minim       minim;
AudioPlayer player;
FFT         fft;

int total = 25;
float r0 =30,
zoom = 0.5;

// ArrayList<Data> data = new ArrayList();
PVector[] data = new PVector [total*total];

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

void setup() {
size(500, 500, P3D);
stroke(200, 0, 0);  //noStroke();
strokeWeight(5);
noFill();
setup_sound();
cam = new PeasyCam(this, 100);
}

void draw() {
background(200, 200, 0);
fft.forward( player.mix );
surface.setTitle(nf(frameRate, 0, 1)+" FPS");
// text (int(frameRate)+" FPS", 33, 33);
ball();
}

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

void ball() {
// runs on and on
// uses data
int j=0;
float r, x, y, z;
for (PVector myData : data) {
r = r0 + zoom * fft.getBand(j);//(i+i*j);
x = r * myData.x;
y = r * myData.y;
z = r * myData.z;
//
point(x, y, z);
j++;
}//for
}//func

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

void setup_sound() {
// runs only ONCE
minim = new Minim(this);
if (player!=null) {
// success
player.loop();
fft = new FFT( player.bufferSize(), player.sampleRate() );
println("fft.specSize: "+fft.specSize());
ball_Init();
} else {
// error
println("Abort");
exit();
}//else
}//func

void ball_Init() {
// runs only ONCE
// stripped down version of the old ball to fill the Array data
// float r=0;
int k=0;
for (int i = 0; i < total; i++) {
float lon = map(i, 0, total, -PI, PI);
for (int j = 0; j < total; j++) {
//r = r0 + zoom * fft.getBand(j);//(i+i*j);
float lat = map(j, 0, total, -HALF_PI, HALF_PI);
//float x = r * sin(lon) * cos(lat);
//float y = r * sin(lon) * sin(lat);
//float z = r * cos(lon);
PVector preparation = new PVector(0, 0, 0);
preparation.x = sin(lon) * cos(lat);
preparation.y = sin(lon) * sin(lat);
preparation.z = cos(lon);
data[k] = preparation.copy();
// point(x, y, z);
k++;
}
}
}
//
``````
1 Like

I have to admit my version is crab.

It’s not faster but it also looks bad, much much worse than yours.

Which is strange, it must be because I store the results in PVector which maybe has not the precision Java works with internally (double?).

E.g. in this line: `float x = r * sin(lon) * cos(lat);`

I could try to store as double… see below.

still looks crab. The amplitude is much smaller than in your sketch

I am sorry I couldn’t be of help

Chrisir

(version where I unsuccessfully store as double (in a class))

``````
// https://discourse.processing.org/t/p3d-vector-spherical-geometry-ball/14083/3

import peasy.*;               // Import Peasy Cam Library camera library.
import ddf.minim.*;           // Import Minim Music Library
import ddf.minim.analysis.*;  // Import

PeasyCam    cam;
Minim       minim;
AudioPlayer player;
FFT         fft;

int total = 25;
float r0 = 30,
zoom = 0.5;

ArrayList<Data> data = new ArrayList();

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

void setup() {
size(500, 500, P3D);
stroke(200, 0, 0);  //noStroke();
strokeWeight(5);
noFill();
setup_sound();
cam = new PeasyCam(this, 100);
}

void draw() {
background(200, 200, 0);
fft.forward( player.mix );
surface.setTitle(nf(frameRate, 0, 1)+" FPS");
// text (int(frameRate)+" FPS", 33, 33);
ball();
}

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

void ball() {
// runs on and on
// uses ArrayList<Data> data
int j=0;
double r, x, y, z;
for (Data myData : data) {
r = r0 + zoom * fft.getBand(j);//(i+i*j);
x = r * myData.preparationX;
y = r * myData.preparationY;
z = r * myData.preparationZ;
//
point((float)x, (float) y, (float) z);
j++;
}//for
}//func

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

void setup_sound() {
// runs only ONCE
minim = new Minim(this);
if (player!=null) {
// success
player.loop();
fft = new FFT( player.bufferSize(), player.sampleRate() );
println("fft.specSize: "+fft.specSize());
ball_Init();
} else {
// error
println("Abort");
exit();
}//else
}//func

void ball_Init() {
// runs only ONCE
// stripped down version of the old ball to fill the ArrayList<Data> data
// float r=0;
for (int i = 0; i < total; i++) {
float lon = map(i, 0, total, -PI, PI);
for (int j = 0; j < total; j++) {
//r = r0 + zoom * fft.getBand(j);//(i+i*j);
float lat = map(j, 0, total, -HALF_PI, HALF_PI);
//float x = r * sin(lon) * cos(lat);
//float y = r * sin(lon) * sin(lat);
//float z = r * cos(lon);
Data newData = new Data();
newData.preparationX = sin(lon) * cos(lat);
newData.preparationY = sin(lon) * sin(lat);
newData.preparationZ = cos(lon);
// point(x, y, z);
}
}
}

// ================================================================
// classes

class Data {
double preparationX = 0;
double preparationY = 0;
double preparationZ = 0;
}//class
//
``````
1 Like

Have you thought about creating a single sphere of fixed size and then use scale when rendering it.

no, my idea was to map the FFT on the sphere:

just to change its size / scale, BUT
fft.specSize() * frameRate /sec
is too heavy and ?invisible? and anyhow much like the BEAT example

@Chrisir test switchable
``````import peasy.*;               // Import Peasy Cam Library camera library.
import ddf.minim.*;           // Import Minim Music Library
import ddf.minim.analysis.*;

PeasyCam cam;
Minim       minim;
AudioPlayer player;
FFT         fft;

void setup_sound() {
minim = new Minim(this);
player.loop();
fft = new FFT( player.bufferSize(), player.sampleRate() );
println("fft.specSize: "+fft.specSize());
}

int total = 50;
float r0 =30, zoom = 0.2;
float[][][] ksphere = new float[total][total];
boolean atChrisir = false; //true;

void setup_ksphere() {                                    // @Chrisir
for (int i = 0; i < total; i++) {
float lon = map(i, 0, total, -PI, PI);
for (int j = 0; j < total; j++) {
float lat = map(j, 0, total, -HALF_PI, HALF_PI);
ksphere[i][j] = sin(lon) * cos(lat);
ksphere[i][j] = sin(lon) * sin(lat);
ksphere[i][j] = cos(lon);
}
}
}

void setup() {
size(500, 500, P3D);
stroke(200, 0, 0);  //noStroke();
strokeWeight(5);
noFill();
setup_sound();
if ( atChrisir ) setup_ksphere();
cam = new PeasyCam(this, 100);
}

void draw() {
background(200, 200, 0);
fft.forward( player.mix );
surface.setTitle(nf(frameRate, 0, 1)+"FPS");
ball();
}

void ball() {
float x=0, y=0, z=0, lon=0, lat=0, r=0;
for (int i = 0; i < total; i++) {
if ( !atChrisir ) lon = map(i, 0, total, -PI, PI);
for (int j = 0; j < total; j++) {
r = r0 + zoom * fft.getBand(j);//(i+i*j);
if ( !atChrisir ) {
lat = map(j, 0, total, -HALF_PI, HALF_PI);
x = r * sin(lon) * cos(lat);
y = r * sin(lon) * sin(lat);
z = r * cos(lon);
} else {
x = r * ksphere[i][j];
y = r * ksphere[i][j];
z = r * ksphere[i][j];
}
point(x, y, z);
}
}
}

``````

You are super awesome!!! That’s really useful! It works on my laptop as well. Also, if I want to create the ball surface like wave/mountain shape. Do you have any ideas about it? Is it even possible? A surface like this: https://www.youtube.com/watch?v=IKB1hWWedMk. Maybe. (Don’t worry about the Triangle strips)

The complicated part is how to match the FFT with the vertex. So, instead of defining the r in your example. I might need to define the point directly. What do you think? >_<

I think it is going to be a little bit complicated. You don’t really need to give me the whole code. Just some thought should be enough.

1 Like

no, but he has: