Metalで描画したものを後で動画として表示する
とりあえず衝突時の様子が表示できるようになった。次はスコアか。ええかげん影も修正しないとなあ。 #gamedev pic.twitter.com/WhIrIcDrq4
— Tatsuya (@yt) 2016年8月29日
↑衝突後に衝突の様子を動画として中央に表示させてるんだけど、ここではどうやってるかのお話。
こういうのをGIF動画にしてツイートってよくあるけど、ここではそういうのは無しでとりあえず動画を表示するってことで。
上の動画で言うと左目用、右目用とさらに別視点での録画用のrenderPassを用意してやって録画用はテクスチャに保存するように設定。
そのテクスチャを id<MTLTexture> *texture に対して
- (void)getBytes:(void *)pixelBytes bytesPerRow:(NSUInteger)bytesPerRow fromRegion:(MTLRegion)region mipmapLevel:(NSUInteger)mipmapLevel
ってメソッドでデータの保存ができる。
保存先はあらかじめ必要な枚数分メモリを確保しておく。
ちなみに上の動画はデータのサイズが横172x縦129、20FPSで表示してるんだけど、まあこれくらいならいいかなって感じ。
{ MTLRegion region = MTLRegionMake2D(0, 0, ImageWidth, ImageHeight);//172x129 int bytesPerPixel = 4; int bytesPerRow = bytesPerPixel * ImageWidth; UInt8 *recordingBuffer = (UInt8 *)&imageBuffer[unitSize * imageIndex]; [texture getBytes:recordingBuffer bytesPerRow:bytesPerRow fromRegion:region mipmapLevel:0]; }ここでunitSizeは画像1枚あたりのバイト数で、imageIndexにより保存先をどんどん変えていくようになってる。もちろん無限に保存するわけにもいかないのでimageIndexが決められた最大数を超えるとゼロになって最初に戻り、古いのに上書きしていく。
MTLTextureの内容を取得する型はUInt8でOK。
以上の処理が毎フレームで行われて、いざ表示となるとその時点で全ての保存してるデータを再度 id<MTLTexture> のテクスチャに戻してる。保存データをUIImageにするコードはこんな感じ。この後UIImageオブジェクトからMTLTextureにしてる。
+(UIImage *)makeImageFromUInt8Data:(UInt8 *)buffer size:(CGSize)size { size_t width = size.width; size_t height = size.height; size_t bitsPerComponent = 8; size_t bitsPerPixel = 32; size_t bytesPerRow = 4*width; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaFirst; bool shouldInterpolate = 1; CGColorRenderingIntent intent = 0; CFDataRef data = CFDataCreate(NULL, buffer, width*height*4); CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); CGImageRef cgimage = CGImageCreate( width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitmapInfo, dataProvider, NULL, shouldInterpolate, intent); UIImage *image = [UIImage imageWithCGImage:cgimage]; CGImageRelease(cgimage); CGDataProviderRelease(dataProvider); CGColorSpaceRelease(colorSpace); CFRelease(data); return image; }
スポンサーサイト