Skip to content

Instantly share code, notes, and snippets.

@companje
Created February 27, 2024 06:55
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/d7bef829be4e460dd69d1298e0323784 to your computer and use it in GitHub Desktop.
Save companje/d7bef829be4e460dd69d1298e0323784 to your computer and use it in GitHub Desktop.
Sphere
Quaternion q = new Quaternion(1, 0, 0, 0);
ArrayList<PVector> dots = new ArrayList();
PImage tex;
PShape sphere;
PShader shader;
void setup() {
size(900, 900, P3D);
tex = loadImage("earth.jpg");
sphere = createShape(SPHERE, height/2);
sphere.rotateY(HALF_PI);
sphere.setTexture(tex);
sphere.setStroke(false);
shader = loadShader("lens.glsl");
textSize(20);
}
void draw() {
ortho();
background(0);
translate(width/2, height/2);
PVector uv = sphereToUV(q.getInverse().rotate(mouseToSphere()));
//shader.set("dotPos", uv.x, uv.y);
//NU NOG ARRAY TOEVOEGEN. EN MISSCHIEN EEN VARIABELE VAN HOEVEEL LENSEN ER ZIJN
//BIJNA KLAAR
for (int i=0; i<dots.size(); i++)
shader.set("lensCenter["+i+"]",q.getInverse().rotate(mouseToSphere()));
shader.set("zoom",2.0);
shader.set("numLenses",dots.size());
//uniform vec3 lensCenter;
//uniform float zoom;
pushMatrix();
q.apply(this);
shader(shader);
shape(sphere);
resetShader();
for (PVector dot : dots) {
pushMatrix();
translate(dot.x, dot.y, dot.z);
fill(255, 255, 0);
noStroke();
sphere(10);
popMatrix();
}
popMatrix();
fill(255, 255, 0);
text(sphereToLatLon(q.getInverse().rotate(mouseToSphere()))+"", 25-width/2, 50-height/2);
}
void mouseDragged() {
PVector from = screenToSphere(pmouseX, pmouseY);
PVector to = mouseToSphere();
q.drag(from, to);
}
void mouseClicked() {
PVector dot = q.getInverse().rotate(mouseToSphere()).setMag(height/2);
dots.add(dot);
}
PVector toSphere(float x, float y) { //-1..1 to unit sphere
PVector v = new PVector(x, y);
if (v.mag()>1.0f) v.normalize();
else v.z = sqrt(1.0-v.magSq());
return v.normalize();
}
PVector screenToSphere(float x, float y) { //screen coords to unit sphere
return toSphere(map(x, 0, width, -1, 1), map(y, 0, height, -1, 1));
}
PVector mouseToSphere() {
return screenToSphere(mouseX, mouseY);
}
PVector sphereToUV(PVector p ) {
float u = (atan2(p.z, -p.x) / TWO_PI + 1.25 ) % 1;
float v = 1-acos(p.y)/PI;
return new PVector(u, v);
}
PVector sphereToLatLon(PVector p) {
PVector uv = sphereToUV(p);
float lat = map(uv.x, 0, 1, -180, 180);
float lon = map(uv.y, 0, 1, 90, -90);
return new PVector(lat, lon);
}
class Quaternion {
float w, x, y, z;
Quaternion(float w, float x, float y, float z) {
set(w, x, y, z);
}
void set(Quaternion q) {
set(q.w,q.x,q.y,q.z);
}
void set(float w, float x, float y, float z) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
void normalize() {
set(normalized());
}
Quaternion normalized() {
float mag = sqrt(w*w + x*x + y*y + z*z);
return new Quaternion(w/mag, x/mag, y/mag, z/mag);
}
Quaternion mult(Quaternion q) {
set(
w*q.w - x*q.x - y*q.y - z*q.z,
w*q.x + x*q.w + y*q.z - z*q.y,
w*q.y - x*q.z + y*q.w + z*q.x,
w*q.z + x*q.y - y*q.x + z*q.w
);
return this;
}
PVector rotate(PVector v) {
Quaternion vecQuat = new Quaternion(0, v.x, v.y, v.z);
Quaternion conjQuat = this.getInverse();
Quaternion rotatedQuat = this.mult(vecQuat).mult(conjQuat);
return new PVector(rotatedQuat.x, rotatedQuat.y, rotatedQuat.z);
}
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);
}
void apply(PGraphics g) {
PVector axis = new PVector();
float[] angle = new float[1];
q.toAxisAngle(axis, angle);
g.rotate(angle[0], axis.x, axis.y, axis.z);
}
void apply(PApplet app) {
apply(app.g);
}
void drag(PVector from, PVector to) {
PVector axis = from.cross(to);
float angle = from.dot(to);
Quaternion q_drag = new Quaternion(cos(angle / 2),
axis.x * sin(angle / 2),
axis.y * sin(angle / 2),
axis.z * sin(angle / 2));
set(q_drag.mult(this));
normalize();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment