Skip to content

Commit

Permalink
将APlayer 加载的视频渲染到球体上
Browse files Browse the repository at this point in the history
将APlayer 加载的视频渲染到球体上
  • Loading branch information
wushiguang committed Mar 14, 2018
1 parent f2509be commit 6394fc5
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 22 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16 changes: 11 additions & 5 deletions ARKit-Learn27/ARKit-Learn27/Base.lproj/LaunchScreen.storyboard
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Bn3-h7-o5O"/>
<viewControllerLayoutGuide type="bottom" id="eyW-x8-XQB"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
Expand Down
32 changes: 27 additions & 5 deletions ARKit-Learn27/ARKit-Learn27/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="beV-t9-LIL"/>
<viewControllerLayoutGuide type="bottom" id="8RQ-8Y-AJ3"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BR7-dz-tzS" customClass="SCNView">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<constraints>
<constraint firstItem="BR7-dz-tzS" firstAttribute="top" secondItem="beV-t9-LIL" secondAttribute="bottom" id="ARf-TM-Pzx"/>
<constraint firstItem="BR7-dz-tzS" firstAttribute="trailing" secondItem="8bC-Xf-vdC" secondAttribute="trailing" id="IdQ-5k-DNE"/>
<constraint firstItem="8RQ-8Y-AJ3" firstAttribute="top" secondItem="BR7-dz-tzS" secondAttribute="bottom" id="huR-jQ-Rcq"/>
<constraint firstItem="BR7-dz-tzS" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="knq-YW-8Zn"/>
</constraints>
</view>
<connections>
<outlet property="scnView" destination="BR7-dz-tzS" id="9gg-3m-OSv"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
Expand Down
141 changes: 134 additions & 7 deletions ARKit-Learn27/ARKit-Learn27/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,150 @@
//

#import "ViewController.h"
#import <SceneKit/SceneKit.h>

@interface ViewController ()

@property (weak, nonatomic) IBOutlet SCNView *scnView;
@property (nonatomic,strong) SCNScene *scene;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

self.scnView.backgroundColor = [UIColor lightGrayColor];

// 创建一个3D场景
self.scene = [SCNScene scene];
self.scnView.scene = self.scene;
//创建一个球体 然后将其添加到场景中去

SCNNode *sphereNode = [SCNNode node];
sphereNode.geometry = [SCNSphere sphereWithRadius:10];
sphereNode.rotation = SCNVector4Make(1, 0, 0, -M_PI/2);
[self.scene.rootNode addChildNode:sphereNode];

//我们知道现在球体是有了,但是我们还需要一个眼睛去观察球体,在全景下,眼睛是根据重力感应,来调节观察的角度,所以我们下面创建一个眼睛节点,然后将其放入场景的中心点

SCNNode *eyeNode = [SCNNode node];
eyeNode = [SCNNode node];
eyeNode.camera = [SCNCamera camera]; // 创建照相机对象 就是眼睛
eyeNode.camera.automaticallyAdjustsZRange = true; // 自动添加可视距离
// eyeNode.camera.xFov = 30;
// eyeNode.camera.yFov = 30;
// eyeNode.camera.focalBlurRadius = 0;
eyeNode.camera.focalLength = 30;
eyeNode.camera.focusDistance = 30;
eyeNode.camera.fStop = 0;
[self.scene.rootNode addChildNode:eyeNode];

sphereNode.geometry.firstMaterial.cullMode = SCNCullModeFront;// 设置剔除外表面
sphereNode.geometry.firstMaterial.doubleSided = false; // 设置只渲染一个表面
}

/*
30-写一个全景+VR的播放器
功能
一般vr+全景播放器有一下几个功能
全景模式+VR 共有的功能
1.手势滑动
2.重力感应
3.恢复视角
4.播放/暂停
5.上一曲
6.下一曲
7.手势滑动
8.单击手势 隐藏功能菜单
9.是否可以播放(不可播放出现小菊花)
10.声音加/减功能
11.捏合手势-缩放画面
VR 模式 特有的头控功能
1.显示/隐藏菜单功能
2.播放/暂停功能
3.上一曲功能
4.下一曲功能
5.声音加/减功能
扩展功能
1.视频滤镜
####实现方案选择
近两年随着AR/VR逐渐火热,企业为了给自己的产品中加入新的元素,有可能会将3D元素添加到应用中去,对于IOS 工程师,你有三种选择 OpenGL ES / Metal/SceneKit ,按照性能排名 Metal 第一位,SceneKit性能相对来说没有前两者高,但是对于开发难度来说,SceneKit的难度最低,因为他是面向对象的,对于iOS 开发者,学习成本是最低的。
需要的知识
了解AVPlayer 对象的用法
了解 CMMotionManager 对象的用法
SCNNode 的用法 (SceneKit框架)
SCNScene的用法(SceneKit框架)
SCNGeometry的用法(SceneKit框架)
SCNCamera的用法(SceneKit框架)
UIGestureRecognizer
CIFilter 处理视频滤镜(可选项)
掌握以上知识点 轻松完成播放器的全部需求
后面我会分为以下几个模块进行讲解
a. 如何创建一个渲染全景视频的球体
b. 如何创建将APlayer 加载的视频渲染到球体上
c. 如何实现通过手势移动来调节呈现出来的画面位置
d. 捏合手势如何缩放画面
f. 头控部分布局
g. 如何检测头控按钮被选中
h. 如何实现悬停动画
i. 如何实现分屏显示
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

*/
/*
31-如何创建一个渲染全景视频的球体
实现步骤:
第一步 创建一个应用工程(略了)
第二步 创建一个渲染视图 继承SCNView DFA47D5C-AE21-4A3A-8E53-858CBA60B647.png
第三步 导入框架SceneKit
#import<SceneKit/SceneKit.h>
第四步 创建一个3D场景
self.scene = [SCNScene scene];
第五步 创建一个球体 然后将其添加到场景中去
SCNNode *sphereNode = [SCNNode node];
sphereNode.geometry = [SCNSphere sphereWithRadius:SHPERE_RADIUS];
sphereNode.rotation = SCNVector4Make(1, 0, 0, -M_PI/2);
[self.scene.rootNode addChildNode:sphereNode];
第六步 我们知道现在球体是有了,但是我们还需要一个眼睛去观察球体,在全景下,眼睛是根据重力感应,来调节观察的角度,所以我们下面创建一个眼睛节点,然后将其放入场景的中心点
SCNNode *eyeNode = [SCNNode node];
eyeNode = [SCNNode node];
eyeNode.camera = [SCNCamera camera]; // 创建照相机对象 就是眼睛
eyeNode.camera.automaticallyAdjustsZRange = true; // 自动添加可视距离
eyeNode.camera.xFov = CAMERA_FOX;
eyeNode.camera.yFov =CAMERA_HEIGHT;
eyeNode.camera.focalBlurRadius = 0;
思考问题1:
球体有两个表面 一个外表面一个内表面,在vr 模式下,我们的眼睛是在球体中间的,如何让球体只渲染内表面?
sphereNode.geometry.firstMaterial.cullMode = SCNCullModeFront;// 设置剔除外表面
sphereNode.geometry.firstMaterial.doubleSided = false; // 设置只渲染一个表面
思考问题2:
球体的半径设置多大?
不要设置太小即可,我设置的是10 注意这里没有单位,根据屏幕的宽度和高度进行相对运算,屏幕上边为1 下边为-1 左边为 -1 右边为 1 根据照相机的视角就可以计算出几何模型在视图中的呈现的画面大小了
*/

@end
Binary file not shown.
86 changes: 81 additions & 5 deletions ARKit-Learn28/ARKit-Learn28/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
//

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <SceneKit/SceneKit.h>
#import <SpriteKit/SpriteKit.h>

#define VIDEO_WIDHT 1280
#define VIDEO_HEIGHT 640

@interface ViewController ()

Expand All @@ -16,14 +22,84 @@ @implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

//创建一个AVPlayer 对象
AVPlayer *player = [[AVPlayer alloc]init];

//创建一个SCNVedioNode 对象
SKVideoNode *videoNode = [[SKVideoNode alloc]initWithAVPlayer:player];
videoNode.size = CGSizeMake(VIDEO_WIDHT, VIDEO_HEIGHT);

//创建一个SKScene对象
SKScene *skScene = [SKScene sceneWithSize:videoNode.size];
skScene.scaleMode = SKSceneScaleModeAspectFit;

//让球体去渲染这个SKScene对象
[skScene addChild:videoNode];
videoNode.position = CGPointMake(VIDEO_WIDHT/2, VIDEO_HEIGHT/2);

//将skScene对象设置为球体渲染的内容


}


- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
32-如何创建将APlayer 加载的视频渲染到球体上
实现步骤
第一步 创建一个AVPlayer 对象
_player = [[AVPlayer alloc]init];
第二步 创建一个SCNVedioNode 对象
self.vedioNode = [[SKVideoNode alloc]initWithAVPlayer:_player];
self.vedioNode.size = CGSizeMake(VEDIO_WIDHT, VEDIO_HEIGHT);
第三步 创建一个SKScene 对象
_skScene = [SKScene sceneWithSize:self.vedioNode.size];
self.skScene.scaleMode = SKSceneScaleModeAspectFit;
第四步 让球体去渲染这个SKScene 对象
[self.skScene addChild:self.vedioNode];
self.vedioNode.position = CGPointMake(VEDIO_WIDHT/2, VEDIO_HEIGHT/2);
// 将skscene对象设置为球体渲染的内容
self.renderNode.geometry.firstMaterial.diffuse.contents=self.skScene;
其他功能实现
下面这部分都比较简单
1.监听播放器的当前时间,缓冲时间,视频总时长
self.observerPlayerTime = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
// 处理逻辑代码
}];
2.视频可播放状态检测
[self.player reasonForWaitingToPlay]
3.播放/暂停功能
[self.player play];
[slef.player pause];
4.播放完成/失败检测
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(playToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(playFail:) name:AVPlayerItemNewErrorLogEntryNotification object:nil];
5.计算视频缓冲的时间
NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域
float startSeconds = CMTimeGetSeconds(timeRange.start);
float durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度
*/

@end
Binary file not shown.

0 comments on commit 6394fc5

Please sign in to comment.