Sometimes the only way to pass precious data from CPU to GPU is by hiding it in textures.
I tried to trick SCNTechnique and simply pass [NSData dataWithBytes:length:]
or a CGDataProviderRef
containing my neatly prepared raw pixel data bytes, but SceneKit is smart enough to detect my sinister attempts.
But I did not give up, and found a loophole:
[_sceneView.technique setValue: UIImagePNGRepresentation(encodeInSinglePixelUIImage(pos.x, pos.y)) forKey:@"blob_pos_"];
Encoding and decoding single pixel PNGs at 60fps on a mobile device is something you can afford, on an iPhone X it just costs 2ms and keeps your palm a little bit warmer. However I do not need any heat-generating features till november, so I was wondering if there's a cool alternative to this method.
The most efficient way I found is constructing floating point RGB TIFFs. It's still not super fast, consuming 0.7ms on the iPhone X, but a lot faster than the PNG method.
Having a float texture also have the benefits of direct float transfer, that is, no encoding to multiple uint8 RGBA values on the CPU and reconstructing floats on the GPU.
Here's how:
Useful TIFF links I used:
http://www.fileformat.info/format/tiff/corion.htm
http://paulbourke.net/dataformats/tiff/
https://www.fileformat.info/format/tiff/egff.htm
https://www.awaresystems.be/imaging/tiff/tifftags/sampleformat.html