Create a texture with cylindrical mapping from script

Hi,

By advance, sorry if my question sounds silly, I’ve only started learning Unity recently.

I want to display 360° images.
Currently, I’ve done it in Unity editor with success, and my problem is now to load images at runtime (from a local or a remote image file).

To display them, I added a skybox to the main camera. It’s material use the “Skybox/Cubemap” shader, and the texture in this material use a "Latitude-Longitude layout (cylindrical).

I’ve found how to access in C# the material (Camera.main.GetComponent ().material), and I saw that the texture is referenced as “_Cube” (Camera.main.GetComponent ().material.GetTexture (“_Tex”)), and is apparently a Cubemap.

Now, I would like to change this texture, and so I want to create a new Cubemap, and load it with an image file, using the same cylindrical mapping.

On a Cubemap, I can only set pixels for 6 faces, so I think that the editor as an algorithm to convert cylindrical coordinates to cube coordinates.

Do you know if this algorithm is available somewhere in C# Unity libs ?

As anyone a more clever way to dynamically load images for skyboxes ? (maybe converting Texture2D to Cubemap, …)

Hi,

I solved this problem today if anyone is still interested.
It may surely not be the best solution but at least it works.

Here’s my script (It is attached to a button in order to change the skybox on click):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Crosstales.FB;
using UnityEditor;
using System.IO;

public class Import360 : MonoBehaviour {

    private Texture2D importedSkybox;
    public Material modulableSkyboxMat;
    private string directory;

	// Use this for initialization
	void Start () {
        directory = "";
        modulableSkyboxMat.shader = Shader.Find("SkyboxPlus/Cubemap");
    }
	
	// Update is called once per frame
	void Update () {
    }

    private IEnumerator LoadImages()
    {
        //Download Link
        directory = FileBrowser.OpenSingleFile("Select a 360 TEXTURE file", System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop), "jpg");
        Debug.Log(directory);
        if (directory != "")
        {
            WWW www = new WWW(directory);

            //Wait for the download to complete
            yield return www;
            importedSkybox = www.texture;

            //Create path in the asset folders:
            string path = "Assets/Resources/SVLevels/av26.jpg";

            //Load Image to modify in the ressource folder
            Texture2D tex2d = Resources.Load<Texture2D>("SVLevels/av26");

            //Uptake byte data from downloaded www image
            byte[] imData = importedSkybox.EncodeToJPG();
            File.WriteAllBytes(Application.dataPath + "/Resources/SVLevels/av26.jpg", imData);

            //Change the texture to cubemap:
            TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(path);
            if (tex2d != null && tex2d.dimension != UnityEngine.Rendering.TextureDimension.Cube)
            {
                importer.textureShape = TextureImporterShape.TextureCube;
                importer.SaveAndReimport();
            }

           // yield return new WaitForSecondsRealtime(1); //INCREASE OR DECREASE THIS TIMING; Depends on the ability of the computer to rapidly execute the previous tasks

            //Reference the Skybox material with the newly made cubemap texture ! IT WILL BE A CUBEMAP TO LOAD AGAIN!
            Cubemap finalSkybox = Resources.Load<Cubemap>("SVLevels/av26");
            
            modulableSkyboxMat.mainTexture = finalSkybox;
            RenderSettings.skybox = modulableSkyboxMat;
        }

    }


    public void OnClickChangeEnvironment()
    {
        Cubemap cube2d = Resources.Load<Cubemap>("SVLevels/av26");

        string path = "Assets/Resources/SVLevels/av26.jpg";
        TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(path);
        if (cube2d != null && cube2d.dimension == UnityEngine.Rendering.TextureDimension.Cube)
        {
            importer.textureShape = TextureImporterShape.Texture2D;
            importer.SaveAndReimport();
        }

        StartCoroutine("LoadImages");
    }

}

For this script to work you will need 2 things in your Asset Folder:

  • A Texture2D that will be updated when uploading a new www.texture (in my case it is av26.jpg)
  • A material that will be set to Skybox/Cubemap and will take the newly uploaded texture as input after the latter has been changed to cubemap (in my case: modulableSkyboxMat)

Both elements were placed in a folder in the Asset folder. (in my case: Assets/Resources/SVLevels)

Hope this helps others! :slight_smile:

Unfortunately, TextureImporter is a UnityEditor class and so isn’t a viable solution to do this at runtime in an actual build. Does anyone have a solution to the problem exactly as posed by the OP, but which doesn’t rely on the editor?

Unity came out with the “Skybox/Panoramic” shader