全景视图iOS

//  PanoramaUtil.c
//  VRPanoramaKit
//
//  Created by 小发工作室 on 2017/9/22.
//  Copyright © 2017年 小发工作室. All rights reserved.
//

#include "PanoramaUtil.h"
#include 
#include 

#define ES_PI  (3.14159265f)


/**
 根据numSlices和radius的大小取索引,顶点,纹理的值
 
 @param numSlices 球面切面数量
 @param radius 半径
 @param vertices 3维顶点坐标
 @param texCoords 纹理
 @param indices 索引
 @param vertices_count 3维顶点坐标数量
 @return 索引数量
 */
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 小发工作室 on 2017/9/22.
//  Copyright © 2017年 小发工作室. All rights reserved.
//

#ifndef PanoramaUtil_h
#define PanoramaUtil_h

#include 

/**
 根据numSlices和radius的大小取索引,顶点,纹理的值
 
 @param numSlices 球面切面数量
 @param radius 半径
 @param vertices 3维顶点坐标
 @param texCoords 纹理
 @param indices 索引
 @param vertices_count 3维顶点坐标数量
 @return 索引数量
 */
int esGenSphere(int numSlices,
                float radius,
                float **vertices,
                float **texCoords,
                uint32_t **indices,
                int *vertices_count);

#endif /* PanoramaUtil_h */
//
//  PanoramaController.h
//  VRPanoramaKit
//
//  Created by 小发工作室 on 2017/9/21.
//  Copyright © 2017年 小发工作室. All rights reserved.
//

#import 
#import 
#import 

@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 全景图类型,默认是jpg
 @return PanoramaController
 */
- (instancetype)initWithImageName:(NSString *)imageName type:(NSString *)type;


/**
 启动全景图
 */
- (void)startPanoramViewMotion;


/**
 关闭全景图
 */
- (void)stopPanoramViewMotion;

@end
//
//  PanoramaController.m
//  VRPanoramaKit
//
//  Created by 小发工作室 on 2017/9/21.
//  Copyright © 2017年 小发工作室. 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  //帧数

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

@interface PanoramaController ()

// 相机的广角角度
@property (nonatomic, assign) CGFloat        overture;

// 索引数
@property (nonatomic, assign) GLsizei        numIndices;

// 顶点索引缓存指针
@property (nonatomic, assign) GLuint         vertexIndicesBuffer;

// 顶点缓存指针
@property (nonatomic, assign) GLuint         vertexBuffer;

// 纹理缓存指针
@property (nonatomic, assign) GLuint         vertexTexCoord;

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

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

// 模型坐标系
@property (nonatomic, assign) GLKMatrix4     modelViewMatrix;

// 手势平移距离
@property (nonatomic, assign) CGFloat        panX;
@property (nonatomic, assign) CGFloat        panY;

//两指缩放大小
@property (nonatomic, assign) CGFloat        scale;

//是否双击
@property (nonatomic, assign) BOOL           isTapScale;

//是否根据陀螺仪旋转
@property (nonatomic, assign) BOOL           isMotion;

//测试按钮
@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];
        
        
        //实际开发中移除测试按钮
        [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);
    
    // 顶点
    GLfloat *vVertices  = NULL;

    // 纹理
    GLfloat *vTextCoord = NULL;

    // 索引
    GLuint *indices     = NULL;

    int numVertices     = 0;

    _numIndices         = esGenSphere(200, 1.0, &vVertices, &vTextCoord, &indices, &numVertices);
    
    
    // 创建索引buffer并将indices的数据放入
    glGenBuffers(1, &_vertexIndicesBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexIndicesBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, _numIndices*sizeof(GLuint), indices, GL_STATIC_DRAW);
    
    // 创建顶点buffer并将vVertices中的数据放入
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices*3*sizeof(GLfloat), vVertices, GL_STATIC_DRAW);
    
    //设置顶点属性,对顶点的位置,颜色,坐标进行赋值
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, NULL);
    
    // 创建纹理buffer并将vTextCoord数据放入
    glGenBuffers(1, &_vertexTexCoord);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexTexCoord);
    glBufferData(GL_ARRAY_BUFFER, numVertices*2*sizeof(GLfloat), vTextCoord, GL_DYNAMIC_DRAW);
    
    //设置纹理属性,对纹理的位置,颜色,坐标进行赋值
    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 {
    
    /// 平移手势
    UIPanGestureRecognizer *pan =[[UIPanGestureRecognizer alloc] initWithTarget:self
                                                                         action:@selector(panGestture:)];
    
    /// 捏合手势
    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;
    
    //转换之后归零
    [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 {
    
    /**清除颜色缓冲区内容时候: 使用白色填充*/
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    /**清除颜色缓冲区与深度缓冲区内容*/
    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 配置透视图
     第一个参数, 类似于相机的焦距, 比如10表示窄角度, 100表示广角 一般65-75;
     第二个参数: 表示时屏幕的纵横比
     第三个, 第四参数: 是为了实现透视效果, 近大远处小, 要确保模型位于远近平面之间
     */
    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);
    

    //上下滑动,绕X轴旋转
    projectionMatrix                   = GLKMatrix4RotateX(projectionMatrix, -0.005 * _panY);
    projectionMatrix                   = GLKMatrix4Multiply(projectionMatrix, rotation);
    // 为了保证在水平放置手机的时候, 是从下往上看, 因此首先坐标系沿着x轴旋转90度
    projectionMatrix                   = GLKMatrix4RotateX(projectionMatrix, M_PI_2);
    
    
    _effect.transform.projectionMatrix = projectionMatrix;
    GLKMatrix4 modelViewMatrix         = GLKMatrix4Identity;
    //左右滑动绕Y轴旋转
    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

该篇文章是小发工作室所发,摘抄过来方便自己查阅

你可能感兴趣的:(全景视图iOS)