# Shader that transforms a mercator projection to equirectangular?

I am new in the OpenGL - GLSL and trying to make a shader that taking a mercator projection texture as a source and converting it to an equirectangular projection texture.

Sample input: (1024x1024)

Desired output (1024x512)

I found this question, that have a similar problem in unity3d. But i stuck to understand it.

I have a C# code that do this task, using WindowsForms, but it's not efficient.

static class Program
{
const double TWO_PI = Math.PI * 2;
const double PI180 = Math.PI / 180;

private static double Clip(double value, double min, double max)
{
return Math.Min(Math.Max(value, min), max);
}

public static PointF PixelXYToLatLong(int X, int Y, int mapSize)
{
PointF coordinate = new PointF();
double x = (Clip(X, 0, mapSize - 1) / mapSize) - 0.5;
double y = 0.5 - (Clip(Y, 0, mapSize - 1) / mapSize);
coordinate.X = (float)(360 * x);
coordinate.Y = (float)(90 - 360 * Math.Atan(Math.Exp(0 - y * 2 * Math.PI)) / Math.PI);
return coordinate;
}

static void Main()
{
Bitmap source = new Bitmap("INPUT_PATH");
int w = source.Width;
int h = source.Height;
int dh = h >> 1;
Bitmap des = new Bitmap(w, dh);
dh = dh >> 1;
int dw = w >> 1;
double r = w / TWO_PI;
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
Color color = source.GetPixel(i, j);
PointF point = PixelXYToLatLong(i, j, w);
double x = point.X * PI180;
double y = point.Y * PI180;
x = r * x;
y = r * y;
x = Math.Round(dw + x);
y = Math.Round(dh - y);
des.SetPixel((int)x, (int)y, color);
}
}
des.Save("OUTPUT_PATH");
source.Dispose();
des.Dispose();
}
}


So i try to implement it in c++ and OpenGL.

const GLchar* vertexSource = R"glsl(
#version 330 core

layout (location = 0) in vec3 texPos;
layout (location = 1) in vec2 texCoord;

out vec2 TexCoord;

void main()
{
gl_Position.xyz = texPos.xyz;
gl_Position.w = 1.0;

TexCoord = texCoord;
}
)glsl";

const GLchar* fragmentSource = R"glsl(
#version 330 core

in vec2 TexCoord;

uniform sampler2D ourTexture;

void main(){
float pi180 = 3.14159265 / 180;
float r = 1 / (2 * 3.14159265);
float x = min(max(TexCoord.x, 0), 1) - 0.5;
float y = 0.5 - min(max(TexCoord.y, 0), 1);
x = 360 * x;
y = 90 - (360 * atan(exp(0 - y * 2 * 3.14159265)) / 3.14159265);
x = x * pi180;
y = y * pi180;
x = 0.5 + (r * x);
y = 0.5 - (r * y);

gl_FragColor = texture(ourTexture, vec2(x,y));
}
)glsl";


And my vertex buffer:

static const GLfloat g_vertex_buffer_data[] = {
1.0f,  1.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f,  1.0f, 0.0f, 1.0f, 0.0f,
-1.0f,  1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f
}


Output:

As you can see there are a lot of problems.

Also i try to change texture wrapping to GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_EDGE and GL_CLAMP_TO_BORDER, as below:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


And glViewport(0, 0, 512, 256) but without any success.

So where I'm wrong?

Sorry for the long question, Thanks in advance.

Now my fragment shader look like this:

const GLchar* fragmentSource = R"glsl(
#version 330 core

in vec2 TexCoord;

uniform sampler2D ourTexture;

#define PI       3.141592653589793238462f
#define TWO_PI   6.283185307179586476924f
#define PI4      0.7853981633974483096155f

void main(){
float lat = (TexCoord.y - 0.5f) * PI;
if(lat >= -1.48442222974871 && lat <= 1.48442222974871){
float y = log(tan(PI4 + (lat / 2.0)));
y = (y + PI) / TWO_PI;
gl_FragColor = texture(ourTexture, vec2(TexCoord.x, y));
return;
}
gl_FragColor = vec4(1, 1, 1, 0);
}
)glsl";


And it's works perfectly.