Skip to content
This repository was archived by the owner on Jun 24, 2024. It is now read-only.

Commit 0e0ace5

Browse files
authored
Merge pull request #4 from diroru/master
Pull request for the project’s raytracing-based revisit.
2 parents 63b0518 + 5df55a8 commit 0e0ace5

File tree

8 files changed

+815
-419
lines changed

8 files changed

+815
-419
lines changed

README.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,30 @@ The planetarium library is intended to project 3D Processing sketches on spheric
22

33
It is based on the FullDomeTemplate code from Christopher Warnow, available at https://github.com/mphasize/FullDome
44

5-
### Overview
5+
### Work in progress
66

7-
A brief descrition of how it works: a 360° view of the scene is generated by rendering the scene 6 times from each direction: positive x, negative x, and so on. The output of each rendering is stored inside a cube map texture, which is then applied on a sphere representing the dome. Hence, the library calls the draw() method 6 times per frame in order to update the corresponding side of the cube map texture (in reality, only 5 times since the bottom side of the cube map is not invisible on the dome).
7+
**DONE:**
8+
9+
- More accurate rendering.
10+
- Variable aperture.
11+
- Debug grid (shader-based).
12+
- Toggle rendering of cubemap sides.
13+
- 2D overlay image rendering in post. (has unfortunately a noticeable performance penalty).
14+
15+
**TODO:**
16+
- Improve cubemap resolution (or at least visual quality).
17+
- Implement rendering into background (2D) layer. (Possible implementation would be to send PGraphics as sampler into the shader, but it collides with the samplerCube, haven’t found a solution yet).
18+
- Custom sweet spot.
19+
- 4 sides should suffice for fulldome, need to rotate cubemap by 45° for that.
20+
- Implement picking?
21+
22+
**CHANGES:** (technical)
23+
- Switching to a raycasting approach in the cube map rendering stage. Uses quad with ray-casting instead of hemisphere.
24+
- Cubemap sampling set to linear.
25+
26+
### Overview (original)
27+
28+
A brief descrition of how it works: a 360° view of the scene is generated by rendering the scene 6 times from each direction: positive x, negative x, and so on. The output of each rendering is stored inside a cube map texture, which is then applied on a sphere representing the dome. Hence, the library calls the draw() method 6 times per frame in order to update the corresponding side of the cube map texture (in reality, only 5 times since the bottom side of the cube map is not invisible on the dome).
829

930
So, it is important to keep in mind that if you need to perform some calculation only one time per frame, then the code for that calculation should be put inside the pre() method. Similarly, calculations that should performed only once after the rendering is concluded should be put in the post() method.
1031

data/cubeMapQuadFrag.glsl

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//grid code originally appears: https://github.com/diroru/domemod
2+
#define PI 3.1415926535897932384626433832795
3+
#define AA 0.1
4+
5+
uniform samplerCube cubemap;
6+
uniform float aperture;
7+
uniform float renderGrid;
8+
9+
varying vec2 vertTexCoord;
10+
11+
vec2 domeXYToLatLon(vec2 xy, float aperture) {
12+
float x = xy.x - 0.5;
13+
float y = xy.y - 0.5;
14+
float lat = sqrt(x*x + y*y) * aperture;
15+
float lon = atan(y,x);
16+
return vec2(lat, lon);
17+
}
18+
19+
vec3 latLonToXYZ(vec2 latLon) {
20+
float lat = latLon.x;
21+
float lon = latLon.y;
22+
float x = cos(lon) * sin(lat);
23+
float y = sin(lon) * sin(lat);
24+
float z = cos(lat);
25+
return vec3(x,y,z);
26+
}
27+
28+
vec3 domeXYToXYZ(vec2 xy, float aperture) {
29+
return latLonToXYZ(domeXYToLatLon(xy, aperture));
30+
}
31+
32+
float rad2Deg(float r) {
33+
return r * 180.0 / PI;
34+
}
35+
36+
vec3 getLatitudeGrid(vec2 longLat, float gratOffset, float gratWidth, vec3 gratColour) {
37+
float gr = mod(rad2Deg(longLat.y) + gratWidth * 0.5, gratOffset) - gratWidth * 0.5;
38+
//return mix(gratColour, vec3(0.0), smoothstep(gratWidth*0.5 - AA, gratWidth*0.5 + AA, abs(gr)));
39+
return mix(gratColour, vec3(0.0), step(gratWidth, abs(gr)));
40+
}
41+
42+
vec3 getLongtitudeGrid(vec2 longLat, float gratOffset, float gratWidth, vec3 gratColour) {
43+
float longDeg = rad2Deg(longLat.x);
44+
float latDeg = rad2Deg(longLat.y);
45+
float go = gratWidth / sin(longLat.y);
46+
float gr = mod(longDeg + go , gratOffset) - go;
47+
//return mix(gratColour, vec3(0.0), smoothstep(go*0.5 - AA, go*0.5 + AA, abs(gr)));
48+
return mix(gratColour, vec3(0.0), step(go, abs(gr)));
49+
}
50+
51+
vec3 getGrid(vec2 longLat, vec3 colour, float gratOffset0, float gratWidth0, float gratOffset1, float gratWidth1) {
52+
vec3 longGrid_0 = getLongtitudeGrid(longLat, gratOffset0, gratWidth0, colour);
53+
vec3 longGrid_1 = getLongtitudeGrid(longLat, gratOffset1, gratWidth1, colour);
54+
vec3 latGrid_0 = getLatitudeGrid(longLat, gratOffset0, gratWidth0, colour);
55+
vec3 latGrid_1 = getLatitudeGrid(longLat, gratOffset1, gratWidth1, colour);
56+
vec3 grid_rgb = longGrid_0 + longGrid_1 + latGrid_0 + latGrid_1;
57+
//grid_rgb = longGrid_0;
58+
//TODO eg. vec3(0.0) as const
59+
return clamp(grid_rgb, vec3(0.0), vec3(1.0));
60+
//return grid_rgb;
61+
}
62+
63+
64+
65+
void main() {
66+
//vec3 color = vec3(textureCube(cubemap, vec3(vertTexCoord,1.0)));
67+
vec2 latLon = domeXYToLatLon(vertTexCoord, aperture*PI);
68+
vec3 ray = latLonToXYZ(latLon);
69+
//vec3 color = ray * 0.5 + vec3(0.5);
70+
vec3 color = vec3(textureCube(cubemap, ray));
71+
72+
vec3 gridColor = getGrid(latLon.yx, vec3(1.0, 1.0, 0.0), 45.0, 0.6, 15.0, 0.2);
73+
// float gridX = 1.0 - smoothstep(gridWeight*0.5-AA, gridWeight*0.5+AA, mod(latLon.x - gridWeight*0.5, gridSize.x));
74+
// float gridY = 1.0 - smoothstep(gridWeight*0.5-AA, gridWeight*0.5+AA, mod(latLon.y - gridWeight*0.5, gridSize.y));
75+
76+
gl_FragColor = vec4(mix(color, gridColor, min(length(gridColor)*0.5, renderGrid)), 1.0);
77+
//gl_FragColor = vec4(rgb + gridColor, 1.0);
78+
}

data/cubeMapQuadVert.glsl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
precision highp float;
2+
precision highp int;
3+
4+
uniform mat4 transform;
5+
uniform mat4 modelview;
6+
uniform mat3 normalMatrix;
7+
attribute vec4 vertex;
8+
attribute vec3 normal;
9+
attribute vec2 texCoord;
10+
11+
varying vec2 vertTexCoord;
12+
13+
void main() {
14+
gl_Position = transform * vertex;
15+
vertTexCoord = texCoord;
16+
}

examples/Basic/Basic.pde

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
// A brief descrition on how it works: a 360° view of the scene is generated
77
// by rendering the scene 6 times from each direction: positive x, negative x,
88
// positive y, and so on. The output of each rendering is stored inside a cube map
9-
// texture, which is then applied on a sphere representing the dome.
9+
// texture, which is then rendered on to a quad using a raytraced fisheye lens.
10+
//
1011
// Hence, the library calls the draw() method 6 times per frame in order to update
1112
// the corresponding side of the cube map texture (in reality, only 5 times since
1213
// the bottom side of the cube map is not invisible on the dome).
14+
// Now you can manually set which face should render using domeCamera's toggleFaceDraw() method.
15+
//
1316
// So, it is important to keep in mind that if you need to perform some calculation
1417
// only one time per frame, then the code for those calculations should be put inside
1518
// the pre() method.
@@ -18,28 +21,40 @@ import codeanticode.planetarium.*;
1821

1922
float cubeX, cubeY, cubeZ;
2023

24+
DomeCamera dc;
25+
int gridMode = Dome.NORMAL;
26+
2127
void setup() {
2228
// For the time being, only use square windows
23-
size(600, 600, Dome.RENDERER);
29+
size(1024, 1024, Dome.RENDERER);
30+
//initial default camera, i.e. interface to interact with the renderer.
31+
dc = new DomeCamera(this);
32+
//Set the aperture, or radial coverage of the dome.
33+
//1 is default, 2 would show the contents of an entire sphere.
34+
dc.setDomeAperture(2f);
35+
//we enable the sixth side, sothat we see what is happenning
36+
dc.setFaceDraw(DomeCamera.NEGATIVE_Z, true);
37+
//This method unfortunately doesn't work yet.
38+
//dc.setCubemapSize(2048);
2439
}
2540

2641
// Called one time per frame.
2742
void pre() {
2843
// The dome projection is centered at (0, 0), so the mouse coordinates
2944
// need to be offset by (width/2, height/2)
30-
cubeX += ((mouseX - width * 0.5) - cubeX) * 0.2;
31-
cubeY += ((mouseY - height * 0.5) - cubeY) * 0.2;
45+
cubeX += ((mouseX - width * 0.5)*2 - cubeX) * 0.2;
46+
cubeY += ((mouseY - height * 0.5)*2 - cubeY) * 0.2;
3247
}
3348

3449
// Called five times per frame.
3550
void draw() {
36-
background(0);
37-
38-
pushMatrix();
39-
translate(width/2, height/2, 300);
40-
51+
background(0, 0, 0, 0);
52+
53+
pushMatrix();
54+
55+
translate(width/2, height/2, -300);
4156
lights();
42-
57+
4358
stroke(0);
4459
fill(150);
4560
pushMatrix();
@@ -49,16 +64,60 @@ void draw() {
4964

5065
stroke(255);
5166
int linesAmount = 10;
52-
for (int i = 0; i < linesAmount;i++) {
67+
for (int i = 0; i < linesAmount; i++) {
5368
float ratio = (float)i/(linesAmount-1);
5469
line(0, 0, cos(ratio*TWO_PI) * 50, sin(ratio*TWO_PI) * 50);
5570
}
5671
popMatrix();
5772
}
5873

74+
void mouseDragged() {
75+
//exaggerating dome aperture. 1f <=> 180°
76+
dc.setDomeAperture(map(mouseY, 0, height, 0.1f, 2f));
77+
}
78+
5979
void keyPressed() {
6080
if (key == CODED) {
6181
if (keyCode == UP) cubeZ -= 5;
6282
else if (keyCode == DOWN) cubeZ += 5;
63-
}
83+
}
84+
switch(key) {
85+
case ' ':
86+
gridMode = gridMode == Dome.GRID ? Dome.NORMAL : Dome.GRID;
87+
//enables rendering of a reference grid (happens inside the shader)
88+
dc.setMode(gridMode);
89+
break;
90+
case 'e':
91+
//fulldome-conform rendering
92+
dc.enable();
93+
break;
94+
case 'd':
95+
//rendering only into a single, conventional camera
96+
dc.disable();
97+
break;
98+
case '0':
99+
//toggles rendering into the X+ side of the cubemap
100+
dc.toggleFaceDraw(0);
101+
break;
102+
case '1':
103+
//toggles rendering into the X- side of the cubemap
104+
dc.toggleFaceDraw(1);
105+
break;
106+
case '2':
107+
//toggles rendering into the Y+ side of the cubemap
108+
dc.toggleFaceDraw(2);
109+
break;
110+
case '3':
111+
//toggles rendering into the Y- side of the cubemap
112+
dc.toggleFaceDraw(3);
113+
break;
114+
case '4':
115+
//toggles rendering into the Z+ side of the cubemap
116+
dc.toggleFaceDraw(4);
117+
break;
118+
case '5':
119+
//toggles rendering into the Z- side of the cubemap
120+
dc.toggleFaceDraw(5);
121+
break;
122+
}
64123
}

examples/Overlay/Overlay.pde

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// The planetarium library is designed to create real-time projections on
2+
// spherical domes. It is based on the FullDome project by Christopher
3+
// Warnow (ch.warnow@gmx.de):
4+
// https://github.com/mphasize/FullDome
5+
//
6+
// A brief descrition on how it works: a 360° view of the scene is generated
7+
// by rendering the scene 6 times from each direction: positive x, negative x,
8+
// positive y, and so on. The output of each rendering is stored inside a cube map
9+
// texture, which is then rendered on to a quad using a raytraced fisheye lens.
10+
//
11+
// Hence, the library calls the draw() method 6 times per frame in order to update
12+
// the corresponding side of the cube map texture (in reality, only 5 times since
13+
// the bottom side of the cube map is not invisible on the dome).
14+
// Now you can manually set which face should render using domeCamera's toggleFaceDraw() method.
15+
//
16+
// So, it is important to keep in mind that if you need to perform some calculation
17+
// only one time per frame, then the code for those calculations should be put inside
18+
// the pre() method.
19+
20+
import codeanticode.planetarium.*;
21+
22+
float cubeX, cubeY, cubeZ;
23+
PImage grid;
24+
25+
DomeCamera dc;
26+
int gridMode = Dome.NORMAL;
27+
28+
void setup() {
29+
// For the time being, only use square windows
30+
size(1024, 1024, Dome.RENDERER);
31+
32+
dc = new DomeCamera(this);
33+
grid = loadImage("DomeGrid_2k.png");
34+
}
35+
36+
// Called one time per frame.
37+
void pre() {
38+
// The dome projection is centered at (0, 0), so the mouse coordinates
39+
// need to be offset by (width/2, height/2)
40+
cubeX += ((mouseX - width * 0.5) - cubeX) * 0.2;
41+
cubeY += ((mouseY - height * 0.5) - cubeY) * 0.2;
42+
dc.imageToForeground(grid,0,0,width,height);
43+
}
44+
45+
// Called five times per frame.
46+
void draw() {
47+
background(0, 0, 0, 0);
48+
49+
pushMatrix();
50+
51+
translate(width/2, height/2, -300);
52+
lights();
53+
54+
stroke(0);
55+
fill(150);
56+
pushMatrix();
57+
translate(cubeX, cubeY, cubeZ);
58+
box(50);
59+
popMatrix();
60+
61+
stroke(255);
62+
int linesAmount = 10;
63+
for (int i = 0; i < linesAmount; i++) {
64+
float ratio = (float)i/(linesAmount-1);
65+
line(0, 0, cos(ratio*TWO_PI) * 50, sin(ratio*TWO_PI) * 50);
66+
}
67+
popMatrix();
68+
}
69+
70+
void keyPressed() {
71+
if (key == CODED) {
72+
if (keyCode == UP) cubeZ -= 5;
73+
else if (keyCode == DOWN) cubeZ += 5;
74+
}
75+
}
1.04 MB
Loading

0 commit comments

Comments
 (0)