全景視圖iOS

//  PanoramaUtil.c
//  VRPanoramaKit
//
//  Created by 小發(fā)工作室 on 2017/9/22.
//  Copyright ? 2017年 小發(fā)工作室. All rights reserved.
//

#include "PanoramaUtil.h"
#include <stdlib.h>
#include <math.h>

#define ES_PI  (3.14159265f)


/**
 根據(jù)numSlices和radius的大小取索引,頂點(diǎn),紋理的值
 
 @param numSlices 球面切面數(shù)量
 @param radius 半徑
 @param vertices 3維頂點(diǎn)坐標(biāo)
 @param texCoords 紋理
 @param indices 索引
 @param vertices_count 3維頂點(diǎn)坐標(biāo)數(shù)量
 @return 索引數(shù)量
 */
int esGenSphere(int numSlices,
                float radius,
                float **vertices,
                float **texCoords,
                uint32_t **indices,
                int *vertices_count) {
    
    
    int numParallels = numSlices / 2;
    int numVertices  = (numParallels + 1) * (numSlices + 1);
    int numIndices   = numParallels * numSlices * 6;
    
    float angleStep  = (2.0f * ES_PI) / ((float) numSlices);
    
    if (vertices != NULL) {
        *vertices = malloc(sizeof(float) * 3 * numVertices);
    }
    
    if (texCoords != NULL) {
        *texCoords = malloc(sizeof(float) * 2 * numVertices);
    }
    
    if (indices != NULL) {
        *indices = malloc(sizeof(uint32_t) * numIndices);
    }
    
    for (int i = 0; i < numParallels + 1; i++) {
        for (int j = 0; j < numSlices + 1; j++) {
            int vertex = (i * (numSlices + 1) + j) * 3;
            
            if (vertices) {
                (*vertices)[vertex + 0] = radius * sinf(angleStep * (float)i) * sinf(angleStep * (float)j);
                (*vertices)[vertex + 1] = radius * cosf(angleStep * (float)i);
                (*vertices)[vertex + 2] = radius * sinf(angleStep * (float)i) * cosf(angleStep * (float)j);
            }
            
            if (texCoords) {
                int texIndex = (i * (numSlices + 1) + j) * 2;
                (*texCoords)[texIndex + 0] = (float)j / (float)numSlices;
                (*texCoords)[texIndex + 1] = 1.0f - ((float)i / (float)numParallels);
            }
        }
    }
    
    // Generate the indices
    if (indices != NULL) {
        uint32_t *indexBuf = (*indices);
        for (int i = 0; i < numParallels ; i++) {
            for (int j = 0; j < numSlices; j++) {
                *indexBuf++ = i * (numSlices + 1) + j;
                *indexBuf++ = (i + 1) * (numSlices + 1) + j;
                *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1);
                
                *indexBuf++ = i * (numSlices + 1) + j;
                *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1);
                *indexBuf++ = i * (numSlices + 1) + (j + 1);
            }
        }
    }
    
    if (vertices_count) {
        *vertices_count = numVertices;
    }
    
    return numIndices;
}
//  PanoramaUtil.h
//  VRPanoramaKit
//
//  Created by 小發(fā)工作室 on 2017/9/22.
//  Copyright ? 2017年 小發(fā)工作室. All rights reserved.
//

#ifndef PanoramaUtil_h
#define PanoramaUtil_h

#include <stdio.h>

/**
 根據(jù)numSlices和radius的大小取索引,頂點(diǎn),紋理的值
 
 @param numSlices 球面切面數(shù)量
 @param radius 半徑
 @param vertices 3維頂點(diǎn)坐標(biāo)
 @param texCoords 紋理
 @param indices 索引
 @param vertices_count 3維頂點(diǎn)坐標(biāo)數(shù)量
 @return 索引數(shù)量
 */
int esGenSphere(int numSlices,
                float radius,
                float **vertices,
                float **texCoords,
                uint32_t **indices,
                int *vertices_count);

#endif /* PanoramaUtil_h */
//
//  PanoramaController.h
//  VRPanoramaKit
//
//  Created by 小發(fā)工作室 on 2017/9/21.
//  Copyright ? 2017年 小發(fā)工作室. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <CoreMotion/CoreMotion.h>

@interface PanoramaController : GLKViewController

@property (nonatomic, copy  ) NSString        *imageName;

@property (nonatomic, copy  ) NSString        *imageNameType;

@property (nonatomic, strong) CMMotionManager *motionManager;

@property (nonatomic, strong) GLKView         *panoramaView;


/**
 初始化全景控制器

 @param imageName 全景圖名字
 @param type 全景圖類型,默認(rèn)是jpg
 @return PanoramaController
 */
- (instancetype)initWithImageName:(NSString *)imageName type:(NSString *)type;


/**
 啟動(dòng)全景圖
 */
- (void)startPanoramViewMotion;


/**
 關(guān)閉全景圖
 */
- (void)stopPanoramViewMotion;

@end
//
//  PanoramaController.m
//  VRPanoramaKit
//
//  Created by 小發(fā)工作室 on 2017/9/21.
//  Copyright ? 2017年 小發(fā)工作室. All rights reserved.
//

#import "PanoramaController.h"
#import "PanoramaUtil.h"

#define ES_PI  (3.14159265f)

#define MAX_VIEW_DEGREE 110.0f  //最大視角
#define MIN_VIEW_DEGREE 50.0f   //最小視角

#define FRAME_PER_SENCOND 60.0  //幀數(shù)

//#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
//#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height

@interface PanoramaController ()<GLKViewControllerDelegate,GLKViewDelegate>

// 相機(jī)的廣角角度
@property (nonatomic, assign) CGFloat        overture;

// 索引數(shù)
@property (nonatomic, assign) GLsizei        numIndices;

// 頂點(diǎn)索引緩存指針
@property (nonatomic, assign) GLuint         vertexIndicesBuffer;

// 頂點(diǎn)緩存指針
@property (nonatomic, assign) GLuint         vertexBuffer;

// 紋理緩存指針
@property (nonatomic, assign) GLuint         vertexTexCoord;

// 著色器
@property (nonatomic, strong) GLKBaseEffect  *effect;

// 圖片的紋理信息
@property (nonatomic, strong) GLKTextureInfo *textureInfo;

// 模型坐標(biāo)系
@property (nonatomic, assign) GLKMatrix4     modelViewMatrix;

// 手勢(shì)平移距離
@property (nonatomic, assign) CGFloat        panX;
@property (nonatomic, assign) CGFloat        panY;

//兩指縮放大小
@property (nonatomic, assign) CGFloat        scale;

//是否雙擊
@property (nonatomic, assign) BOOL           isTapScale;

//是否根據(jù)陀螺儀旋轉(zhuǎn)
@property (nonatomic, assign) BOOL           isMotion;

//測(cè)試按鈕
@property (nonatomic, strong) UIButton       *startButton;
@property (nonatomic, strong) UIButton       *endButton;

@end

@implementation PanoramaController


- (CMMotionManager *)motionManager {
    if (_motionManager == nil) {
        
        _motionManager = [[CMMotionManager alloc] init];
        
        _motionManager.deviceMotionUpdateInterval = 1/FRAME_PER_SENCOND;
        _motionManager.showsDeviceMovementDisplay = YES;

    }
    return _motionManager;
}

- (instancetype)init {
    
    self = [super init];
    
    if (self) {
        
        [self createPanoramView];
    }
    return self;
}

- (instancetype)initWithImageName:(NSString *)imageName type:(NSString *)type{
    

    self = [super init];
    
    if (self) {

        self.imageName     = imageName;
        self.imageNameType = type;
        
        if (type.length == 0) {
            
            type = @"jpg";
        }
        

        
        [self createPanoramView];
        
        
        //實(shí)際開(kāi)發(fā)中移除測(cè)試按鈕
        [self startPanoramViewMotion];
        
     }
    return self;
}

- (void)startPanoramViewMotion{
    
    self.isMotion = YES;

    self.delegate                         = self;
    self.preferredFramesPerSecond         = FRAME_PER_SENCOND;

    [self setupOpenGL];

    
    [self startDeviceMotion];

}
#pragma -Private

- (void)createPanoramView{
    
    if (self.imageName == nil) {
        NSAssert(self.imageName.length != 0, @"image name is nil,please check image name of PanoramView");
        return;
    }
    
    EAGLContext *context                  = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    self.panoramaView                     = (GLKView *)self.view;
    self.panoramaView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    self.panoramaView.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    self.panoramaView.context             = context;
    self.panoramaView.delegate            = self;
    [EAGLContext setCurrentContext:context];
    
    [self addGesture];

    [self startPanoramViewMotion];

    self.isMotion = NO;

    
}

#pragma mark set device Motion
- (void)startDeviceMotion {

    [self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical];
    
    
    _modelViewMatrix = GLKMatrix4Identity;
    
}

- (void)stopDeviceMotion {
    
    [self.motionManager stopDeviceMotionUpdates];
    [self.motionManager stopAccelerometerUpdates];
    
}

#pragma mark setup OpenGL

- (void)setupOpenGL {
    
    glEnable(GL_DEPTH_TEST);
    
    // 頂點(diǎn)
    GLfloat *vVertices  = NULL;

    // 紋理
    GLfloat *vTextCoord = NULL;

    // 索引
    GLuint *indices     = NULL;

    int numVertices     = 0;

    _numIndices         = esGenSphere(200, 1.0, &vVertices, &vTextCoord, &indices, &numVertices);
    
    
    // 創(chuàng)建索引buffer并將indices的數(shù)據(jù)放入
    glGenBuffers(1, &_vertexIndicesBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexIndicesBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, _numIndices*sizeof(GLuint), indices, GL_STATIC_DRAW);
    
    // 創(chuàng)建頂點(diǎn)buffer并將vVertices中的數(shù)據(jù)放入
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices*3*sizeof(GLfloat), vVertices, GL_STATIC_DRAW);
    
    //設(shè)置頂點(diǎn)屬性,對(duì)頂點(diǎn)的位置,顏色,坐標(biāo)進(jìn)行賦值
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, NULL);
    
    // 創(chuàng)建紋理buffer并將vTextCoord數(shù)據(jù)放入
    glGenBuffers(1, &_vertexTexCoord);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexTexCoord);
    glBufferData(GL_ARRAY_BUFFER, numVertices*2*sizeof(GLfloat), vTextCoord, GL_DYNAMIC_DRAW);
    
    //設(shè)置紋理屬性,對(duì)紋理的位置,顏色,坐標(biāo)進(jìn)行賦值
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*2, NULL);
    
    NSString *filePath = [[NSBundle mainBundle]pathForResource:self.imageName ofType:self.imageNameType];
    
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
    
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath
                                                                      options:options
                                                                        error:nil];
    
    _effect                    = [[GLKBaseEffect alloc]init];
    _effect.texture2d0.enabled = GL_TRUE;
    _effect.texture2d0.name    = textureInfo.name;
}

#pragma mark Gesture

- (void)addGesture {
    
    /// 平移手勢(shì)
    UIPanGestureRecognizer *pan =[[UIPanGestureRecognizer alloc] initWithTarget:self
                                                                         action:@selector(panGestture:)];
    
    /// 捏合手勢(shì)
    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(pinchGesture:)];
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(tapGesture:)];
    
    tap.numberOfTouchesRequired = 1;
    tap.numberOfTapsRequired    = 2;
    
    [self.view addGestureRecognizer:pinch];
    [self.view addGestureRecognizer:pan];
    [self.view addGestureRecognizer:tap];

    _scale = 1.0;
    
}

- (void)panGestture:(UIPanGestureRecognizer *)sender {
    
    CGPoint point = [sender translationInView:self.view];
    _panX         += point.x;
    _panY         += point.y;
    
    //轉(zhuǎn)換之后歸零
    [sender setTranslation:CGPointZero inView:self.view];
    
    
}

- (void)pinchGesture:(UIPinchGestureRecognizer *)sender {
    
    _scale       *= sender.scale;
    sender.scale = 1.0;

}

- (void)tapGesture:(UITapGestureRecognizer *)sender {
    
    if (!_isTapScale) {
        
        _isTapScale = YES;
        
        _scale = 1.5;
    }
    else
    {
        _scale = 1.0;
        _isTapScale = NO;
    }
    

        
}


#pragma mark -GLKViewDelegate

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    
    /**清除顏色緩沖區(qū)內(nèi)容時(shí)候: 使用白色填充*/
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    /**清除顏色緩沖區(qū)與深度緩沖區(qū)內(nèi)容*/
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    [_effect prepareToDraw];
//    glDrawElements(GL_TRIANGLES, _numIndices, GL_UNSIGNED_SHORT, 0);
    glDrawElements(GL_TRIANGLES, _numIndices, GL_UNSIGNED_INT,0);

}

static float xx = 0;
static float yy = 0;
static float zz = 0;
static float ww = 0;


#pragma mark GLKViewControllerDelegate

- (void)glkViewControllerUpdate:(GLKViewController *)controller {
    
    
    CGSize size    = self.view.bounds.size;
    float aspect   = fabs(size.width / size.height);
    
    CGFloat radius = [self rotateFromFocalLengh];
    
    /**GLKMatrix4MakePerspective 配置透視圖
     第一個(gè)參數(shù), 類似于相機(jī)的焦距, 比如10表示窄角度, 100表示廣角 一般65-75;
     第二個(gè)參數(shù): 表示時(shí)屏幕的縱橫比
     第三個(gè), 第四參數(shù): 是為了實(shí)現(xiàn)透視效果, 近大遠(yuǎn)處小, 要確保模型位于遠(yuǎn)近平面之間
     */
    GLKMatrix4 projectionMatrix        = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(radius),
                                                                   aspect,
                                                                   0.1f,
                                                                   1);
    
    GLKQuaternion quaternion;

    
    if(self.isMotion){
        

        
        projectionMatrix                   = GLKMatrix4Scale(projectionMatrix, -1.0f, 1.0f, 1.0f);
        
        CMDeviceMotion *deviceMotion       = self.motionManager.deviceMotion;
        
        double w                           = deviceMotion.attitude.quaternion.w;
        double wx                          = deviceMotion.attitude.quaternion.x;
        double wy                          = deviceMotion.attitude.quaternion.y;
        double wz                          = deviceMotion.attitude.quaternion.z;
        
        quaternion = GLKQuaternionMake(-wx,  wy, wz, w);


        NSLog(@"%f + %f + %f + %f",xx,yy,zz,ww);
        NSLog(@"%f,%f,%f,%f",wx,wy,wz,w);

        
    }
    else{
    
        projectionMatrix = GLKMatrix4Scale(projectionMatrix, -1.0f, 1.0f, 1.0f);

        quaternion       = GLKQuaternionMake(0, 0.7, 0.7, 0);
        _panY            = 0;
        _panX            = 0;
        xx = 0;
        yy = 0;
        zz = 0;
        ww = 0;
    }
    


    GLKMatrix4 rotation                = GLKMatrix4MakeWithQuaternion(quaternion);
    

    //上下滑動(dòng),繞X軸旋轉(zhuǎn)
    projectionMatrix                   = GLKMatrix4RotateX(projectionMatrix, -0.005 * _panY);
    projectionMatrix                   = GLKMatrix4Multiply(projectionMatrix, rotation);
    // 為了保證在水平放置手機(jī)的時(shí)候, 是從下往上看, 因此首先坐標(biāo)系沿著x軸旋轉(zhuǎn)90度
    projectionMatrix                   = GLKMatrix4RotateX(projectionMatrix, M_PI_2);
    
    
    _effect.transform.projectionMatrix = projectionMatrix;
    GLKMatrix4 modelViewMatrix         = GLKMatrix4Identity;
    //左右滑動(dòng)繞Y軸旋轉(zhuǎn)
    modelViewMatrix                    = GLKMatrix4RotateY(modelViewMatrix, 0.005 * _panX);
    _effect.transform.modelviewMatrix  = modelViewMatrix;
 
}

- (void)glkViewController:(GLKViewController *)controller willPause:(BOOL)pause{
    NSLog(@"pause:%d", pause);
}

- (void)drawPanoramView{
}

- (CGFloat)rotateFromFocalLengh{
    
    CGFloat radius = 100 / _scale;
    
    // radius不小于50, 不大于110;
    if (radius < MIN_VIEW_DEGREE) {
        
        radius = MIN_VIEW_DEGREE;
        _scale = 1 / (MIN_VIEW_DEGREE / 100);
        
    }
    if (radius > MAX_VIEW_DEGREE) {
        
        radius = MAX_VIEW_DEGREE;
        _scale = 1 / (MAX_VIEW_DEGREE / 100);
    }
    
    return radius;
}

- (void)dealloc{
    
}


@end

該篇文章是小發(fā)工作室所發(fā),摘抄過(guò)來(lái)方便自己查閱

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我一直懷念那年,那個(gè)教室,那群可愛(ài)的人兒…… 總有那么一群人,給過(guò)你最多的感動(dòng),你們一起哭過(guò),笑過(guò),瘋過(guò),后來(lái)才知...
    槿誓閱讀 167評(píng)論 0 0
  • 一切商業(yè)的原則皆是低買高賣。 那么買的是什么,賣的又是什么呢?通證經(jīng)濟(jì)體系下這種買賣會(huì)有什么變化? 1 商業(yè)模式的...
    BobiGo閱讀 222評(píng)論 0 0
  • 從前。有一個(gè)女巫,她的容貌永遠(yuǎn)停留在22歲。她會(huì)七十二變,神通廣大。她買來(lái)針和藥,脫光孩子們的衣服,然后搖身一變,...
    一棵花白閱讀 2,069評(píng)論 21 59
  • 今天是廣州今年最冷的一天,雖然今年沒(méi)過(guò)幾年。最近跟人聊天也常常忘記已經(jīng)到了2018年。最近的生活,普通、無(wú)味又總有...
    安靈子閱讀 156評(píng)論 0 0

友情鏈接更多精彩內(nèi)容