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$

1 Answer 1

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.

$\endgroup$

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .