SceneKit自学之路(2)

第二个Demo,没有用到什么新的东西。算是对学习的东西一个巩固吧。


该实例模拟了一个简单的天体运动。大概分了以下几步来实现。

- (void)viewDidLoad {
    [super viewDidLoad];
    //创建场景
    SCNView *universeView = [self makeScene];
    //创建太阳
    SCNNode *sunNode = [self makeSun];
    [universeView.scene.rootNode addChildNode:sunNode];
    //太阳自转
    [self rotation:sunNode];
    //创建地球
    SCNNode *earthNode = [self makeEarth];
    //地球自转
    [self rotation:earthNode];
    //地球公转
    [sunNode addChildNode:earthNode];
    //添加月亮
    SCNNode *moonNode = [self makeMoon];
    //月亮自转
    [self rotation:moonNode];
    //月亮公转
    [earthNode addChildNode:moonNode];
}
1、创建场景

在创建场景时,我把除天体以外的SCNViewSCNSceneSCNNode都放在了这初始化。方便流程了理解。

#pragma mark - 初始化Scene
-(SCNView *)makeScene {
    //创建SCNView
    SCNView *universeView = [[SCNView alloc]initWithFrame:self.view.frame];
    [self.view addSubview:universeView];
    [universeView setBackgroundColor:[UIColor lightGrayColor]];
    //创建SCNScene
    SCNScene *scene = [SCNScene new];
    universeView.scene = scene;
    //创建cameraNode(用于调整镜头,必须添加camera,否则添加的node总是会适应scene的大小,无法观测调整大小效果)
    SCNNode *cameraNode = [SCNNode node];
    cameraNode.camera = [SCNCamera camera];
    [scene.rootNode addChildNode:cameraNode];
    cameraNode.position = SCNVector3Make(0, 0,250);
    cameraNode.camera.zFar = 2000;
    return universeView;
}

在这里需要强调的是camera这个Node非常重要,要实现一个完整的功能,几乎必不可少。所以接下来的一篇,我将单独专门研究camera。

2、创建太阳

在上一篇的HelloWorld中,我发现SCNText这个几何图形有些特殊,如果是其他几何图形SCNSphereSCNBox等,在沿Y轴旋转时,都是围着中心旋转。但是SCNText是围着左边旋转。
分析后发现其他的几何图形,他们的坐标轴都是在自己的中心,但是SCNText是在自己的左下角。设置alignmentMode都没用。那如何让SCNText实现围着中心旋转呢?
搜索引擎了两天没有得到结果。我最终采用的方法是类似html的div方式。把SCNText用其他的几何图形包一层,然后让包裹它的几何图形旋转。需要注意的地方是我们需要将SCNText放在parentNode的中心。
我封装了这个一个方法

- (void)recenterText:(SCNNode *)node {
    SCNText *sceneText = (SCNText *)node.geometry;
    SCNVector3 min = SCNVector3Zero;
    SCNVector3 max = SCNVector3Zero;
    [sceneText getBoundingBoxMin:&min max:&max];
    sceneText.alignmentMode = kCAAlignmentCenter;
    CGFloat textHeight = max.y - min.y;
    CGFloat textWidth = max.x - min.x;
    SCNVector3 position = SCNVector3Make(-textWidth/2 , -textHeight/3*2 , 0);
    node.position = position;
}

上面的position的y值,我认为应该是-textHeight/2就行了,但是实际效果却偏高了一点,目测调整为-textHeight/3*2,原因还没想通。

#pragma mark - 初始化Sun
-(SCNNode *)makeSun {
    //创建太阳
    SCNNode *sunNode = [SCNNode new];
    SCNSphere *sphere = [SCNSphere sphereWithRadius:40];
    sphere.firstMaterial.diffuse.contents = [UIColor colorWithRed:1.0 green:0 blue:0 alpha:0.8];
    sunNode.geometry = sphere;
    //把太阳设置为发光源
    sunNode.geometry.firstMaterial.lightingModelName = SCNLightingModelConstant;
    SCNNode *omniLightNode = [SCNNode node];
    omniLightNode.light = [SCNLight light];
    omniLightNode.light.type = SCNLightTypeOmni;
    omniLightNode.light.color = [UIColor whiteColor];
    [sunNode addChildNode:omniLightNode];
    //给他一个Title
    SCNNode *textNode = [SCNNode new];
    SCNText *text = [SCNText textWithString:@"太阳" extrusionDepth:2];
    text.font = [UIFont systemFontOfSize:32];
    text.firstMaterial.diffuse.contents = [UIColor whiteColor];
    textNode.geometry = text;
    [sunNode addChildNode:textNode];
    [self recenterText:textNode];
    return sunNode;
}

我没有素材,就用颜色+文字表达了。给几何图形设置颜色的方法是text.firstMaterial.diffuse.contents = [UIColor redColor];也可以设置firstMateri.almultiply.contents等,了解更多可以查看一下SCNMaterial类。我没计划深入了解贴图,所以这里先跳过。

3、太阳自转
#pragma mark - 自转
-(void)rotation:(SCNNode *)node {
    SCNAction *customAction = [SCNAction rotateByX:0 y:1 z:0 duration:1];
    SCNAction *repeatAction = [SCNAction repeatActionForever:customAction];
    [node runAction:repeatAction];
}
4、初始化地球/月亮

地球和月亮的初始化方法和自转方法与太阳大同小异。

5、地球/月亮公转

实际上每个天体的旋转速度都是不一样的,在Demo中我们忽略这些。
地球是围着太阳旋转的,我们直接把earthNode加入sunNode的子节点,earthNode就跟着sunNode一起旋转了。

[sunNode addChildNode:earthNode];

假如要实现公转速度与太阳自转速度不相等,只需要再加一个公转速度的节点,并将地球节点设为它的子节点就好了。
还要注意地球与太阳的位置

earthNode.position = SCNVector3Make(120, 0, 0);

这个position就是node的坐标原点相对parentNode坐标原点的位置。


代码写得比较冗余(实际上除了注释也就几十行代码),可以按照代码规范优化。但是目前是以学习为主,所以尽量把所有的流程都写出来,方便理解。

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

推荐阅读更多精彩内容