I have recently been spending a lot of time with procedural texture generation. However that quickly came to a halt when I was trying to get the textures to map to a sphere. I am required to use an image projected into something called equirectangular cylindrical projection. Here I have an image of random noise that I want mapped to the projection:
enter image description here
Here is an image using the Projection code I found below, however this code does not reproject an image, but rather picks points in 3D noise and then maps those points to a texture:
enter image description here
The code used to get this image can be found here credit to the original author
This is the code that I have currently to reproject the texture, although it does not work how I would like:

public static class EquirectangularReProjection
    public static Texture2D ConvertToEquirectangular(Texture2D tex, TextureData data)
        if (!data._ReprojectToEquirectangular)
            return tex;

        int xSize = tex.width;
        int ySize = tex.height;

        Texture2D output = InitializeTextureSettings(xSize, ySize, tex.name);
        Color[] colors = new Color[xSize * ySize];
        Stopwatch watch = new Stopwatch();

        for (int x = 0; x < xSize; x++)
            for (int y = 0; y < ySize; y++)
                int i = (y * xSize) + x;

                float longitude = (-180 + x * 360f / xSize) * Mathf.Deg2Rad;
                float latitude = (-90 + y * 180f / ySize) * Mathf.Deg2Rad;

                Vector3 point = data._Radius * new Vector3(Mathf.Cos(longitude) * Mathf.Cos(latitude), Mathf.Sin(latitude), Mathf.Sin(longitude) * Mathf.Cos(latitude));

                colors[i] = SampleTexture(point, data);

        if (data._DebugTimes)
            UnityEngine.Debug.Log($"Time to Reproject {output.name}: {watch.ElapsedMilliseconds}ms | {watch.ElapsedTicks}-ticks");

        return output;

    private static float MinLWH = float.MaxValue;
    private static float MaxLWH = float.MinValue;

    private static Color SampleTexture(Vector3 point3d, TextureData data)
        float heightFrac = Map(LayerWorldHeight(point3d, data), MinLWH, MaxLWH, 0f, 1f);

        Color heightColour = Color.Lerp(Color.black, Color.white, heightFrac);

        return heightColour;//Color.Lerp (randomColour, heightColour, p.gradientBlending);
    private static float LayerWorldHeight(Vector3 x, TextureData p) => LayerWorldHeight(x.x, x.y, x.z, p);
    private static float LayerWorldHeight(float x, float y, float z, TextureData p)
        float layerTotal = p._Noise.fastNoise.GetNoise(x, y, z);

        if (layerTotal < MinLWH) MinLWH = layerTotal;
        if (layerTotal > MaxLWH) MaxLWH = layerTotal;

        return layerTotal;
    private static float Map(float x, float in_min, float in_max, float out_min, float out_max) => (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;

I would like to reproject as my last step in the texture creation process so that it is a lot easier to manipulate.

  • 1
    \$\begingroup\$ "Reprojection to equirectangular" makes sense if your source is in the spherical domain, and you want to project it to a rectangular domain instead. If your source is already in a rectangular domain, then first you'd have to project it to a sphere, then reproject that sphere to equirectangular coordinates. If you use an equirectangular projection for both steps, going onto the sphere and back to the rectangle, then the net result is a no-op: you'll get your input back as your output (though possibly with added artifacts). Usually when generating noise for a sphere, we use a 3D noise function \$\endgroup\$
    – DMGregory
    May 1 at 16:22


You must log in to answer this question.

Browse other questions tagged .