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. Dismiss Notice

Question How to get specific portion of array data?

Discussion in 'Scripting' started by UserNobody, Aug 28, 2021.

  1. UserNobody

    UserNobody

    Joined:
    Oct 3, 2019
    Posts:
    144
    Hello there.
    I have a regular NativeArray of colors. I want to efficiently sample and get a specific portion of data from that array depending on the given rect.

    Let's say I have this 5x5 (25 in length) size color array and I need to get data from this rect (x:7, y:1, w:3, h:3) as shown in the picture
    array sample.png

    How can I do that?
    If I try to use the function NativeArray<>.Copy it copies from index to length. So if I specify index 7 and 6 length it would copy from 7 to 12, which wouldn't work for me.
     
  2. HellGate94

    HellGate94

    Joined:
    Sep 21, 2017
    Posts:
    132
    you cant escape multiple copies ([7..9], [12..14]) unless you find a way to make your data align with the query.
     
  3. UserNobody

    UserNobody

    Joined:
    Oct 3, 2019
    Posts:
    144
    What could be the most efficient way in doing that? I am dealing with much larger images and I need to access specific data quite often (sometimes even every frame).
     
  4. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    Or you just do multiple queries (each "line") separately. But I don't know if there is a method to aggregate them back in a single target array. In worst case you would have to do that manually. But I would assume there is an API for putting data in a certain part of NativeArray (I have not worked with them). So in your example you get 7,8,9 in one and 12, 13, 14 in the second query.
     
  5. HellGate94

    HellGate94

    Joined:
    Sep 21, 2017
    Posts:
    132
    instead of copying you could also store an array of pointers for each row to the original data
     
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,525
    Well, an array of pointers is not necessary because this is exactly what is called the row "stride". The original array has a stride of 5. So every 5 elements you get to the same element, just one row further down. It still works the same, you just have to use the proper stride when you go through the elements. So when you iterate through a 3x3 sub area, all you have to do is having two nested for loops as usual that go from 0 to 2 (go through the width and height of your sub area) and just increase index / offset into your source array alongside. Something like this:

    Code (CSharp):
    1.  
    2.         int width = 3;
    3.         int height = 2;
    4.         int stride = 5; // assuming 5 is the width of the original image / data
    5.         for(int y = 0, offset = startIndex; y < height; y++, offset += stride)
    6.         {
    7.             for(int x = 0; x < width; x++)
    8.             {
    9.                 var c = yourArray[offset + x];
    10.             }
    11.         }
    12.  
    Of course "startIndex" would be the source index where your sub area should start. The area you specified doesn't make much sense since you don't have an x index of 7 in a 5x5 image ^^. The area you marked should be
    (x:2, y:1, w:3, h:2)


    With that information the startIndex is

    Code (CSharp):
    1. startIndex = x + y*stride;
    As just mentioned, x would be 2 and y would be 1 giving you the index of the first tile which is 2 + 1*5 == 7

    The index in the inner most array is just offset by our innermost loop variable. So we iterate through the elements 7,8,9 After that the next outerloop. Here we will increase the offset by stride which brings us from 7 to 12. So the second inner most loop run-through would be 12,13,14

    Of course there's the NativeSlice struct which can map out a sub section of a NativeArray and it has a stride value internally. However that's just the "element stride" in bytes. So if you have a Color32 array it means the element stride is 4. So the native array has to advance 4 bytes to get to the next element. You can not really close a physical gap in memory. So if you would use a NativeSlice, you would need to create one for each row and also process one row after another.