燈光篇
本節(jié)學(xué)習(xí)目標(biāo)
今天我們要學(xué)習(xí)的SceneKit 游戲框架中的幾種光以及如何使用它們!
學(xué)習(xí)任務(wù)
1.熟悉SCNLight 類(lèi) 2.理解四種光源的作用 3.學(xué)會(huì)如何選擇在游戲場(chǎng)景中使用光源.
光的介紹
- 環(huán)境光(SCNLightTypeAmbient)
這種光的特點(diǎn),沒(méi)有方向轴捎,位置在無(wú)窮遠(yuǎn)處,光均勻的散射到物體上.
- 點(diǎn)光源(SCNLightTypeOmni)
有固定的位置洞渤,方向360度,可以衰減
- 平行方向光(SCNLightTypeDirectional)
只有照射的方向橙凳,沒(méi)有位置,不會(huì)衰減
- 聚焦光源(SCNLightTypeSpot) 可
光源有固定的位置丘损,也有方向,也有照射區(qū)域 奕筐,可以衰減
SCNLight 介紹
我們使用光源,主要用到的類(lèi)就是SCNLight,我們把這個(gè)類(lèi)的屬性分析一下舱痘。
-
創(chuàng)建光對(duì)象
+(instancetype)light;
-
設(shè)置燈光類(lèi)型,就是上面講的那個(gè)類(lèi)型
@property(nonatomic, copy) NSString *type;
-
燈光的顏色
@property(nonatomic, retain) id color;
-
燈光的名字,可以用來(lái)索引燈光用
@property(nonatomic, copy, nullable) NSString *name;
-
是否支持投射陰影,注意,這個(gè)屬性只在點(diǎn)光源或者平行方向光源起作用
@property(nonatomic) BOOL castsShadow;
-
設(shè)置陰影的顏色救欧,默認(rèn)為透明度為50%的黑色
@property(nonatomic, retain) id shadowColor;
-
設(shè)置陰影的采樣角度 默認(rèn)值為3
@property(nonatomic) CGFloat shadowRadius;
-
設(shè)置陰影貼圖的大小,陰影貼圖越大衰粹,陰影越精確,但計(jì)算速度越慢笆怠。如果設(shè)置為{ 0 0}陰影貼圖的大小自動(dòng)選擇铝耻,默認(rèn)為{0,0}
@property(nonatomic) CGSize shadowMapSize NS_AVAILABLE(10_10, 8_0);
-
設(shè)置每一幀計(jì)算陰影貼圖的次數(shù)蹬刷,默認(rèn)為一次
@property(nonatomic) NSUInteger shadowSampleCount NS_AVAILABLE(10_10, 8_0);
-
設(shè)置陰影模式(默認(rèn))
@property(nonatomic) SCNShadowMode shadowMode NS_AVAILABLE(10_10, 8_0); // 可選值為下面三種 SCNShadowModeForward = 0, 通過(guò)Alpha值得變化決定陰影 SCNShadowModeDeferred = 1, 根據(jù)最后的顏色決定陰影瓢捉,一般不太用,除非有多個(gè)光源作用的情況下 SCNShadowModeModulated = 2 光沒(méi)有作用办成,只投射陰影泡态,一般用于圖案作為陰影的情況下,比如鏡像漸變圖像(黑白)
-
陰影的深度偏移量
@property(nonatomic) CGFloat shadowBias NS_AVAILABLE(10_10, 8_0);
-
平行方向放陰影比例值調(diào)節(jié)
@property(nonatomic) CGFloat orthographicScale NS_AVAILABLE(10_10, 8_0);
-
光作用的范圍
@property(nonatomic) CGFloat zFar NS_AVAILABLE(10_10, 8_0); @property(nonatomic) CGFloat zNear NS_AVAILABLE(10_10, 8_0);
-
光衰減的開(kāi)始距離和結(jié)束距離(Omni or Spot light)
@property(nonatomic) CGFloat attenuationStartDistance NS_AVAILABLE(10_10, 8_0);// 默認(rèn)為0 @property(nonatomic) CGFloat attenuationEndDistance NS_AVAILABLE(10_10, 8_0);// 默認(rèn)為1 @property(nonatomic) CGFloat attenuationFalloffExponent NS_AVAILABLE(10_10, 8_0);// 1 表示線性減弱 2表示平方減弱
-
聚焦光的發(fā)射點(diǎn)的方向和光線強(qiáng)度最弱的時(shí)候的夾角
@property(nonatomic) CGFloat spotInnerAngle NS_AVAILABLE(10_10, 8_0);// 默認(rèn)為0度 @property(nonatomic) CGFloat spotOuterAngle NS_AVAILABLE(10_10, 8_0);// 默認(rèn)為45度
-
當(dāng)你要使用碰撞檢測(cè)時(shí)迂卢,請(qǐng)?jiān)O(shè)置下面的屬性
@property(nonatomic) NSUInteger categoryBitMask NS_AVAILABLE(10_10, 8_0);
-
點(diǎn)光源材質(zhì)屬性(只支持spot類(lèi)型)
@property(nonatomic, readonly, nullable) SCNMaterialProperty *gobo NS_AVAILABLE(10_9, 8_0);
你最?lèi)?ài)的代碼部分
我們已經(jīng)熟悉了光源類(lèi)的具體使用方法,下面我們就來(lái)驗(yàn)證一下理論的真實(shí)性某弦!
第一步.創(chuàng)建工程
第二步.添加游戲框架
第三步.創(chuàng)建一個(gè)游戲框架專(zhuān)屬的視圖(SCNView類(lèi)型)
self.gameView = [[SCNView alloc]initWithFrame:self.view.bounds];
self.gameView.backgroundColor = [UIColor blackColor];
[self.view addSubview:self.gameView];
運(yùn)行一下,如果界面是下面這樣,表示創(chuàng)建成功

我們把攝像機(jī)控制打開(kāi),方便我們觀察視圖
self.gameView.allowsCameraControl = true;
第四步.設(shè)置場(chǎng)景
友情提示
SCNView 對(duì)象的scene 屬性,系統(tǒng)默認(rèn)為nil,所以我們必須手動(dòng)創(chuàng)建scene
self.gameView.scene = [SCNScene scene];
第五步.我們給游戲視圖中添加一個(gè)正方形塊節(jié)點(diǎn)和一個(gè)球體節(jié)點(diǎn)
// 創(chuàng)建正方塊
SCNBox *box = [SCNBox boxWithWidth:0.5 height:0.5 length:0.5 chamferRadius:0];// 正方體
// 創(chuàng)建球體
SCNSphere *sphere = [SCNSphere sphereWithRadius:0.1];// 設(shè)置球體半徑為0.1
// 把兩個(gè)結(jié)合體綁定到節(jié)點(diǎn)上
SCNNode *boxNode = [SCNNode node];
boxNode.geometry = box;
boxNode.position = SCNVector3Make(0, 0, -11); // 把節(jié)點(diǎn)的位置固定在(0,0,-11)
SCNNode *sphereNode = [SCNNode node];
sphereNode.geometry = sphere;
sphereNode.position = SCNVector3Make(0, 0, -10); // 把節(jié)點(diǎn)的位置固定在(0,0,-11)
// 添加節(jié)點(diǎn)到場(chǎng)景中去
[self.gameView.scene.rootNode addChildNode:boxNode];
[self.gameView.scene.rootNode addChildNode:sphereNode];
運(yùn)行結(jié)果:
第六步.我們給場(chǎng)景中只添加一個(gè)環(huán)境光
SCNLight *light = [SCNLight light]; // 創(chuàng)建燈光
light.type = SCNLightTypeAmbient; // 設(shè)置燈光類(lèi)型
light.color = [UIColor yellowColor]; // 設(shè)置燈光顏色
SCNNode *lightNode = [SCNNode node];
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode];
運(yùn)行結(jié)果
問(wèn)題1:設(shè)置顏色為yellowColor 為什么物體不是yellow呢而克?
因?yàn)槲矬w材質(zhì)中沒(méi)有黃色成分,比如你傳的是一件綠色的衣服,你用黃光照射他,你不可能看見(jiàn)衣服是綠色或者黃色的,這里你可以把物體的顏色變?yōu)辄S色試試看靶壮。
問(wèn)題2:那為什么和不添加環(huán)境光一樣的效果呢?
因?yàn)橄到y(tǒng)本身如果我們不提供任何光源员萍,它會(huì)自動(dòng)添加環(huán)境光腾降,如果檢測(cè)到我們添加了光源,它將不會(huì)幫我們添加環(huán)境光
第七步.我們向游戲場(chǎng)景中只添加一個(gè)點(diǎn)光源
SCNLight *light = [SCNLight light];// 創(chuàng)建光對(duì)象
light.type = SCNLightTypeOmni;// 設(shè)置類(lèi)型
light.color = [UIColor yellowColor]; // 設(shè)置光的顏色
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 0, 100); // 設(shè)置光源節(jié)點(diǎn)的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場(chǎng)景中去
運(yùn)行結(jié)果:
我們的點(diǎn)光源的位置為(0,0,100),我們把位置改為(0,100,100),看一下效果碎绎,對(duì)比一下螃壤,你就掌握了這種光的特點(diǎn)
點(diǎn)光源的特顯,你應(yīng)該明白了筋帖!我們繼續(xù)奸晴!
第八步.只添加一個(gè)平行方向光源
我們一開(kāi)始說(shuō)了這種光源的特點(diǎn):只有方向,沒(méi)有位置,我們驗(yàn)證一下
SCNLight *light = [SCNLight light];// 創(chuàng)建光對(duì)象
light.type = SCNLightTypeDirectional;// 設(shè)置類(lèi)型
light.color = [UIColor yellowColor]; // 設(shè)置光的顏色
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 10, -100); // 設(shè)置光源節(jié)點(diǎn)的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場(chǎng)景中去
位置為(0,0,-100)運(yùn)行結(jié)果
下面我們把它的位置放在(1000,1000,1000) 看一下結(jié)果
一點(diǎn)變化也沒(méi)有,接著下面我們改變一下照射方向,這種光的默認(rèn)方向?yàn)閦軸負(fù)方向幕随,我們把它設(shè)置成Y軸負(fù)方向
lightNode.rotation = SCNVector4Make(1, 0, 0, -M_PI/2.0);
看一下運(yùn)行結(jié)果
我相信你已經(jīng)明白了這種光的特點(diǎn).
第九步.添加聚焦光源
SCNLight *light = [SCNLight light];// 創(chuàng)建光對(duì)象
light.type = SCNLightTypeSpot;// 設(shè)置類(lèi)型
light.color = [UIColor yellowColor]; // 設(shè)置光的顏色
light.castsShadow = TRUE;// 捕捉陰影
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 0, -9); // 設(shè)置光源節(jié)點(diǎn)的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場(chǎng)景中去
運(yùn)行結(jié)果:
我們?cè)囍褂靡幌抡丈浞秶膶傩?讓它只照射到球
SCNLight *light = [SCNLight light];// 創(chuàng)建光對(duì)象
light.type = SCNLightTypeSpot;// 設(shè)置類(lèi)型
light.color = [UIColor yellowColor]; // 設(shè)置光的顏色
light.castsShadow = TRUE;// 捕捉陰影
light.zFar = 10; // 設(shè)置它最遠(yuǎn)能照射單位10 的地方,也就是說(shuō)只能照到 球體的位置
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 0, 0); // 設(shè)置光源節(jié)點(diǎn)的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場(chǎng)景中去
運(yùn)行:
有的朋友要問(wèn)了蚁滋,那怎么還能看見(jiàn)后面的立方體的,這是因?yàn)槲矬w都存在漫反射赘淮,這個(gè)屬于自然現(xiàn)象辕录,你用手電筒可以去試試!那如何才能讓它看不見(jiàn)后面的立方體呢梢卸?設(shè)置光的發(fā)射角度走诞,上代碼:
light.spotOuterAngle = 2;
運(yùn)行結(jié)果:
上面的幾種光的基本特性講解完畢,本節(jié)的內(nèi)容你掌握了嗎?