Skip to content

Instantly share code, notes, and snippets.

@companje
Last active February 24, 2024 15:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save companje/832c33c61d9b6b39e4b30193419373da to your computer and use it in GitHub Desktop.
Save companje/832c33c61d9b6b39e4b30193419373da to your computer and use it in GitHub Desktop.
Sphere ArcBall rotate with Quaternion, also with inverse rotation
Quaternion q = new Quaternion(1, 0, 0, 0);
PShape globe;
PImage tex;
ArrayList<PVector> points = new ArrayList();
float radius;
void setup() {
size(800, 800, P3D);
tex = loadImage("earth.jpg");
radius = height/2;
globe = createShape(SPHERE, radius);
globe.rotateY(HALF_PI);
globe.setTexture(tex);
globe.setStroke(false);
for (int i=0; i<20; i++) {
PVector p = PVector.random3D();
p.setMag(radius);
points.add(p);
}
}
void draw() {
background(0);
ortho();
lights();
translate(width/2, height/2);
//grote bol
PVector axis = new PVector();
float[] angle = new float[1];
q.toAxisAngle(axis, angle);
fill(255);
stroke(0);
pushMatrix();
rotate(angle[0], axis.x, axis.y, axis.z);
shape(globe);
//red dots that turn yellow when mouse nearby
for (PVector point : points) {
pushMatrix();
translate(point.x, point.y, point.z);
if (dist(mouseX,mouseY,screenX(0,0,0),screenY(0,0,0))<20) {
fill(255, 255, 0);
} else {
fill(255, 0, 0);
}
noStroke();
sphere(5);
popMatrix();
}
popMatrix();
}
void mouseDragged() {
float angle = dist(mouseX, mouseY, pmouseX, pmouseY) * 0.005;
PVector axis = new PVector(pmouseY - mouseY, mouseX - pmouseX, 0).normalize();
Quaternion dragQuaternion = new Quaternion(
cos(angle / 2),
axis.x * sin(angle / 2),
axis.y * sin(angle / 2),
axis.z * sin(angle / 2));
q = dragQuaternion.mult(q);
q.normalize();
}
class Quaternion {
float w, x, y, z;
Quaternion(float w, float x, float y, float z) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
// Normaliseer de quaternion
void normalize() {
float mag = sqrt(w*w + x*x + y*y + z*z);
w /= mag;
x /= mag;
y /= mag;
z /= mag;
}
// Quaternion vermenigvuldiging
Quaternion mult(Quaternion q) {
return new Quaternion(
this.w*q.w - this.x*q.x - this.y*q.y - this.z*q.z,
this.w*q.x + this.x*q.w + this.y*q.z - this.z*q.y,
this.w*q.y - this.x*q.z + this.y*q.w + this.z*q.x,
this.w*q.z + this.x*q.y - this.y*q.x + this.z*q.w
);
}
void toAxisAngle(PVector axis, float[] angle) {
normalize(); // Ensure the quaternion is normalized
angle[0] = 2 * acos(w);
float s = sqrt(1 - w * w);
if (s < 0.001) { // Test to avoid divide by zero, s is always positive due to sqrt
// If s close to zero then direction of axis not important
axis.x = x; // If it is important that axis is normalized then replace with x=1; y=z=0;
axis.y = y;
axis.z = z;
} else {
axis.x = x / s; // Normalize axis
axis.y = y / s;
axis.z = z / s;
}
}
Quaternion getInverse() {
return new Quaternion(w, -x, -y, -z);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment