Created
February 12, 2025 20:01
-
-
Save companje/10c44743911955ea71cca39355b7d206 to your computer and use it in GitHub Desktop.
3D Sphere to CubeMap to Equirectangular texture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PImage earth; | |
PShape globe; | |
PGraphics fbo[] = new PGraphics[6]; | |
int cubemapSize = 1024; | |
PImage output_texture; | |
PImage tex; | |
PGraphics view3D,ortho3D; | |
float h, hd2; | |
PVector center[] = { | |
new PVector(-1, 0, 0), // afrika | |
new PVector(1, 0, 0), // japan (wrap) | |
new PVector(0, -1, 0), // noordpool | |
new PVector(0, 1, 0), // zuidpool | |
new PVector(0, 0, 1), // india | |
new PVector(0, 0, -1) // zuid-amerika | |
}; | |
PVector up[] = { | |
new PVector(0, -1, 0), // afrika | |
new PVector(0, 1, 0), // japan (wrap) | |
new PVector(0, 0, 1), // noordpool | |
new PVector(0, 0, -1), // zuidpool | |
new PVector(0, -1, 0), // india | |
new PVector(0, 1, 0) // zuid-amerika | |
}; | |
PVector rotateY(PVector v, float angle) { | |
return new PVector( | |
cos(angle) * v.x + sin(angle) * v.z, | |
v.y, | |
-sin(angle) * v.x + cos(angle) * v.z | |
); | |
} | |
void setup() { | |
size(1536, 512, P3D); | |
h=height; | |
hd2=h/2; | |
earth = loadImage("earth.jpg"); | |
tex = createImage(1024, 512, RGB); | |
view3D = createGraphics((int)h, (int)h, P3D); | |
ortho3D = createGraphics((int)h, (int)h, P3D); | |
globe = createShape(SPHERE, hd2); | |
globe.rotateY(HALF_PI); | |
globe.setStroke(false); | |
globe.setTexture(earth); | |
for (int i = 0; i < 6; i++) { | |
fbo[i] = createGraphics(cubemapSize, cubemapSize, P3D); | |
} | |
} | |
void draw() { | |
background(0); | |
renderToTexture(fbo, tex); | |
image(tex, h, 0, h*2, h); | |
renderToDome(view3D); | |
image(view3D, 0, 0); | |
renderOrtho(ortho3D); | |
image(ortho3D, 0, 0); | |
} | |
void render(PGraphics pg) { | |
pg.background(0); | |
pg.shape(globe); | |
pg.translate(0, 0, 185); | |
pg.fill(255, 255, 0); | |
pg.textAlign(CENTER); | |
pg.textSize(30); | |
pg.text("HELLO PROJECTION", 0, 0); | |
} | |
void renderOrtho(PGraphics pg) { | |
pg.beginDraw(); | |
pg.ortho(); | |
pg.camera(0, 0, 0, 0, 0, hd2, 0, 1, 0); | |
pg.scale(-1, 1, 1); | |
render(pg); | |
pg.endDraw(); | |
} | |
void renderToDome(PGraphics pg) { | |
float eyeZ = 1900, distToCam = 1900; | |
pg.beginDraw(); | |
pg.perspective(atan(hd2/distToCam)*2, 1, distToCam, 10000); | |
pg.camera(0, 0, -distToCam, 0, 0, 0, 0, 1, 0); | |
pg.scale(-1, 1, 1); | |
render(pg); | |
pg.endDraw(); | |
} | |
void renderToTexture(PGraphics fbo[], PImage tex) { //via cubemap | |
int c[][] = { | |
{0, 0, 1, 0, -1, 0}, | |
{0, 0, -1, 0, 1, 0}, | |
{0, -1, 0, 1, 0, 0}, | |
{0, 1, 0, -1, 0, 0}, | |
{1, 0, 0, 0, -1, 0}, | |
{-1, 0, 0, 0, 1, 0}}; | |
for (int i = 0; i < 6; i++) { | |
fbo[i].beginDraw(); | |
fbo[i].camera(0, 0, 0, c[i][0], c[i][1], c[i][2], c[i][3], c[i][4], c[i][5]); | |
fbo[i].perspective(HALF_PI, 1.0, 1, 1000); | |
render(fbo[i]); | |
fbo[i].endDraw(); | |
fbo[i].loadPixels(); | |
} | |
convertToTexture(tex, 1024, 512); | |
} | |
PImage convertToTexture(PImage tex, int w, int h) { | |
tex.loadPixels(); | |
for (int y = 0; y < h; y++) { | |
for (int x = 0; x < w; x++) { | |
float u = map(x, 0, w, -PI, PI); | |
float v = map(y, 0, h, HALF_PI, -HALF_PI); | |
PVector dir = new PVector(cos(v) * cos(u), sin(v), cos(v) * sin(u)); | |
tex.pixels[y * w + x] = sampleFromCubemap(dir); | |
} | |
} | |
tex.updatePixels(); | |
return tex; | |
} | |
color sampleFromCubemap(PVector dir) { | |
float ax = abs(dir.x), ay = abs(dir.y), az = abs(dir.z); | |
boolean xGreatest = ax >= ay && ax >= az, yGreatest = ay >= az; | |
int face = xGreatest ? (dir.x > 0 ? 0 : 1) : | |
yGreatest ? (dir.y > 0 ? 2 : 3) : | |
dir.z > 0 ? 4 : 5; | |
float uc = xGreatest ? dir.z / ax : | |
yGreatest ? dir.x / ay : | |
-dir.x / az; | |
float vc = (face % 2 == 0 ? 1 : -1) * | |
(xGreatest ? dir.y / ax : | |
yGreatest ? dir.z / ay : | |
dir.y / az); | |
int px = int(map(uc, -1, 1, 0, fbo[face].width - 1)); | |
int py = int(map(vc, -1, 1, 0, fbo[face].height - 1)); | |
return fbo[face].pixels[py*fbo[face].width+px]; | |
} |
Author
companje
commented
Feb 12, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment