全景视频

学习opengl的时候,看别人做了一个全景视频。因此感兴趣,所以学习下。

原理

视频播放

在播放全景视频时,和普通视频一样,也是播放器从视频源中一帧一帧地取画面,但全景视频播放器会将取出来的画面帖在一个球体的表面:

比如视频中的一帧画面如下: 

将其帖到一个球体表面后如下:


将画面帖到球体表面后,为什么人能够看到整个画面的各个方面呢?是因为观影点刚好在这个球体的中心,观众可以通过转动头部来控制观察的视线方向:


用opengl 绘制怎么展示这个效果呢?

1。我们知道,图像需要绘制在一个球的上面。所以,我们需要用opengl 绘制一个球体

2. 图像附着在球体上面,因此,我们需要将球体的表面纹理绘制成这张照片

3. 而我们应该在球体的中心观察。摄像机的位置位于球体的中心。

这里我们只是单纯的对一张图片做下全景解析。会解析一张图。那么也会解析视频了,因为视频也是有一张张图来的。

代码如下

#import "GLTestView.h"#import "OPenGLManger.h"#import "sphere.h"

enum{ ATTRIB_VERTEX,

ATTRIB_TEXCOORD,

NUM_ATTRIBUTES};

enum{ UNIFORM_TEXTURE,

UNIFORM_PROJECTION_MARTRIX,

UNIFORM_MODELVIEW_MARTRIX,

UNIFORM_ROTATE, NUM_UNIFORMS};

GLint uniforms[NUM_UNIFORMS];

@interface GLTestView(){

EAGLContext *_context;

UILabel* horizontalLabel;

float horizontalDegree;

UILabel* verticalLabel;

float verticalDegree;

}

@property (nonatomic ,strong) ShaderManager * shadermanager;

@property (nonatomic, strong) AGLKVertexAttribArrayBuffer * vertexBuffer;

@property (nonatomic ,strong) AGLKVertexAttribArrayBuffer * vertexTextureBuffer;

@property (nonatomic ,strong) FrameBufferManger * frameManager;

@property (nonatomic , strong) CADisplayLink *mDisplayLink;

@end

@implementation GLTestView

+ (Class)layerClass{ return [CAEAGLLayer class];}

- (instancetype)initWithFrame:(CGRect)frame

{

self = [super initWithFrame:frame];

if (self)

{

self.mDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];

self.mDisplayLink.frameInterval = 2;//FPS=30

[[self mDisplayLink] addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[[self mDisplayLink] setPaused:NO];

[self setupView];

self.contentScaleFactor = [[UIScreen mainScreen] scale];

CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;

eaglLayer.opaque = TRUE;

eaglLayer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBacking :[NSNumber numberWithBool:NO], kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8};

_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

if (!_context || ![EAGLContext setCurrentContext:_context] || ![self loadShaders]) { return nil; }

[EAGLContext setCurrentContext:_context];

[self initVertex];

[self frameBuffer];

[self setShader];

[self initImage];

[self render];

}

return self;}

///初始化顶点-(void)initVertex{

glDisable(GL_DEPTH_TEST);

self.vertexBuffer = [[AGLKVertexAttribArrayBuffer alloc]initWithAttribStride:sizeof(GLfloat)*3 numberOfVertices:sphereNumVerts bytes:sphereVerts usage:GL_STATIC_DRAW];

self.vertexTextureBuffer=[[AGLKVertexAttribArrayBuffer alloc]initWithAttribStride:sizeof(GLfloat)*2 numberOfVertices:sphereNumVerts bytes:sphereTexCoords usage:GL_STATIC_DRAW];}

-(void)initImage{ //地球纹理 [self setupTexture:@"Earth512x256.jpg"];}

- (GLuint)setupTexture:(NSString *)fileName { // 1获取图片的CGImageRef CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage; if (!spriteImage) { NSLog(@"Failed to load image %@", fileName); exit(1); } // 2 读取图片的大小 size_t width = CGImageGetWidth(spriteImage); size_t height = CGImageGetHeight(spriteImage); GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte)); //rgba共4个byte CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast); // 3在CGContextRef上绘图 CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage); CGContextRelease(spriteContext); // 4绑定纹理到默认的纹理ID(这里只有一张图片,故而相当于默认于片元着色器里面的colorMap,如果有多张图不可以这么做) glBindTexture(GL_TEXTURE_2D, 0); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); float fw = width, fh = height; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData); glBindTexture(GL_TEXTURE_2D, 0); free(spriteData); return 0;}

-(void)frameBuffer{

self.frameManager = [[FrameBufferManger alloc]init]; self.frameManager.renderBufferStore = ^{ [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer]; };

[self.frameManager buildLayer];

}

- (BOOL)loadShaders{

self.shadermanager =[[ShaderManager alloc]init]; return [self.shadermanager CompileLinkSuccessShaderName:@"Shader" glBindAttribLocationBlock:^(GLuint program) { glBindAttribLocation(program, ATTRIB_VERTEX, "position"); } GetUniformLocationBlock:^(GLuint program) { uniforms[UNIFORM_TEXTURE] =glGetUniformLocation(program, "Sampler"); uniforms[UNIFORM_ROTATE] = glGetUniformLocation(program, "preferredRotation"); uniforms[UNIFORM_PROJECTION_MARTRIX] = glGetUniformLocation(program, "projectionMatrix"); uniforms[UNIFORM_MODELVIEW_MARTRIX] = glGetUniformLocation(program, "modelViewMatrix"); }];

}

-(void)setShader{ glUseProgram(self.shadermanager.program); glUniform1f(uniforms[UNIFORM_ROTATE], GLKMathDegreesToRadians(180)); GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(90, CGRectGetWidth(self.bounds) * 1.0 / CGRectGetHeight(self.bounds), 0.01, 10); GLKMatrix4 modelViewMatrix = GLKMatrix4MakeLookAt(0, 0, 0, 1, 0, 0, 0, 1, 0); glUniform1i(uniforms[UNIFORM_TEXTURE], 0); glUniformMatrix4fv(uniforms[UNIFORM_PROJECTION_MARTRIX], 1, GL_FALSE, projectionMatrix.m); glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_MARTRIX], 1, GL_FALSE, modelViewMatrix.m);}-(void)render{ glClearColor(0.1f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(self.shadermanager.program); // 更新顶点数据 [self.vertexBuffer prepareToDrawWithAttrib:ATTRIB_VERTEX numberOfCoordinates:3 attribOffset:0 shouldEnable:YES]; [self.vertexTextureBuffer prepareToDrawWithAttrib:ATTRIB_TEXCOORD numberOfCoordinates:2 attribOffset:0 shouldEnable:YES]; [AGLKVertexAttribArrayBuffer drawPreparedArraysWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:sphereNumVerts]; [self.frameManager layerRender:^{ if ([EAGLContext currentContext] == _context) { [_context presentRenderbuffer:GL_RENDERBUFFER]; } }];}#define LY_ROTATE YES- (void)setupView{ horizontalLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 0, 200, 50)]; [self addSubview:horizontalLabel]; horizontalLabel.textColor = [UIColor redColor]; verticalLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 50, 200, 50)]; [self addSubview:verticalLabel]; verticalLabel.textColor = [UIColor redColor]; if (LY_ROTATE) { horizontalDegree = 0.0; verticalDegree = M_PI_2; horizontalLabel.text = [NSString stringWithFormat:@"绕X轴旋转角度为%.2f", GLKMathRadiansToDegrees(horizontalDegree)]; verticalLabel.text = [NSString stringWithFormat:@"绕Y轴旋转角度为%.2f", GLKMathRadiansToDegrees(verticalDegree)]; } else { horizontalDegree = M_PI_2; verticalDegree = 0.0; horizontalLabel.text = [NSString stringWithFormat:@"偏航角为%.2f", GLKMathRadiansToDegrees(horizontalDegree)]; verticalLabel.text = [NSString stringWithFormat:@"高度角为%.2f", GLKMathRadiansToDegrees(verticalDegree)]; }}- (void)roatateWithX:(float)x Y:(float)y { horizontalDegree -= x / 100; verticalDegree += y / 100; horizontalLabel.text = [NSString stringWithFormat:@"绕X轴旋转角度为%.2f", GLKMathRadiansToDegrees(horizontalDegree)]; verticalLabel.text = [NSString stringWithFormat:@"绕Y轴旋转角度为%.2f", GLKMathRadiansToDegrees(verticalDegree)]; GLKMatrix4 modelViewMatrix = GLKMatrix4Identity; modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, horizontalDegree); modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, verticalDegree); glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_MARTRIX], 1, GL_FALSE, modelViewMatrix.m);}- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch* touch = [touches anyObject];

    CGPoint point = [touch locationInView:self];

    CGPoint prePoint = [touch previousLocationInView:self];

    if (LY_ROTATE) {

        [self roatateWithX:point.y - prePoint.y Y:point.x - prePoint.x];

    }

    else {

        [self changeModelViewWithHorizontal:point.x - prePoint.x Vertical:point.y - prePoint.y];

    }

}

- (void)changeModelViewWithHorizontal:(float)h Vertical:(float)v {

    horizontalDegree -= h / 100;

    verticalDegree -= v / 100;


    horizontalLabel.text = [NSString stringWithFormat:@"偏航角为%.2f", GLKMathRadiansToDegrees(horizontalDegree)];

    verticalLabel.text = [NSString stringWithFormat:@"高度角为%.2f", GLKMathRadiansToDegrees(verticalDegree)];



    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeLookAt(0, 0, 0,

                                                      sin(horizontalDegree) * cos(verticalDegree),

                                                      sin(horizontalDegree) * sin(verticalDegree),

                                                      cos(horizontalDegree),

                                                      0, 1, 0);


    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_MARTRIX], 1, GL_FALSE, modelViewMatrix.m);

}

- (void)displayLinkCallback:(CADisplayLink *)sender

{

    [self render];

}

@end


借鉴文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容