3
$\begingroup$

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)

enter image description here

Desired output (1024x512)

enter image description here

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.

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

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.

$\endgroup$
3
$\begingroup$

This question 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.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.