2

I'm working on transmitting point cloud data over the network using Flatbuffers to an application built in Unity.

Say I have the following schema file:

namespace PCFrame;

struct Vec3 {
    x: float;
    y: float;
    z: float;
}

struct RGB {
    R: ubyte;
    G: ubyte;
    B: ubyte;
}

struct PCPoint {
    Position: Vec3;
    Color: RGB;
}

table PCFrame {
    FrameNo: uint;
    Points: [PCPoint];
}

file_identifier "FBPC";

root_type PCFrame;

I've successfully serialized and transmitted the buffer. But after receiving the ByteBuffer in C# and deserializing it as a PCFrame object, the only way for me to access a point in the Points array is to call the method Points(n). This is extremely inefficient, especially when the array can include hundreds of thousands of points and I need to iterate over all of them.

Is there any way to access the array more efficiently?

Edit: I ended up giving up on the more legible PCPoint struct and instead created the Points data as a float array (arranged as x1, y1, z1, r1, g1, b1, x2, y2...). So the much simpler schema now looks like this:

namespace PCFrame;

table PCFrame 
{
    FrameNo: uint;
    Points: [float];  // x1, y1, z1, r1, g1, b1, x2, y2, z2, r2, g2, b2, x3, ...
}

file_identifier "FBPC";

root_type PCFrame;

Using an array of a primitive type allows me to extract the byte array directly using:

ArraySegment<byte> pointsArraySegment = fb_frame.GetPointsBytes();
byte[] pointsByteArray = pointsArraySegment.Value.Array;

Which in turn allows me to Buffer.BlockCopy the entire array back into a float array at once:

int offset = pointsArraySegment.Value.Offset;
float[] pointsArray = new float[(pointsByteArray.Length - offset) / sizeof(double)];
Buffer.BlockCopy(pointsByteArray, offset, pointsArray, 0, pointsByteArray.Length - offset);

Accessing the point data from the float array in this manner is much more efficient. I'm still not sure why FlatBuffers doesn't allow you to do this on non-primitive arrays, though.

Handelo
  • 39
  • 4
  • The problem is that C# has no way to cast this existing byte memory as a struct with exactly the same layout as serialized. If you need this kind of performance you need to be using C++ or Rust. – Aardappel May 27 '20 at 15:14
  • @Aardappel Well, you can deserialise a json object to a C# object. Not sure about a struct though. You could create a class for each one to deserialise to that's just 3 public floats. It's a bit worse for garbage collector allocations though.? – Rocketman Dan May 27 '20 at 22:19
  • Apparently this can be accomplished with a primitive type array, but not a complex type one. Not exactly sure why. I've edited my question to show how I worked around it using a float array rather than an array of structs. – Handelo Jun 02 '20 at 09:09

0 Answers0