SceneKit_入門01_旋轉(zhuǎn)人物
SceneKit_入門02_如何創(chuàng)建工程
SceneKit_入門03_節(jié)點
SceneKit_入門04_燈光
SceneKit_入門05_照相機
SceneKit_入門06_行為動畫
SceneKit_入門07_幾何體
SceneKit_入門08_材質(zhì)
SceneKit_入門09_物理身體
SceneKit_入門10_物理世界
SceneKit_入門11_粒子系統(tǒng)
SceneKit_入門12_物理行為
SceneKit_入門13_骨骼動畫
SceneKit_中級01_模型之間的過渡動畫
SceneKit_中級02_SCNView 詳細講解
SceneKit_中級03_切換照相機視角
SceneKit_中級04_約束的使用
SceneKit_中級05_力的使用
SceneKit_中級06_場景的切換
SceneKit_中級07_動態(tài)修改屬性
SceneKit_中級08_陰影詳解
SceneKit_中級09_碰撞檢測
SceneKit_中級10_濾鏡效果制作
SceneKit_中級11_動畫事件
SceneKit_高級01_GLSL
SceneKit_高級02_粒子系統(tǒng)深入研究
SceneKit_高級03_自定義力
SceneKit_高級04_自定義場景過渡效果
SceneKit_高級05 檢測手勢點擊到節(jié)點
SceneKit_高級06_加載頂點狡赐、紋理、法線坐標
SceneKit_高級07_SCNProgram用法探究
SceneKit_高級08_天空盒子制作
SceneKit_高級09_霧效果
SceneKit_大神01_掉落的文字
SceneKit_大神02_彈幕來襲
SceneKit_大神03_navigationbar上的3D文字
學習目標
1.理解骨骼動畫的含義
2.學習骨骼動畫相關的類(SCNKinner)
開始吧
百度百科
當前有兩種模型動畫的方式:頂點動畫和骨骼動畫筐高。頂點動畫中换薄,每幀動畫其實就是模型特定姿態(tài)的一個“快照”苛白。通過在幀之間插值的方法,引擎可以得到平滑的動畫效果,在骨骼動畫中,模型具有互相連接的“骨骼”組成的骨架結(jié)構(gòu)论衍,通過改變骨骼的朝向和位置來為模型生成動畫。
骨骼動畫比頂點動畫要求更高的處理器性能聚磺,但同時它也具有更多的優(yōu)點坯台,骨骼動畫可以更容易、更快捷地創(chuàng)建瘫寝。不同的骨骼動畫可以被結(jié)合到一起——比如蜒蕾,模型可以轉(zhuǎn)動頭部稠炬、射擊并且同時也在走路。一些引擎可以實時操縱單個骨骼咪啡,這樣就可以和環(huán)境更加準確地進行交互——模型可以俯身并向某個方向觀察或射擊首启,或者從地上的某個地方撿起一個東西。多數(shù)引擎支持頂點動畫撤摸,但不是所有的引擎都支持骨骼動畫毅桃。
蘋果官方
骨骼動畫是一種簡化復雜幾何形狀的動畫的技術,比如游戲中人的特征,動畫骨架是一個簡單的控制節(jié)點的層次結(jié)構(gòu),本身沒有可見的幾何對象,將骨頭和幾何對象進行結(jié)合,當你移動這個骨頭控制的節(jié)點時允許SceneKit 去自動使幾何對象變形。
給張圖理解一下
相信你已經(jīng)基本了解骨骼動畫的含義了准夷。
接下來學習一個類的使用
- SCNKinner 能干什么?
提供一些方法可以將節(jié)點的骨骼動畫進行分離,你可以使用這個對象管理從Scene文件導入的骨骼動畫與節(jié)點和幾何對象之間動態(tài)關系钥飞。
- 怎么使用骨骼動畫?
1.一般情況下,游戲設計師使用3D 工具創(chuàng)建一個皮膚模型,包含了骨骼的動畫,保存在一個場景文件中,你從場景文件中導入這個骨骼模型,然后讓他們運動起來,
2.另外你也可以直接從場景文件中導入動畫對象直接操作骨頭節(jié)點
3.您還可以單獨創(chuàng)建一個自定義的幾何和骨架數(shù)據(jù)的皮膚模型
- 我們先找一個帶骨骼的模型文件,分析一下它的結(jié)構(gòu)
我們先看一下完整的動畫效果
接下來我們做一個練習
如何將一段完整的動畫衫嵌,分階段執(zhí)行,我們剛才看見了這段動畫的時間為0~24秒左右读宙。
首先先介紹一個類(SCNSceneSource)
主要用于管理場景文件的讀取任務,也可以讀取NSData對象哦!你懂了吧,如果這個模型,我們從網(wǎng)絡傳輸?shù)脑?可能就需要使用這個類了。
這個類不詳細講解,今天主要用到它的兩個方法
N0.1
- (NSArray<NSString *> *)identifiersOfEntriesWithClass:(Class)entryClass;
作用:
獲取場景中包含的某一類對象的標識(數(shù)組),可以獲取的類型有 SCNMaterial, SCNScene, SCNGeometry, SCNNode, CAAnimation, SCNLight, SCNCamera, SCNSkinner, SCNMorpher, NSImage
NO.2
- (nullable id)entryWithIdentifier:(NSString *)uid withClass:(Class)entryClass;
作用:
根據(jù)對象的ID 和對象的類型楔绞,獲取對象本身
NO.3
+ (nullable instancetype)sceneSourceWithURL:(NSURL *)url options:(nullable NSDictionary<NSString *, id> *)options;
作用:
初始化方法
NO.4
- (nullable SCNScene *)sceneWithOptions:(nullable NSDictionary<NSString *, id> *)options error:(NSError **)error;
作用:
創(chuàng)建場景
走進代碼的世界
1.創(chuàng)建工程(略)
2.加載場景文件(略)
3.添加框架SceneKit/Scenekit.h
4.創(chuàng)建場景資源對象
SCNSceneSource *sceneSource = [SCNSceneSource sceneSourceWithURL:[[NSBundle mainBundle] URLForResource:@"skinning" withExtension:@"dae"] options:nil];
5.創(chuàng)建場景
scnView.scene = [sceneSource sceneWithOptions:nil error:nil];
6.獲取場景中的某種對象的標識數(shù)組
// 我們獲取動畫類的數(shù)組
NSArray *animationIDs = [sceneSource identifiersOfEntriesWithClass:[CAAnimation class]];
7.把每個動畫幀放到一個大數(shù)組中
NSUInteger animationCount = [animationIDs count];
NSMutableArray *longAnimations = [[NSMutableArray alloc] initWithCapacity:animationCount];
CFTimeInterval maxDuration = 0;
for (NSInteger index = 0; index < animationCount; index++) {
CAAnimation *animation = [sceneSource entryWithIdentifier:animationIDs[index] withClass:[CAAnimation class]];
if (animation) {
maxDuration = MAX(maxDuration, animation.duration);
[longAnimations addObject:animation];
}
}
8.創(chuàng)建一個動畫組
CAAnimationGroup *longAnimationsGroup = [[CAAnimationGroup alloc] init];
longAnimationsGroup.animations = longAnimations;
longAnimationsGroup.duration = maxDuration;
9.截取我們要的動畫階段比如(20~24秒)
// 截取20秒之后的動畫組
CAAnimationGroup *idleAnimationGroup = [longAnimationsGroup copy];
idleAnimationGroup.timeOffset = 20 ;
// 創(chuàng)建一個重復執(zhí)行這個動畫的動畫組
CAAnimationGroup *lastAnimationGroup;
lastAnimationGroup = [CAAnimationGroup animation];
lastAnimationGroup.animations = @[idleAnimationGroup];
lastAnimationGroup.duration = 24.71 -20;
lastAnimationGroup.repeatCount = 10000;
lastAnimationGroup.autoreverses = YES;
10.然后將這個動畫組添加到模型節(jié)點去就可以了
SCNNode *cNode = [scnView.scene.rootNode childNodeWithName:@"avatar_attach" recursively:YES];
[cNode addAnimation:lastAnimationGroup forKey:@"animation"];
運行一下:
提示:
模型中的骨頭只是一個位置,沒有大小和形狀的,如果你想要查看骨頭在什么位置怎么辦呢?
// 查找骨頭節(jié)點
_skeletonNode = [_characterNode childNodeWithName:@"skeleton" recursively:YES];
// 調(diào)用下面的方法給骨頭添加一個小四方塊
- (void)visualizeBones:(BOOL)show ofNode:(SCNNode *)node inheritedScale:(CGFloat)scale
{
scale *= node.scale.x;
if (show) {
if (node.geometry == nil)
node.geometry = [SCNBox boxWithWidth:6.0 / scale height:6.0 / scale length:6.0 / scale chamferRadius:0.5];
}
else {
if ([node.geometry isKindOfClass:[SCNBox class]])
node.geometry = nil;
}
for (SCNNode *child in node.childNodes)
[self visualizeBones:show ofNode:child inheritedScale:scale];
}
效果如下:
SWIFT 版本
- 第一步 獲取資源
let source = SCNSceneSource(url: file!, options: nil)
- 第二步 獲取動畫標志數(shù)組
let animationIDs = source?.identifiersOfEntries(withClass: CAAnimation.self)
var animationArray:[CAAnimation] = []
for id in animationIDs!{
let animation = source?.entryWithIdentifier(id, withClass: CAAnimation.self)
animationArray.append(animation!)
}
- 第三步 創(chuàng)建動畫數(shù)組
let animationGroup = CAAnimationGroup()
animationGroup.animations = animationArray
animationGroup.duration = 21.33
animationGroup.repeatCount = 1000
animationGroup.beginTime = 0
- 第四步 添加
rightHetun.addAnimation(animationGroup, forKey: "an")
- 什么玩意,難道我們做個游戲结闸,光添加動畫就這么復雜?
其實不是的,實際開發(fā)過程中,我們不需要這么做的墓律,處分你要對文件中的骨骼動畫,進行時間上的調(diào)整膀估,我們才會使用這種方法
下面叫大家一種更為簡單的方式,添加骨骼動畫耻讽,找一個帶骨骼動畫的文件
let file = Bundle.main.url(forResource: "hetun", withExtension: "dae")
let source = SCNSceneSource(url: file!, options: nil)
let hetun = try! source?.scene(options: nil).rootNode
// 調(diào)整位置
hetun?.scale = SCNVector3Make(0.01, 0.01, 0.01)
hetun?.rotation = SCNVector4Make(0, 1, 0, -Float.pi/2)
hetun?.position = SCNVector3Make(0, 0, 0)
解釋一下
我們只要獲取到文件的根節(jié)點,根節(jié)點中包含文件所有的元素,然后將rootnode添加到指定的位置即可,這樣我們就完成了,是不是很簡單呢察纯?
總結(jié)
本節(jié)內(nèi)容簡單的介紹了骨骼動畫的概念,骨骼動畫更高級的用法,我們后面再繼續(xù)講解。