上節提到RealityKit 預設的幾何模型只有6種:包括3D文字、立方體、球體、平面、圓錐體、圓柱體等,均使用 MeshResource 的類型方法產出。

雖然預設模型種類不多,但加以組合還是可以製作不少物件,本節就利用3D文字、圓錐體、圓柱體來製作一個「3D座標軸」,以便在後續程式中當作虛擬空間的參考座標。

我們要將「3D座標軸」做成「共享程式」,這樣以後每個頁面都可用到,避免程式碼一再重複。怎麼做呢?在電子書模式(playgroudbook)下,只要將下面寫好的「座標軸()」函式,剪貼到左側欄「原始碼」之下的 “SharedCode.swift” 裡面即可。

截圖 2025-02-07 下午1.37.17.png

搬移到共享程式唯一需要更改的地方,是函式必須宣告為 “public” (公開),如果沒有加 public,主程式會出現以下錯誤:”Cannot find ‘座標軸’ in scope” (有效範圍內找不到「座標軸」名稱)

截圖 2025-02-13 下午1.13.22.png

這是因為主程式與共享程式現在位於不同模組,預設是不能互通的,只有宣告為 “public” 的函式、變數或物件,才能讓別的模組取用。

共享的「座標軸()」程式碼如下:

// 6-6b 3D座標系統
// Created by Heman Lu on 2025/02/03
// Test Environment: iMac 2019 (macOS 15.3) + Swift Playground 4.6.1
import RealityKit

public func 座標軸(_ 軸長: Float = 1.0) -> ModelEntity {
    let 原點 = MeshResource.generateSphere(radius: 0.0)
    let 軸線 = MeshResource.generateCylinder(height: 軸長 * 2.0, radius: 軸長 * 0.001)
    let 箭頭 = MeshResource.generateCone(height: 軸長 * 0.07, radius: 軸長 * 0.01)
    
    let 座標原點 = ModelEntity(mesh: 原點)
    
    let y軸 = ModelEntity(mesh: 軸線)
    let 箭頭y = ModelEntity(mesh: 箭頭)
    箭頭y.position.y = 軸長
    y軸.addChild(箭頭y)
    座標原點.addChild(y軸)
        
    let x軸 = ModelEntity(mesh: 軸線)
    let 箭頭x = ModelEntity(mesh: 箭頭)
    箭頭x.position.y = 軸長
    x軸.addChild(箭頭x)
    x軸.orientation = simd_quatf(angle: .pi / 2.0, axis: [0, 0, -1])
    
    let z軸 = ModelEntity(mesh: 軸線)
    let 箭頭z = ModelEntity(mesh: 箭頭)
    箭頭z.position.y = 軸長
    z軸.addChild(箭頭z)
    z軸.orientation = simd_quatf(angle: .pi / 2.0, axis: [1, 0, 0])
    
    let 字體比例 = 軸長 * 0.005
    let y字 = ModelEntity(mesh: .generateText("Y"))
    y字.scale = [字體比例, 字體比例, 字體比例]
    y字.position.y = 軸長
    座標原點.addChild(y字)

    let x字 = ModelEntity(mesh: .generateText("X"))
    x字.scale = [字體比例, 字體比例, 字體比例]
    x字.position.x = 軸長
    座標原點.addChild(x字)
    座標原點.addChild(x軸)

    let z字 = ModelEntity(mesh: .generateText("Z"))
    z字.scale = [字體比例, 字體比例, 字體比例]
    z字.position.z = 軸長
    座標原點.addChild(z字)
    座標原點.addChild(z軸)
    
    return 座標原點
}

注意第一行 import RealityKit,每個共享程式還是要導入所需框架。

「座標軸()」會以模型個體(ModelEntity)的類型傳回一個做好的X/Y/Z座標系統,以後要用時,只要呼叫「座標軸()」並加入「內容」即可:

內容.add(座標軸())    // 預設XYZ軸長±1.0米
// 或
內容.add(座標軸(2.5)) // XYZ軸長±2.5米

實際做法,我們先產出一個隱藏的(半徑=0)小球模型「座標原點」,當作整個座標系的原點,也是所有個體的根節點,其他個體用「座標原點.addChild()」加進來。