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
}
}