When putting points on the edge of a 2D circle you can do the following.
let r = 50;
for(i = 0; i < 360; i ++){
ellipse(cos(i) * r, sin(i) * r,3);
}
There has to be an equivalent for spheres without cheating it right?
When putting points on the edge of a 2D circle you can do the following.
let r = 50;
for(i = 0; i < 360; i ++){
ellipse(cos(i) * r, sin(i) * r,3);
}
There has to be an equivalent for spheres without cheating it right?
// https://discourse.processing.org/t/i-want-the-pvector-after-rotate/30744
// https://discourse.processing.org/t/i-want-the-pvector-after-rotate/30744/7
import peasy.*;
PeasyCam pCamera;
ArrayList<PVector> list = new ArrayList();
PVector v = new PVector();
PVector center,
myPV, myPV2;
void setup() {
size(800, 800, P3D);
center = new PVector(0, 0, 0);
pCamera = new PeasyCam(this, 300);
v = new PVector(40, 0, 0);
for (int i=0; i<=360; i+=10) {
makeCircle(v);
rotateY(radians(10));
}
}
void draw() {
background(255);
lights();
fill( 0, 0, 255);
spherePV(center, 4);
fill( 255, 0, 0);
for (PVector pv : list) {
spherePV(pv, 2);
}
}
//--------------------------------------------------------------------------------------
void makeCircle(PVector pv) {
for (int i = 3; i<360; i+=17) {
pushMatrix();
rotateZ(radians(i));
translateAndAddToList(pv);
popMatrix();
}//for
}
//--------------------------------------------------------------------------------------
void translateAndAddToList(PVector pv) {
pushMatrix();
translatePV(pv);
PVector myPV = new PVector(modelX(0, 0, 0), modelY(0, 0, 0), modelZ(0, 0, 0) );
list.add(myPV);
popMatrix();
}
void translatePV(PVector pv) {
// one nice wrapper for build in translate-command
translate(pv.x, pv.y, pv.z);
}
void spherePV(PVector pv,
float size1) {
// one nice wrapper for build in sphere-command
pushMatrix();
noStroke();
// fill(255, 0, 0);
translate(pv.x, pv.y, pv.z);
sphere(size1);
popMatrix();
}
p5js, Isn’t there a format with two for loops maybe?
There are 2 for loops
@olaf000olaf You can think of a sphere as a whole bunch of circles stacked on top of each other, the circles near the middle have a radius from the axis of the sphere that is nearly equal to the radius of the sphere, the circles near the poles have a radius from the axis that approaches zero. The curve that the relationship of the radius of each circle to the height in the sphere follows is the same as the curve for a circle. In order to map angles to points on a sphere you need two angles: elevation (from 90° straight up to -90° straight down), and the azimuth (from 0° to 360°). To find the Cartesian coordinates for the point on a sphere given those angles you can first find the radius of the circle at that elevation (circle_radius = sphere_radius * cos(elevation)
) and the y
component of the vector (y = sphere_radius * sin(elevation)
). Then you can use the circle_radius
and the azimuth
angle to find the x
and z
components (x = circle_radius * cos(azimuth)
and z = circle_radius * zin(azimuth)
.
Here’s a quick example:
const radius = 100;
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
angleMode(DEGREES);
}
function draw() {
orbitControl(2, 1, 0.05);
background(0);
strokeWeight(2);
stroke('lime');
for (let e = -80; e <= 80; e += 10) {
let cr = radius * cos(e);
let y = radius * sin(e);
for (let a = 0; a < 360; a += 20) {
let x = cr * cos(a);
let z = cr * sin(a);
point(x, y, z);
}
}
}
here is a kind of firework in 3D
(sorry, KumuPaul, I saw your post too late)
// 3D sketch : Fireworks
// You can see the sketch as a stage where you can place different Main Items on.
// In this case the Main Item is Fireworks.
// To change the Main Item, see initMainItem() and showMainItem() in their two tabs.
// Other elements are pure decoration, like clouds, trees, CSG etc.
//You can also switch Video Export on and off. See the variable videoExportIsOn.
// https://youtu.be/xNfS3uOd6P8
// https://youtu.be/46qwczx1jx8
import com.hamoid.*;
final int GENERAL_Y_HEIGHT = 500;
ArrayList<Spark> sparks = new ArrayList();
int divider=2;
// the PShape reference which will contain the converted
PShape csgResult;
// ***************************************************************************
boolean videoExportIsOn = true;// ********************************************
// ***************************************************************************
VideoExport videoExport;
PVector camPos = new PVector(width/2.0, height/2.0, 990);
PVector camLookAt = new PVector(width/2.0, height/2.0, -600);
PVector camUp = new PVector( 0, 1, 0 );
// -----------------------------------------------------
void setup() {
size (1400, 800, P3D);
sphereDetail(18);
initExplosion() ;
// hamoid video export
if (videoExportIsOn) {
videoExport = new VideoExport(this);
println( "Start with s // Use e for videoExport.endMovie");
videoExport.startMovie();
} else {
println( "videoExport IS OFF +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
}
} // func
void draw() {
// clear & prepare canvas
background(220);
lights();
// apply vectors to actual camera
camera (camPos.x, camPos.y, camPos.z,
camLookAt.x, camLookAt.y, camLookAt.z,
camUp.x, camUp.y, camUp.z);
// ***************************************************************************
// show Main Item - the core of draw()
showMainItem();
// ***************************************************************************
// show center
// scene.showCenters(); // two spheres
// text upper left corner
fill(0, 255, 0);
//// hamoid video export
//if (videoExportIsOn) {
// videoExport.saveFrame();
//}
//
} // func
void initExplosion() {
float extensionHalf=500;
int colType=int(random (7));
float x= random(-extensionHalf, extensionHalf);
float y= random(-44, GENERAL_Y_HEIGHT-222); // random(33, 220);
float z= random(-extensionHalf, extensionHalf);
for (int i=0; i<990; i++) {
Spark spark = new Spark(width/2, height-4, 4, 0);
sparks.add(spark);
spark.startSpark( x, y, z,
colType );
}
}
void showMainItem() {
// main item of the sketch
// manage sparks / shrapnels
if (keyPressed) {
noStroke();
}
// The core:
for (Spark spark : sparks) {
spark.move();
spark.display();
spark.script();
}
// remove dead ones
for (int i=sparks.size()-1; i>=0; i--) {
if (sparks.get(i).isDead)
sparks.remove(i);
}
// spawn new
if (frameCount%divider == 0) {
initExplosion();
divider=int(random(53, 133));
}
}
//
void endSketch() {
// hamoid video export
if (videoExportIsOn) {
videoExport.endMovie();
exit();
}
}
// ---------------------------------------------------------------------------------------
void myBox(float x, float y, float z, // pos
float w, float h, float d) { // size
// nice wrapper for build in box-command
//w float: dimension of the box in the x-dimension
//h float: dimension of the box in the y-dimension
//d float: dimension of the box in the z-dimension
pushMatrix();
translate(x, y, z);
box(w, h, d);
popMatrix();
}
void mySphere(float x, float y, float z,
float size1) {
// nice wrapper for build in sphere-command
pushMatrix();
translate(x, y, z);
sphere(size1);
popMatrix();
}
String videoExportIsOnToString() {
if (videoExportIsOn)
return " with Video Export.";
else return " no Video Export.";
}
//
//=====================================================
class Spark {
float x, y, z; // current position
float x1, y1, z1; // initial position
float diameter; // diameter
color col;
//states
final int stateWait=0; // unique numbers
final int stateTriggered=1;
final int stateJump=2;
int stateSpark = stateWait;
int timer;
int duration;
boolean isDead=false;
float xadd, yadd, zadd;
// new approach
PVector gear0=new PVector(0, 0, 0);
float Theta;
float u;
// new approach
float Tau100 = (TAU/100);
float i2=random(100);
float i3=random(100);
// Constructor
Spark(float x_in, float y_in, float z_in,
float diameter_in) {
x = x_in;
y = y_in;
z = z_in;
xadd=0;
yadd=0;
zadd=0;
diameter = diameter_in;
}// Constructor
void move() {
// Spark move
Theta = Tau100 * i2;
u = map (i3, 0, 100, -1, 1);
x = x1+ gear0.x*cos(Theta)*sqrt(1-(u*u));
z = y1+ gear0.y*sin(Theta)*sqrt(1-(u*u));
y = z1+ gear0.z*u;
gear0.add(xadd, yadd, zadd);
// it dies
if (diameter<=0.25)
isDead=true;
diameter -= 0.041; // how fast it shrinks / and then dies
} // function
// start spark
void startSpark( float x_, float y_, float z_,
int colType ) {
// duration for this spark to start after ignition
duration=int(random(4, 379)); // int(random(40, 190));
stateSpark=stateTriggered;
x1=x_;
y1=y_;
z1=z_;
diameter=random(1.5, 3.7);
switch (colType) {
case 0:
col = color(random(256), random(256), random(256));
break;
case 1:
col = color(random(256), 0, 0);
break;
case 2:
col = color(random(256));
break;
case 3:
col = color(random(254, 256));
break;
case 4:
// blue or white
if (random(100)>50)
col = color(0, 0, random(254, 256));//blue
else col = color(random(254, 256)); // white
break;
case 5:
// A or B
if (random(100)>50)
col = color(random(50, 256), random(50, 256), random(50, 256));
else col = color(random(256), random(256), random(256));
break;
default:
col = color(random(33), random(22), random(256));
break;
}//switch
timer=millis();
}
void script() {
switch(stateSpark) {
case stateWait:
// wait
break;
case stateTriggered:
if (millis()-timer>duration)
stateSpark=stateJump;
break;
case stateJump:
startExplosion();
stateSpark=0;
break;
default:
println("Error 114");
exit();
break;
}//switch
}//method
void startExplosion() {
//starts explosion
// radius_Add=random(2.1, 9.4);
xadd=random(2.4, 3.3) ;
yadd=random(2.4, 3.3) ;
zadd=random(2.4, 3.3) ;
if (random(100)>50)
xadd*=-1;
if (random(100)>50)
yadd*=-1;
if (random(100)>50)
zadd*=-1;
}// function
void display() {
// Spark display
pushMatrix();
translate(x, y, z);
fill(col);
//if (!keyPressed)
// ellipse(x, y, diameter, diameter);
// else
sphere(diameter);
popMatrix();
//
}// function
//
}//class
//
Here is an example that adds a bit more visualization for where the trig components fit in: Trig Sphere - OpenProcessing
It’s all just triangles all the way down.
No problem, but I’m confused. The OP is asking about math for positions on a sphere and p5.js and you’re sharing complicated sketches written in Processing that happen to include some spherical coordinate math. As cool as that sketch may be I’m not sure it is particularly helpful to the OP.
That’s a good point! I thought he could just copy the relevant lines and translate them?
Hello,
I found this to be a good reference:
A Processing Java version implementing above:
float theta; // θ
float phi; // φ
float x, y, z;
int r = 100;
// TAU = TWO_PI in radians which is 360 degrees
void sphere01()
{
for(int j = 0; j<=8; j++) //theta loop
{
theta = j*(TAU/2)/8;
for(int i = 0; i<32; i++) //phi loop
{
phi = i*TAU/32;
// From Wikipedia
//x = r*cos(phi)*sin(theta);
//y = r*sin(phi)*sin(theta);
//z = r*cos(theta);
// Swapped z and y axes
x = r*cos(phi)*sin(theta);
z = r*sin(phi)*sin(theta);
y = r*cos(theta);
strokeWeight(4);
stroke(255, 0, 0);
point(x, y, z);
}
}
}
You can optimize by putting the theta calculations in the inner loop to the outer loop.
I tend to work directly with radians; that is just a personal choice.
@KumuPaul has the optimized version at first glance.
:)
For 2D there is a fast algorithm, 3D I don’t know:
https://www.vicanek.de/articles/QuadOsc.pdf