<p><a href="https://stackoverflow.com/questions/59907996/shader-that-transforms-a-mercator-projection-to-equirectangular">This question</a> and its answer, actually answer my question. I had to read its answer carefully and find my mistake.</p>

<p>Now my fragment shader look like this:</p>

<pre><code>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 &gt;= -1.48442222974871 &amp;&amp; lat &lt;= 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";
</code></pre>

<p>And it's works perfectly.</p>

CC BY-SA 4.0
2020-05-19T09:30:03.427Z
2020-05-19T09:40:15.693Z
2020-05-19T09:40:15.693Z
Hamid Reza Mohammadi
<p>I am new in the OpenGL - GLSL and trying to make a shader that taking a <a href="https://en.wikipedia.org/wiki/Mercator_projection" rel="nofollow noreferrer">mercator projection</a> texture as a source and converting it to an <a href="https://en.wikipedia.org/wiki/Equirectangular_projection" rel="nofollow noreferrer">equirectangular projection</a> texture.</p>

<p><strong>Sample input: (1024x1024)</strong></p>

<p><a href="https://i.sstatic.net/1h4vk.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/1h4vk.jpg" alt="enter image description here"></a></p>

<p><strong>Desired output (1024x512)</strong></p>

<p><a href="https://i.sstatic.net/qLQlo.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/qLQlo.jpg" alt="enter image description here"></a></p>

<p>I found <a href="https://stackoverflow.com/questions/59907996/shader-that-transforms-a-mercator-projection-to-equirectangular">this question</a>, that have a similar problem in unity3d. But i stuck to understand it.</p>

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

<pre><code>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 &gt;&gt; 1;
        Bitmap des = new Bitmap(w, dh);
        dh = dh &gt;&gt; 1;
        int dw = w &gt;&gt; 1;
        double r = w / TWO_PI;
        for (int i = 0; i &lt; w; i++)
        {
            for (int j = 0; j &lt; 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();
    }
}
</code></pre>

<p>So i try to implement it in c++ and OpenGL. </p>

<p><strong>My vertex and fragment shaders</strong></p>

<pre><code>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";
</code></pre>

<p>And my vertex buffer:</p>

<pre><code>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
}
</code></pre>

<p><strong>Output:</strong></p>

<p><a href="https://i.sstatic.net/JjzrH.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/JjzrH.png" alt="enter image description here"></a></p>

<p>As you can see there are a lot of problems.</p>

<p>Also i try to change texture wrapping to <code>GL_REPEAT</code>, <code>GL_MIRRORED_REPEAT</code>, <code>GL_CLAMP_TO_EDGE</code> and <code>GL_CLAMP_TO_BORDER</code>, as below:</p>

<pre><code>glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
</code></pre>

<p>And <code>glViewport(0, 0, 512, 256)</code> but without any success.</p>

<p>So where I'm wrong?</p>

<p>Sorry for the long question, Thanks in advance.</p>

<opengl><glsl><c++>
Shader that transforms a mercator projection to equirectangular?
Hamid Reza Mohammadi
# Shader that transforms a mercator projection to equirectangular?

(Asked by: username_0 on 2020-05-18)

I am new in the OpenGL - GLSL and trying to make a shader that taking a [mercator projection](https://en.wikipedia.org/wiki/Mercator_projection) texture as a source and converting it to an [equirectangular projection](https://en.wikipedia.org/wiki/Equirectangular_projection) texture.

**Sample input: (1024x1024)**

[![enter image description here](https://i.sstatic.net/1h4vk.jpg)](https://i.sstatic.net/1h4vk.jpg)

**Desired output (1024x512)**

[![enter image description here](https://i.sstatic.net/qLQlo.jpg)](https://i.sstatic.net/qLQlo.jpg)

I found [this question](https://stackoverflow.com/questions/59907996/shader-that-transforms-a-mercator-projection-to-equirectangular), 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.

**My vertex and fragment shaders**

```
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:**

[![enter image description here](https://i.sstatic.net/JjzrH.png)](https://i.sstatic.net/JjzrH.png)

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.

**Tags:** opengl, glsl, c++


---

## 1 answers

### Answer by username_0 on 2020-05-19. Score: 3 | Accepted answer

[This question](https://stackoverflow.com/questions/59907996/shader-that-transforms-a-mercator-projection-to-equirectangular) and its answer, actually answer my question. I had to read its answer carefully and find my mistake.

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.


---

