Hi!
I am a bit of a newbie with shader, so excuse me if this is too basic.
I am trying to map a plannar FBO into a sphere of changing radius. I guess that this should be done in the vertex shader better than in the fragment shader., but I can’t find the way to do it.
Any suggestion? How to map the cartesian 2D into a sphere? I’ve found info about Mercator projection, -it should be the other way around, but that’s OK- but I can’t find the way to implement it in the vertex file.
Thanks a lot!
D!
Hi @dmelladom!
I have very little experience with shader programming, but mapping a plane to a sphere is not too difficult (depending on exactly what you want…)
A sphere has a circumference of 2pi (or 360 degrees if you want), so you need to map the x coordinates from 0 to 2pi and the y coordinates from 0 to pi. Then you can convert these coordinates (basically latitude and longitude) to spherical coordinates to plot them on a sphere. Think about a map of the earth you want to wrap around a sphere…
the code to map an image/fbo with a given width/height to a sphere would look something like this…
ofMesh mesh;
float width = 500;
float height = 250;
vector <float> longitude;
vector <float> latitude;
float SphereRadius = 250.0;
for (int x=0; x<width; x++) {
for (int y=0; y<height; y++) {
latitude.push_back( ofMap(x, 0, width, 0, (2*PI) ) );
longitude.push_back( ofMap(y, 0, height, 0, PI ) );
}
}
for (unsigned i = 0; i<longitude.size(); i++) {
float longTMP = longitude[i];
float latTMP = latitude[i];
float X = ( SphereRadius * cos(latTMP) * sin(longTMP) );
float Y = ( SphereRadius * sin(latTMP) * sin(longTMP) );
float Z = ( SphereRadius * cos(longTMP) );
ofVec3f temp = ofVec3f(X,Y,Z);
mesh.addVertex(temp);
mesh.addColor( ofFloatColor(1,1,1));
}
I used code similar to this to generate a globe that would not look out of place in the next tron movie 
Unfortunately, I don’t know how to apply this trick in a shader, maybe someone else can help out?
1 Like
Hi innodle!
You project looks really interesting! I hope this could help.
This code has been developed by Javier Villaroel as estated in the coments. I used it in a fragment shader with great results. Begin it before drawing the FBO, pass the paramenters, draw and finish it after all , just the regular way.
//////////////////////////////////////////////////////////////////////
// //
// //
// Code developed by Javier Villaroel, //
// Madrid, Spain, March 2015 //
// javier@ultra-lab.net //
// www.ultra-lab.net //
// //
//////////////////////////////////////////////////////////////////////
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2DRect texture0;
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
void main(void)
{
vec2 center = resolution/2.0;
vec2 pos = gl_TexCoord[0].xy;
float pi = 3.1415;
float R;
vec2 r = pos - center;
float mr = length(r);
vec2 posM;
float angT = 0.0;//10.0*time;
float expansionT = 5.0;
float giroT = 20.0;
float radioMax = 4000.0;
if (time < expansionT){
R = radioMax - time*(radioMax - 0.5*resolution.y)/expansionT;
} else {
if ( time < giroT + expansionT){
R = resolution.y * 0.5;
angT = 0.5 * resolution.y * sin(2.0*pi*(time - expansionT)/giroT);
} else {
R = -(radioMax - 0.5*resolution.y)*(giroT+expansionT)/expansionT
+ time*(radioMax - 0.5*resolution.y)/expansionT
+ resolution.y*0.5;
}
}
if(length(r) < R)
{
float theta = acos(-r.y/R)/pi; //angulo con respecto a los polos
float phi = abs(atan(sqrt(abs(R*R - r.x*r.x - r.y*r.y))/r.x))/pi; //angulo en el plano XY de la esfera
float ajusteP = resolution.y / 2.0 + resolution.x / 2.0 - angT;
float ajusteN = resolution.x / 2.0 - resolution.y / 2.0 - angT;
if(R <= resolution.y / 2.0)
{
posM.y = resolution.y * theta;
posM.x = resolution.y * phi;
}
if(R > resolution.y / 2.0 )
{
float alpha = acos(resolution.y/(2.0*R))/pi;
float A = resolution.y /(1.0-(2.0*alpha));
float beta = acos(resolution.y/(2.0*R))/pi;
float B = resolution.y /(1.0-(2.0*beta));
posM.y = A * (theta - alpha);
posM.x = B * (phi - beta);
}
if(r.x > 0.0){
posM.x = ajusteP - posM.x;
} else {
posM.x += ajusteN;
}
if (posM.x <= 0.0 || posM.y <= 0.0 || posM.y > resolution.y || posM.x > resolution.x){
discard;
} else {
vec4 color = texture2DRect(texture0, posM);
gl_FragColor = color;
}
} else {
discard;
}
}