Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c8d5da7
vrm1.0 support
tatsuya-ogawa Jan 26, 2026
6c880bd
Update Example/VisionExample/VisionExampleApp.swift
tatsuya-ogawa Jan 31, 2026
85a140f
displayName
tatsuya-ogawa Jan 31, 2026
b6a0b7f
displayName
tatsuya-ogawa Jan 31, 2026
04b327f
Update Example/VisionExample/ContentView.swift
tatsuya-ogawa Jan 31, 2026
7e8607f
materialName
tatsuya-ogawa Jan 31, 2026
0ea686a
SpringBone
tatsuya-ogawa Jan 31, 2026
445e5f6
revert Sources/VRMKit/VRM/Node.swift
tatsuya-ogawa Jan 31, 2026
b66fe1c
revert Sources/VRMKit/VRM/VRM1.swift
tatsuya-ogawa Jan 31, 2026
6371170
Revert "revert Sources/VRMKit/VRM/VRM1.swift"
tatsuya-ogawa Jan 31, 2026
51d4ff6
Revert "revert Sources/VRMKit/VRM/Node.swift"
tatsuya-ogawa Jan 31, 2026
4b5e8fd
fix test
tatsuya-ogawa Jan 31, 2026
58c01fa
fix BlendShape
tatsuya-ogawa Feb 1, 2026
c058dd8
Merge branch 'main' of github.com:tatsuya-ogawa/VRMKit into feature/v…
tatsuya-ogawa Feb 2, 2026
d8b23bd
fix comment
tatsuya-ogawa Feb 2, 2026
8b9b966
remove comments
tatsuya-ogawa Feb 2, 2026
d1cb5f3
fix comment
tatsuya-ogawa Feb 2, 2026
9451a52
mac example
tatsuya-ogawa Feb 2, 2026
dee4292
add testcase
tatsuya-ogawa Feb 2, 2026
e51ea67
remove unnecessary comment
tatsuya-ogawa Feb 2, 2026
84d9113
SwiftTesting
tatsuya-ogawa Feb 3, 2026
6abaf87
revert VRM1Tests.swift
tatsuya-ogawa Feb 3, 2026
9dd2db8
Revert "revert VRM1Tests.swift"
tatsuya-ogawa Feb 3, 2026
9876270
refactor testcase
tatsuya-ogawa Feb 3, 2026
4e407c4
allowedUserName
tatsuya-ogawa Feb 3, 2026
775d164
texture transform
tatsuya-ogawa Feb 3, 2026
cfb1b65
fix build error
tatsuya-ogawa Feb 3, 2026
141fb79
add example build pipeline
tatsuya-ogawa Feb 3, 2026
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
Prev Previous commit
Next Next commit
SwiftTesting
  • Loading branch information
tatsuya-ogawa committed Feb 3, 2026
commit 84d9113bb8085c7750565d0d65a338b11400acab
73 changes: 73 additions & 0 deletions Tests/VRMKitTests/VRM1MigrationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Testing
import VRMKit
import Foundation

struct VRM1MigrationTests {

@Test func migrationToLegacyVRM() throws {
let vrm0 = try VRM(data: Resources.seedSan.data)

// Meta
#expect(vrm0.meta.title == "Seed-san")
#expect(vrm0.meta.author == "VirtualCast, Inc.")
#expect(vrm0.meta.version == "1")
#expect(vrm0.meta.texture == 14)
#expect(vrm0.meta.allowedUserName == "Everyone")
#expect(vrm0.meta.violentUssageName == "Allow")
#expect(vrm0.meta.sexualUssageName == "Allow")
#expect(vrm0.meta.commercialUssageName == "corporation")
#expect(vrm0.meta.licenseName == "https://vrm.dev/licenses/1.0/")

// Humanoid
#expect(vrm0.humanoid.humanBones.count == 51)
#expect(vrm0.humanoid.humanBones.first { $0.bone == "hips" }?.node == 3)
#expect(vrm0.humanoid.humanBones.first { $0.bone == "head" }?.node == 45)

// BlendShapeMaster
#expect(vrm0.blendShapeMaster.blendShapeGroups.count == 18)

#expect(vrm0.blendShapeMaster.blendShapeGroups.first { $0.name == "Happy" }?.presetName == "joy")
#expect(vrm0.blendShapeMaster.blendShapeGroups.first { $0.name == "Angry" }?.presetName == "angry")
#expect(vrm0.blendShapeMaster.blendShapeGroups.first { $0.name == "Sad" }?.presetName == "sorrow")
#expect(vrm0.blendShapeMaster.blendShapeGroups.first { $0.name == "Relaxed" }?.presetName == "fun")
#expect(vrm0.blendShapeMaster.blendShapeGroups.first { $0.name == "Surprised" }?.presetName == "unknown")

// FirstPerson
#expect(vrm0.firstPerson.meshAnnotations.count == 5)
#expect(vrm0.firstPerson.firstPersonBone == -1)
#expect(vrm0.firstPerson.lookAtTypeName == .blendShape)

// SecondaryAnimation (SpringBone)
#expect(vrm0.secondaryAnimation.colliderGroups.count == 6)

#expect(vrm0.secondaryAnimation.colliderGroups.contains { $0.node == 4 && $0.colliders.count == 1 })
#expect(vrm0.secondaryAnimation.colliderGroups.contains { $0.node == 5 && $0.colliders.count == 3 })

// MaterialProperties (MToon)
#expect(vrm0.materialProperties.count == 17)

// Material 0 (MToon)
let mtoon0 = vrm0.materialProperties[0]
#expect(mtoon0.shader == "VRM/MToon")

if let floatProps = mtoon0.floatProperties.value as? [String: Double] {
#expect(floatProps["_ShadingToony"] == 0.95)
#expect(floatProps["_ShadingShift"] == -0.05)
} else {
Issue.record("floatProperties type mismatch")
}

// _ShadeColor is vector
if let vectorProps = mtoon0.vectorProperties.value as? [String: [Double]] {
if let shadeColor = vectorProps["_ShadeColor"] {
#expect(shadeColor.count == 4)
// Approximate equality for double
#expect(abs(shadeColor[0] - 0.301212043) < 0.0001)
} else {
Issue.record("_ShadeColor missing")
}
} else {
Issue.record("vectorProperties type mismatch")
}
}
}
79 changes: 0 additions & 79 deletions Tests/VRMKitTests/VRM1Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1183,83 +1183,4 @@ class VRM1Tests: XCTestCase {
XCTAssertEqual(vrm.gltf.jsonData.nodes?[35].extensions?.nodeConstraint?.constraint.rotation?.weight, 1)
XCTAssertEqual(vrm.gltf.jsonData.nodes?[35].extensions?.nodeConstraint?.specVersion, "1.0")
}

func testMigrationToLegacyVRM() {
let vrm0 = try! VRM(data: Resources.seedSan.data)

// Meta
XCTAssertEqual(vrm0.meta.title, "Seed-san")
XCTAssertEqual(vrm0.meta.author, "VirtualCast, Inc.")
XCTAssertEqual(vrm0.meta.version, "1")
XCTAssertEqual(vrm0.meta.texture, 14)
XCTAssertEqual(vrm0.meta.allowedUserName, "Everyone")
XCTAssertEqual(vrm0.meta.violentUssageName, "Allow")
XCTAssertEqual(vrm0.meta.sexualUssageName, "Allow")
XCTAssertEqual(vrm0.meta.commercialUssageName, "corporation")
XCTAssertEqual(vrm0.meta.licenseName, "https://vrm.dev/licenses/1.0/")

// Humanoid
XCTAssertEqual(vrm0.humanoid.humanBones.count, 51)
XCTAssertEqual(vrm0.humanoid.humanBones.first(where: { $0.bone == "hips" })?.node, 3)
XCTAssertEqual(vrm0.humanoid.humanBones.first(where: { $0.bone == "head" })?.node, 45)

// BlendShapeMaster
// VRM1 has 5 presets (happy, angry, sad, relaxed, surprised) + 5 vowels + blink + look + neutral = many
// Migration mapping based on VRMMigration.swift:
// Happy -> joy
// Angry -> angry
// Sad -> sorrow
// Relaxed -> fun
// Surprised -> unknown

XCTAssertEqual(vrm0.blendShapeMaster.blendShapeGroups.count, 18)

XCTAssertEqual(vrm0.blendShapeMaster.blendShapeGroups.first(where: { $0.name == "Happy" })?.presetName, "joy")
XCTAssertEqual(vrm0.blendShapeMaster.blendShapeGroups.first(where: { $0.name == "Angry" })?.presetName, "angry")
XCTAssertEqual(vrm0.blendShapeMaster.blendShapeGroups.first(where: { $0.name == "Sad" })?.presetName, "sorrow")
XCTAssertEqual(vrm0.blendShapeMaster.blendShapeGroups.first(where: { $0.name == "Relaxed" })?.presetName, "fun")
XCTAssertEqual(vrm0.blendShapeMaster.blendShapeGroups.first(where: { $0.name == "Surprised" })?.presetName, "unknown")

// FirstPerson
XCTAssertEqual(vrm0.firstPerson.meshAnnotations.count, 5)
XCTAssertEqual(vrm0.firstPerson.firstPersonBone, -1)
XCTAssertEqual(vrm0.firstPerson.lookAtTypeName, .blendShape)

// SecondaryAnimation (SpringBone)
// VRM1 colliders are flattened in migration to be grouped by node.
// Node 4: 1 collider
// Node 5: 3 colliders
// Node 130, 131, 137, 138: 1 collider each
// Total groups should be 6.
XCTAssertEqual(vrm0.secondaryAnimation.colliderGroups.count, 6)

XCTAssertTrue(vrm0.secondaryAnimation.colliderGroups.contains(where: { $0.node == 4 && $0.colliders.count == 1 }))
XCTAssertTrue(vrm0.secondaryAnimation.colliderGroups.contains(where: { $0.node == 5 && $0.colliders.count == 3 }))

// MaterialProperties (MToon)
XCTAssertEqual(vrm0.materialProperties.count, 17) // glTF has 17 materials based on testMaterialsMToon (indices go up to 16)

// Material 0 (MToon)
let mtoon0 = vrm0.materialProperties[0]
XCTAssertEqual(mtoon0.shader, "VRM/MToon")

if let floatProps = mtoon0.floatProperties.value as? [String: Double] {
XCTAssertEqual(floatProps["_ShadingToony"], 0.95)
XCTAssertEqual(floatProps["_ShadingShift"], -0.05)
} else {
XCTFail("floatProperties type mismatch")
}

// _ShadeColor is vector
if let vectorProps = mtoon0.vectorProperties.value as? [String: [Double]] {
if let shadeColor = vectorProps["_ShadeColor"] {
XCTAssertEqual(shadeColor.count, 4)
XCTAssertEqual(shadeColor[0], 0.301212043, accuracy: 0.0001)
} else {
XCTFail("_ShadeColor missing")
}
} else {
XCTFail("vectorProperties type mismatch")
}
}
}
Loading