I want to make a model with added bones move by dragging it with gestures,This is a model exported using Blender,
What I understand is using IKComponent, but I don't know how to use it specifically
Hi @LazyCoder
Here's a snippet to get you started. The snippet enables you to manipulate a humanoid robot by dragging sphere's attached to its hands ands feet. The snippet uses the model available for download here. For more information on the model format, read Rigging a Model for Motion Capture.
To run the snippet, download the model and include it in your project. The snippet looks for a model named "biped_robot".
Please reach out if you have followup questions. If this answers your question please accept the answer.
Here's the source for ImmersiveView
. I'll share the code for the SampleModel
in my next response.
struct ImmersiveView: View {
@State fileprivate var model = SampleModel()
@State var subscription: EventSubscription?
@State var humanEntity = Entity()
@State var leftHandTarget:ModelEntity
@State var rightHandTarget:ModelEntity
@State var leftFootTarget:ModelEntity
@State var rightFootTarget:ModelEntity
let root = Entity()
init() {
let alpha = 0.65
leftHandTarget = Self.createTargetEntity(color: .blue.withAlphaComponent(alpha))
rightHandTarget = Self.createTargetEntity(color: .red.withAlphaComponent(alpha))
leftFootTarget = Self.createTargetEntity(color: .orange.withAlphaComponent(alpha))
rightFootTarget = Self.createTargetEntity(color: .green.withAlphaComponent(alpha))
}
var body: some View {
RealityView { content in
guard let character = try? await ModelEntity(named: "biped_robot") else {
fatalError("Failed to load character model.")
}
character.transform.translation = [0, 0, -1]
character.transform.scale = SIMD3(repeating: 1.0)
humanEntity = character
content.add(character)
try? model.setUpIK(character)
subscription = content.subscribe(to: SceneEvents.Update.self) { event in
model.updateIK()
}
root.addChild(character)
addTargetEntities()
root.position = [0, 1.5, -1]
content.add(root)
initializePositions(for: character)
}.gesture(DragGesture().targetedToAnyEntity()
.onChanged { event in
let entity = event.entity
guard let parent = entity.parent else {return}
entity.position = event.convert(event.location3D, from: .local, to: parent)
syncPositions()
}
)
}
private func addTargetEntities() {
setInitialModelPose()
root.addChild(leftHandTarget)
root.addChild(rightHandTarget)
root.addChild(leftFootTarget)
root.addChild(rightFootTarget)
}
private func setInitialModelPose() {
leftHandTarget.position = [1.014, 0.543, -1.109]
rightHandTarget.position = [-1.014, 0.543, -1.109]
leftFootTarget.position = [0.31, -1.063, -1.07]
rightFootTarget.position = [-0.31, -1.063, -1.07]
}
private func initializePositions(for character: ModelEntity) {
Task {
// wait for model to load
var attempts = 0
let maxAttempts = 10
let retryDelayInMilliseconds = 100
while model.setUpTargets(character) == false {
attempts += 1
if attempts >= maxAttempts {
fatalError("Model failed to load in time.")
}
try? await Task.sleep(for: .milliseconds(retryDelayInMilliseconds))
}
syncPositions()
}
}
private func syncPositions() {
model.setTargetPosition(limb: .leftHand, targetPosition: leftHandTarget.position(relativeTo: humanEntity))
model.setTargetPosition(limb: .rightHand, targetPosition: rightHandTarget.position(relativeTo: humanEntity))
model.setTargetPosition(limb: .leftFoot, targetPosition: leftFootTarget.position(relativeTo: humanEntity))
model.setTargetPosition(limb: .rightFoot, targetPosition: rightFootTarget.position(relativeTo: humanEntity))
}
private static func createTargetEntity(color: UIColor) -> ModelEntity {
let radius:Float = 0.05
let entity = ModelEntity(
mesh: .generateSphere(radius: radius),
materials: [SimpleMaterial(color: color, roughness: 0.9, isMetallic: false)]
)
entity.components.set(CollisionComponent(shapes: [.generateSphere(radius: radius)]))
entity.components.set(InputTargetComponent())
entity.components.set(HoverEffectComponent())
return entity
}
}