燈光篇
本節(jié)學習目標
今天我們要學習的SceneKit 游戲框架中的幾種光以及如何使用它們!
學習任務
1.熟悉SCNLight 類 2.理解四種光源的作用 3.學會如何選擇在游戲場景中使用光源.
光的介紹
- 環(huán)境光(SCNLightTypeAmbient)
這種光的特點,沒有方向,位置在無窮遠處,光均勻的散射到物體上.

- 點光源(SCNLightTypeOmni)
有固定的位置,方向360度,可以衰減

- 平行方向光(SCNLightTypeDirectional)
只有照射的方向,沒有位置,不會衰減

- 聚焦光源(SCNLightTypeSpot) 可
光源有固定的位置,也有方向,也有照射區(qū)域 ,可以衰減

SCNLight 介紹
我們使用光源,主要用到的類就是SCNLight,我們把這個類的屬性分析一下。
-
創(chuàng)建光對象
+(instancetype)light; -
設置燈光類型,就是上面講的那個類型
@property(nonatomic, copy) NSString *type; -
燈光的顏色
@property(nonatomic, retain) id color; -
燈光的名字,可以用來索引燈光用
@property(nonatomic, copy, nullable) NSString *name; -
是否支持投射陰影,注意,這個屬性只在點光源或者平行方向光源起作用
@property(nonatomic) BOOL castsShadow; -
設置陰影的顏色,默認為透明度為50%的黑色
@property(nonatomic, retain) id shadowColor; -
設置陰影的采樣角度 默認值為3
@property(nonatomic) CGFloat shadowRadius; -
設置陰影貼圖的大小,陰影貼圖越大,陰影越精確,但計算速度越慢。如果設置為{ 0 0}陰影貼圖的大小自動選擇,默認為{0,0}
@property(nonatomic) CGSize shadowMapSize NS_AVAILABLE(10_10, 8_0); -
設置每一幀計算陰影貼圖的次數(shù),默認為一次
@property(nonatomic) NSUInteger shadowSampleCount NS_AVAILABLE(10_10, 8_0); -
設置陰影模式(默認)
@property(nonatomic) SCNShadowMode shadowMode NS_AVAILABLE(10_10, 8_0); // 可選值為下面三種 SCNShadowModeForward = 0, 通過Alpha值得變化決定陰影 SCNShadowModeDeferred = 1, 根據(jù)最后的顏色決定陰影,一般不太用,除非有多個光源作用的情況下 SCNShadowModeModulated = 2 光沒有作用,只投射陰影,一般用于圖案作為陰影的情況下,比如鏡像漸變圖像(黑白) -
陰影的深度偏移量
@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); -
光衰減的開始距離和結束距離(Omni or Spot light)
@property(nonatomic) CGFloat attenuationStartDistance NS_AVAILABLE(10_10, 8_0);// 默認為0 @property(nonatomic) CGFloat attenuationEndDistance NS_AVAILABLE(10_10, 8_0);// 默認為1 @property(nonatomic) CGFloat attenuationFalloffExponent NS_AVAILABLE(10_10, 8_0);// 1 表示線性減弱 2表示平方減弱 -
聚焦光的發(fā)射點的方向和光線強度最弱的時候的夾角
@property(nonatomic) CGFloat spotInnerAngle NS_AVAILABLE(10_10, 8_0);// 默認為0度 @property(nonatomic) CGFloat spotOuterAngle NS_AVAILABLE(10_10, 8_0);// 默認為45度 -
當你要使用碰撞檢測時,請設置下面的屬性
@property(nonatomic) NSUInteger categoryBitMask NS_AVAILABLE(10_10, 8_0); -
點光源材質(zhì)屬性(只支持spot類型)
@property(nonatomic, readonly, nullable) SCNMaterialProperty *gobo NS_AVAILABLE(10_9, 8_0);
你最愛的代碼部分
我們已經(jīng)熟悉了光源類的具體使用方法,下面我們就來驗證一下理論的真實性!
第一步.創(chuàng)建工程

第二步.添加游戲框架

第三步.創(chuàng)建一個游戲框架專屬的視圖(SCNView類型)
self.gameView = [[SCNView alloc]initWithFrame:self.view.bounds];
self.gameView.backgroundColor = [UIColor blackColor];
[self.view addSubview:self.gameView];
運行一下,如果界面是下面這樣,表示創(chuàng)建成功

我們把攝像機控制打開,方便我們觀察視圖
self.gameView.allowsCameraControl = true;
第四步.設置場景
友情提示
SCNView 對象的scene 屬性,系統(tǒng)默認為nil,所以我們必須手動創(chuàng)建scene
self.gameView.scene = [SCNScene scene];
第五步.我們給游戲視圖中添加一個正方形塊節(jié)點和一個球體節(jié)點
// 創(chuàng)建正方塊
SCNBox *box = [SCNBox boxWithWidth:0.5 height:0.5 length:0.5 chamferRadius:0];// 正方體
// 創(chuàng)建球體
SCNSphere *sphere = [SCNSphere sphereWithRadius:0.1];// 設置球體半徑為0.1
// 把兩個結合體綁定到節(jié)點上
SCNNode *boxNode = [SCNNode node];
boxNode.geometry = box;
boxNode.position = SCNVector3Make(0, 0, -11); // 把節(jié)點的位置固定在(0,0,-11)
SCNNode *sphereNode = [SCNNode node];
sphereNode.geometry = sphere;
sphereNode.position = SCNVector3Make(0, 0, -10); // 把節(jié)點的位置固定在(0,0,-11)
// 添加節(jié)點到場景中去
[self.gameView.scene.rootNode addChildNode:boxNode];
[self.gameView.scene.rootNode addChildNode:sphereNode];
運行結果:

第六步.我們給場景中只添加一個環(huán)境光
SCNLight *light = [SCNLight light]; // 創(chuàng)建燈光
light.type = SCNLightTypeAmbient; // 設置燈光類型
light.color = [UIColor yellowColor]; // 設置燈光顏色
SCNNode *lightNode = [SCNNode node];
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode];
運行結果

問題1:設置顏色為yellowColor 為什么物體不是yellow呢?
因為物體材質(zhì)中沒有黃色成分,比如你傳的是一件綠色的衣服,你用黃光照射他,你不可能看見衣服是綠色或者黃色的,這里你可以把物體的顏色變?yōu)辄S色試試看。
問題2:那為什么和不添加環(huán)境光一樣的效果呢?
因為系統(tǒng)本身如果我們不提供任何光源,它會自動添加環(huán)境光,如果檢測到我們添加了光源,它將不會幫我們添加環(huán)境光
第七步.我們向游戲場景中只添加一個點光源
SCNLight *light = [SCNLight light];// 創(chuàng)建光對象
light.type = SCNLightTypeOmni;// 設置類型
light.color = [UIColor yellowColor]; // 設置光的顏色
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 0, 100); // 設置光源節(jié)點的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場景中去
運行結果:

我們的點光源的位置為(0,0,100),我們把位置改為(0,100,100),看一下效果,對比一下,你就掌握了這種光的特點

點光源的特顯,你應該明白了!我們繼續(xù)!
第八步.只添加一個平行方向光源
我們一開始說了這種光源的特點:只有方向,沒有位置,我們驗證一下
SCNLight *light = [SCNLight light];// 創(chuàng)建光對象
light.type = SCNLightTypeDirectional;// 設置類型
light.color = [UIColor yellowColor]; // 設置光的顏色
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 10, -100); // 設置光源節(jié)點的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場景中去
位置為(0,0,-100)運行結果

下面我們把它的位置放在(1000,1000,1000) 看一下結果

一點變化也沒有,接著下面我們改變一下照射方向,這種光的默認方向為z軸負方向,我們把它設置成Y軸負方向
lightNode.rotation = SCNVector4Make(1, 0, 0, -M_PI/2.0);
看一下運行結果

我相信你已經(jīng)明白了這種光的特點.
第九步.添加聚焦光源
SCNLight *light = [SCNLight light];// 創(chuàng)建光對象
light.type = SCNLightTypeSpot;// 設置類型
light.color = [UIColor yellowColor]; // 設置光的顏色
light.castsShadow = TRUE;// 捕捉陰影
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 0, -9); // 設置光源節(jié)點的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場景中去
運行結果:

我們試著使用一下照射范圍的屬性,讓它只照射到球
SCNLight *light = [SCNLight light];// 創(chuàng)建光對象
light.type = SCNLightTypeSpot;// 設置類型
light.color = [UIColor yellowColor]; // 設置光的顏色
light.castsShadow = TRUE;// 捕捉陰影
light.zFar = 10; // 設置它最遠能照射單位10 的地方,也就是說只能照到 球體的位置
SCNNode *lightNode = [SCNNode node];
lightNode.position = SCNVector3Make(0, 0, 0); // 設置光源節(jié)點的位置
lightNode.light = light;
[self.gameView.scene.rootNode addChildNode:lightNode]; // 添加到場景中去
運行:

有的朋友要問了,那怎么還能看見后面的立方體的,這是因為物體都存在漫反射,這個屬于自然現(xiàn)象,你用手電筒可以去試試!那如何才能讓它看不見后面的立方體呢?設置光的發(fā)射角度,上代碼:
light.spotOuterAngle = 2;
運行結果:

上面的幾種光的基本特性講解完畢,本節(jié)的內(nèi)容你掌握了嗎?