Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions Example/Example/RealityKitViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,27 @@ final class RealityKitViewController: UIViewController, UIGestureRecognizerDeleg
updateCameraTransform()

let neck = vrmEntity.humanoid.node(for: .neck)
let leftShoulder = vrmEntity.humanoid.node(for: .leftShoulder) ?? vrmEntity.humanoid.node(for: .leftUpperArm)
let rightShoulder = vrmEntity.humanoid.node(for: .rightShoulder) ?? vrmEntity.humanoid.node(for: .rightUpperArm)
let leftArm: Entity?
let rightArm: Entity?
switch vrmEntity.vrm {
case .v1:
leftArm = vrmEntity.humanoid.node(for: .leftShoulder)
rightArm = vrmEntity.humanoid.node(for: .rightShoulder)
case .v0:
leftArm = vrmEntity.humanoid.node(for: .leftUpperArm)
rightArm = vrmEntity.humanoid.node(for: .rightUpperArm)
}
Comment on lines +103 to +112
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic for determining the arm entities based on the VRM version is duplicated across multiple example files (RealityKitViewController.swift, MacExample/ContentView.swift, VisionExample/ContentView.swift). A similar duplication exists for SCNNode in ViewController.swift and WatchExample Watch App/ViewModel.swift.

To improve code reuse and maintainability, consider abstracting this logic into computed properties on VRMEntity and VRMNode respectively.

For example, you could add this to VRMEntity:

public var leftArm: Entity? {
    switch vrm {
    case .v1: return humanoid.node(for: .leftShoulder)
    case .v0: return humanoid.node(for: .leftUpperArm)
    }
}

public var rightArm: Entity? {
    switch vrm {
    case .v1: return humanoid.node(for: .rightShoulder)
    case .v0: return humanoid.node(for: .rightUpperArm)
    }
}

This would make the call sites much cleaner.

If you prefer to keep the changes local to this file for now, you can make the existing code more concise by initializing leftArm and rightArm as a tuple.

            let (leftArm, rightArm): (Entity?, Entity?)
            switch vrmEntity.vrm {
            case .v1:
                (leftArm, rightArm) = (vrmEntity.humanoid.node(for: .leftShoulder), vrmEntity.humanoid.node(for: .rightShoulder))
            case .v0:
                (leftArm, rightArm) = (vrmEntity.humanoid.node(for: .leftUpperArm), vrmEntity.humanoid.node(for: .rightUpperArm))
            }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the logic is intended for visual adjustments specific to each example, so I think keeping it local rather than abstracting it is preferable.


let neckRotation = simd_quatf(angle: 20 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let shoulderRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let armRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
if let neck {
neck.transform.rotation = neck.transform.rotation * neckRotation
}
if let leftShoulder {
leftShoulder.transform.rotation = leftShoulder.transform.rotation * shoulderRotation
if let leftArm {
leftArm.transform.rotation = leftArm.transform.rotation * armRotation
}
if let rightShoulder {
rightShoulder.transform.rotation = rightShoulder.transform.rotation * shoulderRotation
if let rightArm {
rightArm.transform.rotation = rightArm.transform.rotation * armRotation
}
vrmEntity.setBlendShape(value: 1.0, for: .preset(currentExpression.preset))

Expand Down
14 changes: 12 additions & 2 deletions Example/Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,18 @@ class ViewController: UIViewController {
node.setBlendShape(value: 1.0, for: .preset(currentExpression.preset))

node.humanoid.node(for: .neck)?.eulerAngles = SCNVector3(0, 0, 20 * CGFloat.pi / 180)
node.humanoid.node(for: .leftShoulder)?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / 180)
node.humanoid.node(for: .rightShoulder)?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / 180)
let leftArm: SCNNode?
let rightArm: SCNNode?
switch node.vrm {
case .v1:
leftArm = node.humanoid.node(for: .leftShoulder)
rightArm = node.humanoid.node(for: .rightShoulder)
case .v0:
leftArm = node.humanoid.node(for: .leftUpperArm)
rightArm = node.humanoid.node(for: .rightUpperArm)
}
leftArm?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / 180)
rightArm?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / 180)

node.runAction(SCNAction.repeatForever(SCNAction.sequence([
SCNAction.rotateBy(x: 0, y: -0.5, z: 0, duration: 0.5),
Expand Down
23 changes: 16 additions & 7 deletions Example/MacExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SwiftUI
import RealityKit
internal import VRMRealityKit
internal import Combine
internal import VRMKit

struct ContentView: View {
@State private var viewModel = ContentViewModel()
Expand Down Expand Up @@ -73,19 +74,27 @@ final class ContentViewModel {

// Adjust pose
let neck = vrmEntity.humanoid.node(for: .neck)
let leftShoulder = vrmEntity.humanoid.node(for: .leftShoulder) ?? vrmEntity.humanoid.node(for: .leftUpperArm)
let rightShoulder = vrmEntity.humanoid.node(for: .rightShoulder) ?? vrmEntity.humanoid.node(for: .rightUpperArm)
let leftArm: Entity?
let rightArm: Entity?
switch vrmEntity.vrm {
case .v1:
leftArm = vrmEntity.humanoid.node(for: .leftShoulder)
rightArm = vrmEntity.humanoid.node(for: .rightShoulder)
case .v0:
leftArm = vrmEntity.humanoid.node(for: .leftUpperArm)
rightArm = vrmEntity.humanoid.node(for: .rightUpperArm)
}

let neckRotation = simd_quatf(angle: 20 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let shoulderRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let armRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
if let neck {
neck.transform.rotation = neck.transform.rotation * neckRotation
}
if let leftShoulder {
leftShoulder.transform.rotation = leftShoulder.transform.rotation * shoulderRotation
if let leftArm {
leftArm.transform.rotation = leftArm.transform.rotation * armRotation
}
if let rightShoulder {
rightShoulder.transform.rotation = rightShoulder.transform.rotation * shoulderRotation
if let rightArm {
rightArm.transform.rotation = rightArm.transform.rotation * armRotation
}
vrmEntity.setBlendShape(value: 1.0, for: .custom("><"))

Expand Down
22 changes: 15 additions & 7 deletions Example/VisionExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,27 @@ final class ImmersiveViewModel {

// Adjust pose
let neck = vrmEntity.humanoid.node(for: .neck)
let leftShoulder = vrmEntity.humanoid.node(for: .leftShoulder) ?? vrmEntity.humanoid.node(for: .leftUpperArm)
let rightShoulder = vrmEntity.humanoid.node(for: .rightShoulder) ?? vrmEntity.humanoid.node(for: .rightUpperArm)
let leftArm: Entity?
let rightArm: Entity?
switch vrmEntity.vrm {
case .v1:
leftArm = vrmEntity.humanoid.node(for: .leftShoulder)
rightArm = vrmEntity.humanoid.node(for: .rightShoulder)
case .v0:
leftArm = vrmEntity.humanoid.node(for: .leftUpperArm)
rightArm = vrmEntity.humanoid.node(for: .rightUpperArm)
}

let neckRotation = simd_quatf(angle: 20 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let shoulderRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let armRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
if let neck {
neck.transform.rotation = neck.transform.rotation * neckRotation
}
if let leftShoulder {
leftShoulder.transform.rotation = leftShoulder.transform.rotation * shoulderRotation
if let leftArm {
leftArm.transform.rotation = leftArm.transform.rotation * armRotation
}
if let rightShoulder {
rightShoulder.transform.rotation = rightShoulder.transform.rotation * shoulderRotation
if let rightArm {
rightArm.transform.rotation = rightArm.transform.rotation * armRotation
}
vrmEntity.setBlendShape(value: 1.0, for: .custom("><"))

Expand Down
15 changes: 13 additions & 2 deletions Example/WatchExample Watch App/ViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,19 @@ final class ViewModel: ObservableObject {
let rotationOffset = model.initialRotation
node.eulerAngles = SCNVector3(0, rotationOffset, 0)

node.humanoid.node(for: .leftShoulder)?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / 180)
node.humanoid.node(for: .rightShoulder)?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / -180)
let leftArm: SCNNode?
let rightArm: SCNNode?
switch node.vrm {
case .v1:
leftArm = node.humanoid.node(for: .leftShoulder)
rightArm = node.humanoid.node(for: .rightShoulder)
case .v0:
leftArm = node.humanoid.node(for: .leftUpperArm)
rightArm = node.humanoid.node(for: .rightUpperArm)
}

leftArm?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / 180)
rightArm?.eulerAngles = SCNVector3(0, 0, 40 * CGFloat.pi / -180)

node.runAction(.repeatForever(.sequence([
.wait(duration: 3.0),
Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,18 @@ vrmEntity.setBlendShape(value: 1.0, for: .custom("><"))
```swift
vrmEntity.setBlendShape(value: 1.0, for: .preset(.fun))
let neckRotation = simd_quatf(angle: 20 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let shoulderRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let armRotation = simd_quatf(angle: 40 * .pi / 180, axis: SIMD3<Float>(0, 0, 1))
let (leftArm, rightArm): (Entity?, Entity?)
switch vrmEntity.vrm {
case .v1:
(leftArm, rightArm) = (vrmEntity.humanoid.node(for: .leftShoulder), vrmEntity.humanoid.node(for: .rightShoulder))
case .v0:
(leftArm, rightArm) = (vrmEntity.humanoid.node(for: .leftUpperArm), vrmEntity.humanoid.node(for: .rightUpperArm))
}

vrmEntity.humanoid.node(for: .neck)?.transform.rotation *= neckRotation
vrmEntity.humanoid.node(for: .leftShoulder)?.transform.rotation *= shoulderRotation
vrmEntity.humanoid.node(for: .rightShoulder)?.transform.rotation *= shoulderRotation
leftArm?.transform.rotation *= armRotation
rightArm?.transform.rotation *= armRotation
```

### Read the thumbnail image
Expand Down
Loading