第二個(gè)Demo袱耽,沒有用到什么新的東西咒循。算是對(duì)學(xué)習(xí)的東西一個(gè)鞏固吧据途。
該實(shí)例模擬了一個(gè)簡單的天體運(yùn)動(dòng)。大概分了以下幾步來實(shí)現(xiàn)叙甸。
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建場景
SCNView *universeView = [self makeScene];
//創(chuàng)建太陽
SCNNode *sunNode = [self makeSun];
[universeView.scene.rootNode addChildNode:sunNode];
//太陽自轉(zhuǎn)
[self rotation:sunNode];
//創(chuàng)建地球
SCNNode *earthNode = [self makeEarth];
//地球自轉(zhuǎn)
[self rotation:earthNode];
//地球公轉(zhuǎn)
[sunNode addChildNode:earthNode];
//添加月亮
SCNNode *moonNode = [self makeMoon];
//月亮自轉(zhuǎn)
[self rotation:moonNode];
//月亮公轉(zhuǎn)
[earthNode addChildNode:moonNode];
}
1颖医、創(chuàng)建場景
在創(chuàng)建場景時(shí),我把除天體以外的SCNView
裆蒸、SCNScene
熔萧、SCNNode
都放在了這初始化。方便流程了理解僚祷。
#pragma mark - 初始化Scene
-(SCNView *)makeScene {
//創(chuàng)建SCNView
SCNView *universeView = [[SCNView alloc]initWithFrame:self.view.frame];
[self.view addSubview:universeView];
[universeView setBackgroundColor:[UIColor lightGrayColor]];
//創(chuàng)建SCNScene
SCNScene *scene = [SCNScene new];
universeView.scene = scene;
//創(chuàng)建cameraNode(用于調(diào)整鏡頭佛致,必須添加camera,否則添加的node總是會(huì)適應(yīng)scene的大小辙谜,無法觀測(cè)調(diào)整大小效果)
SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = [SCNCamera camera];
[scene.rootNode addChildNode:cameraNode];
cameraNode.position = SCNVector3Make(0, 0,250);
cameraNode.camera.zFar = 2000;
return universeView;
}
在這里需要強(qiáng)調(diào)的是camera這個(gè)Node非常重要俺榆,要實(shí)現(xiàn)一個(gè)完整的功能,幾乎必不可少装哆。所以接下來的一篇罐脊,我將單獨(dú)專門研究camera定嗓。
2、創(chuàng)建太陽
在上一篇的HelloWorld中萍桌,我發(fā)現(xiàn)SCNText
這個(gè)幾何圖形有些特殊宵溅,如果是其他幾何圖形SCNSphere
、SCNBox
等上炎,在沿Y軸旋轉(zhuǎn)時(shí)恃逻,都是圍著中心旋轉(zhuǎn)。但是SCNText
是圍著左邊旋轉(zhuǎn)反症。
分析后發(fā)現(xiàn)其他的幾何圖形辛块,他們的坐標(biāo)軸都是在自己的中心,但是SCNText
是在自己的左下角铅碍。設(shè)置alignmentMode
都沒用润绵。那如何讓SCNText
實(shí)現(xiàn)圍著中心旋轉(zhuǎn)呢?
搜索引擎了兩天沒有得到結(jié)果胞谈。我最終采用的方法是類似html的div方式尘盼。把SCNText
用其他的幾何圖形包一層,然后讓包裹它的幾何圖形旋轉(zhuǎn)烦绳。需要注意的地方是我們需要將SCNText
放在parentNode
的中心卿捎。
我封裝了這個(gè)一個(gè)方法
- (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值,我認(rèn)為應(yīng)該是-textHeight/2
就行了径密,但是實(shí)際效果卻偏高了一點(diǎn)午阵,目測(cè)調(diào)整為-textHeight/3*2
,原因還沒想通享扔。
#pragma mark - 初始化Sun
-(SCNNode *)makeSun {
//創(chuàng)建太陽
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;
//把太陽設(shè)置為發(fā)光源
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];
//給他一個(gè)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;
}
我沒有素材底桂,就用顏色+文字表達(dá)了。給幾何圖形設(shè)置顏色的方法是text.firstMaterial.diffuse.contents = [UIColor redColor];
也可以設(shè)置firstMateri.almultiply.contents
等惧眠,了解更多可以查看一下SCNMaterial
類籽懦。我沒計(jì)劃深入了解貼圖,所以這里先跳過氛魁。
3暮顺、太陽自轉(zhuǎn)
#pragma mark - 自轉(zhuǎn)
-(void)rotation:(SCNNode *)node {
SCNAction *customAction = [SCNAction rotateByX:0 y:1 z:0 duration:1];
SCNAction *repeatAction = [SCNAction repeatActionForever:customAction];
[node runAction:repeatAction];
}
4、初始化地球/月亮
地球和月亮的初始化方法和自轉(zhuǎn)方法與太陽大同小異秀存。
5捶码、地球/月亮公轉(zhuǎn)
實(shí)際上每個(gè)天體的旋轉(zhuǎn)速度都是不一樣的,在Demo中我們忽略這些或链。
地球是圍著太陽旋轉(zhuǎn)的宙项,我們直接把earthNode
加入sunNode
的子節(jié)點(diǎn),earthNode
就跟著sunNode
一起旋轉(zhuǎn)了株扛。
[sunNode addChildNode:earthNode];
假如要實(shí)現(xiàn)公轉(zhuǎn)速度與太陽自轉(zhuǎn)速度不相等尤筐,只需要再加一個(gè)公轉(zhuǎn)速度的節(jié)點(diǎn)汇荐,并將地球節(jié)點(diǎn)設(shè)為它的子節(jié)點(diǎn)就好了。
還要注意地球與太陽的位置
earthNode.position = SCNVector3Make(120, 0, 0);
這個(gè)position
就是node
的坐標(biāo)原點(diǎn)相對(duì)parentNode
坐標(biāo)原點(diǎn)的位置盆繁。
代碼寫得比較冗余(實(shí)際上除了注釋也就幾十行代碼)掀淘,可以按照代碼規(guī)范優(yōu)化。但是目前是以學(xué)習(xí)為主油昂,所以盡量把所有的流程都寫出來革娄,方便理解。