Search Unity

Resolved Async version of Texture2D.GetPixel()

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

  1. Heptagram064

    Heptagram064

    Joined:
    Feb 22, 2022
    Posts:
    99
    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:
    649
    use GPUAsyncReadbacks instead..
     
  3. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    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:
    99
    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,461
    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:
    99
    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 ^.^