在本課一開始認識 RealityKit ECS 架構之後,接下來最重要的兩個物件,就是 RealityView 的「內容」與「模型個體」(ModelEntity),到現在應該已相當熟悉。
「內容」囊括所有虛擬個體,本身也是個物件,內含若干屬性與方法,我們已經用過「內容.add()」,其他屬性與方法並不多,但都相當重要,如下表:
# | 內容的屬性/方法 | 說明 | 初次使用章節 |
---|---|---|---|
1 | add() | 加入個體 | 6-6a |
2 | remove() | 移除個體 | - |
3 | subscribe() | 訂閱(某些事件發布) | 6-? |
4 | entities | 所有已加入個體(陣列) | 6-6c |
5 | camera | 設定鏡頭(虛擬或實景) | 6-? |
6 | environment | 環景(Image-Based Lighting) | 6-7c |
7 | renderingEffects | 場景渲染效果選項 | - |
8 | audioListener | 空間音效的聆聽位置(預設同鏡頭) | - |
本節有兩個目標:一是用預設的幾何模型,組成一個實用場景「旋轉樓梯」,其中需要四元數 simd_quatf 計算旋轉角度;二是觀察「內容.entities」有哪些資訊。
仿照 6-6b 座標軸的做法,將「旋轉樓梯()」寫成一個共享函式,傳回模型個體。在左側欄「第6單元共享程式」之下,新增一個「6-6d 旋轉樓梯.swift」檔案,敲入以下程式:
// 6-6d 共享程式:旋轉樓梯
// Created by Heman, 2025/02/12
// Test Environment: iMac 2019 (macOS 15.3) + Swift Playground 4.6.1
import RealityKit
public func 旋轉樓梯(圓柱半徑 r: Float = 0.3,
高 h: Float = 2.0,
樓梯寬 w: Float = 0.5,
樓梯數 n: Int = 20) -> ModelEntity {
let 圓柱 = MeshResource.generateCylinder(height: h, radius: r)
let 水泥材質 = SimpleMaterial(color: .gray, roughness: 1.0, isMetallic: false)
let 圓柱體 = ModelEntity(mesh: 圓柱, materials: [水泥材質])
圓柱體.name = "旋轉樓梯"
let 橫板 = MeshResource.generateBox(size: [w, w * 0.08, w * 0.4], cornerRadius: w * 0.02)
let 橘色材質 = SimpleMaterial(color: .orange, roughness: 0.2, isMetallic: false)
let 樓梯板 = ModelEntity(mesh: 橫板, materials: [橘色材質])
樓梯板.position.y = -h * 0.5
圓柱體.addChild(樓梯板)
let 樓梯間距 = h / Float(n) // 樓梯間距 0.1m
for i in 0...n {
let 新樓板 = 樓梯板.clone(recursive: false)
新樓板.name = "樓板#\\(i)"
樓梯板.addChild(新樓板)
let 旋轉弧度 = Float.pi * 0.1 * Float(i) // 旋轉間距 .pi * 0.1 = 18°
新樓板.orientation = simd_quatf(angle: 旋轉弧度, axis: [0, 1, 0])
新樓板.position.x = cos(旋轉弧度) * (r + w * 0.4) // 樓梯寬*0.4:一半再小一點
新樓板.position.y = 樓梯間距 * Float(i)
新樓板.position.z = -sin(旋轉弧度) * (r + w * 0.4)
}
return 圓柱體
}
在上面宣告「旋轉樓梯()」時,我們用了一個新語法:參數標籤(label),也就是在函式的參數名稱前面再加一個名字:
public func 旋轉樓梯(圓柱半徑 r: Float = 0.3,
高 h: Float = 2.0,
樓梯寬 w: Float = 0.5,
樓梯數 n: Int = 20) -> ModelEntity { }
圓柱半徑、高、樓梯寬、樓梯數是參數標籤,用來充分表達參數的意義,可以讓其他模組看到;而 r, h, w, n 等參數名稱則只用於函式內部,講求簡單方便,自己看懂就行。
一旦用了參數標籤,當我們呼叫此函式時,只能用參數標籤,不能再用參數名稱:
let 一號梯 = 旋轉樓梯(高: 4.5)
// 不能用:
let 一號梯 = 旋轉樓梯(h: 4.5) // 語法錯誤!
所以參數標籤又稱為外部名稱。若參數標籤為底線 “_”,表示呼叫時前置標籤可省略,這從第1單元就已經用過。
另外,有一行程式碼相當重要,需要特別說明: