Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Resolved Async version of Texture2D.GetPixel()

Discussion in 'World Building' started by Heptagram064, Nov 2, 2022.

  1. Heptagram064

    Heptagram064

    Joined:
    Feb 22, 2022
    Posts:
    94
    So, in my project i use textures for my terrain generator, e.g. to determine how much a procedural generation algorithm should blend with others, to create smooth terrain transitions (e.g. 2 different types of Perlin noise algorithms, one for hills and one for mountains).

    The only problem is that i like my terrain generator to compute asynchronously to the main thread. Unfortunately the Texture2D.GetPixel() function can only be used on the main thread;
    complaint.png
    In the current workaround creating a frame drop each time a set of textures is loaded and converted to a Color[ , ] array for the async mesh builder to use.

    I was wondering if there would be a alternate method to Texture2D.GetPixel() that could retrieve pixel information from a texture asynchronously.
     
  2. JasonBooth

    JasonBooth

    Joined:
    Jan 27, 2014
    Posts:
    621
    use GPUAsyncReadbacks instead..
     
  3. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,450
    Oh, I see, you're already in CPU land. You can use Native Arrays/GetRawTextureData a to copy the data into a native array and back into textures bypassing the slow Get/SetPixels APIs.
     
  4. Heptagram064

    Heptagram064

    Joined:
    Feb 22, 2022
    Posts:
    94
    So i tried this function;
    Code (CSharp):
    1. private Color32[,] textureData;
    2. private async void ConvertTexture(Texture2D texture2D, Vector2Int textureSize) {
    3.         await Task.Run(() => {
    4.             var data = texture2D.GetRawTextureData<Color32>();
    5.             var output = new Color32[textureSize.x, textureSize.y];
    6.             for (int i = 0, x = 0; x < textureSize.x; i++, x++)
    7.             {
    8.                 for (int y = 0; y < textureSize.y; y++)
    9.                 {
    10.                     if (y != 0) i++;
    11.                     output[x, y] = data[i];
    12.                 }
    13.             }
    14.             textureData = output;
    15.         });
    16.     }
    And i yet, this function is also, only able to be called from the main thread, getting the exact same error as with GetPixel();

    UnityException: get_isReadable can only be called from the main thread.
     
    Last edited: Nov 21, 2022
  5. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,450
    No, you need to use jobs (with burst) and native arrays here, not this. IJobParellelFor is likely what you want..
     
    Heptagram064 likes this.
  6. Heptagram064

    Heptagram064

    Joined:
    Feb 22, 2022
    Posts:
    94
    The jobs and burst systems are both very new to unity (Jobs having been marked 'stable' since only a couple months). For this reason i avoided learning and working with any of the systems rumored to become part of the future unity DOTS, until DOTS gets a stable release out there. (cause why not start learning DOTS when DOTS is actually released). However if using unity jobs is the appropriate way of achieving this, i will read into using it when i get back to my terrain generator.

    In any case, thanks for the help ^.^