Get coordinates of pivot point in ModelEntity

I'd like to know the location of the pivot point of a ModelEntity, is there any way to get this? Alternatively can I get it from a USDZ file?

I want to place models in a specific location and some models have the pivot in the center while others have it at the bottom. If I can detect this I can adjust accordingly and place them correctly. I don't have control over the models, alas. Thanks, Spiff

Answered by arthurfromberlin in 709400022

Hi,

as far as I know there is currently no way to retrieve the pivot point directly. What you can do though is to query the bounding box and then calculate a Y-Offset based on the min and max positions of the bounding boxes corners and set that as the position of the entity. Now when you wrap it into another empty parent entity, you should have the desired effect.

public extension Entity {

    enum PivotPosition {
        case top
        case center
        case bottom
    }

    func wrapEntityAndSetPivotPosition(to targetPosition: PivotPosition) -> Entity {
        setPivotPosition(to: targetPosition, animated: false)

        let entity = Entity()
        entity.addChild(self)
        return entity
    }

    func setPivotPosition(to targetPosition: PivotPosition, animated: Bool = false) {
        let boundingBox = visualBounds(relativeTo: nil)
        let min = boundingBox.min
        let max = boundingBox.max

        let yTranslation: Float

        switch targetPosition {
        case .top:
            yTranslation = -max.y
        case .center:
            yTranslation = -(min.y + (max.y - min.y) / 2)
        case .bottom:
            yTranslation = -min.y
        }

        let targetPosition = simd_float3(
            x: boundingBox.center.x * -1,
            y: yTranslation,
            z: boundingBox.center.z * -1
        )

        guard animated else {
            position = targetPosition
            return
        }

        guard isAnchored, parent != nil else {
            print("Warning: to set the Entities pivot position animated make sure it is already anchored and has a parent set.")
            return
        }

        var translationTransform = transform
        translationTransform.translation = targetPosition
        move(to: translationTransform, relativeTo: parent, duration: 0.3, timingFunction: .easeOut)
    }
}

And the whole thing in action:

        let boxModel = ModelEntity(mesh: .generateBox(size: 0.3))
        let wrappedBoxEntity = boxModel.wrapEntityAndSetPivotPosition(to: .bottom)
        let boxAnchor = AnchorEntity(plane: .horizontal)
        boxAnchor.addChild(wrappedBoxEntity)

        arView.scene.anchors.append(boxAnchor)

I agree though that there should be a dedicated API for this – as we have in SceneKit. I filed feedback a while ago.

Accepted Answer

Hi,

as far as I know there is currently no way to retrieve the pivot point directly. What you can do though is to query the bounding box and then calculate a Y-Offset based on the min and max positions of the bounding boxes corners and set that as the position of the entity. Now when you wrap it into another empty parent entity, you should have the desired effect.

public extension Entity {

    enum PivotPosition {
        case top
        case center
        case bottom
    }

    func wrapEntityAndSetPivotPosition(to targetPosition: PivotPosition) -> Entity {
        setPivotPosition(to: targetPosition, animated: false)

        let entity = Entity()
        entity.addChild(self)
        return entity
    }

    func setPivotPosition(to targetPosition: PivotPosition, animated: Bool = false) {
        let boundingBox = visualBounds(relativeTo: nil)
        let min = boundingBox.min
        let max = boundingBox.max

        let yTranslation: Float

        switch targetPosition {
        case .top:
            yTranslation = -max.y
        case .center:
            yTranslation = -(min.y + (max.y - min.y) / 2)
        case .bottom:
            yTranslation = -min.y
        }

        let targetPosition = simd_float3(
            x: boundingBox.center.x * -1,
            y: yTranslation,
            z: boundingBox.center.z * -1
        )

        guard animated else {
            position = targetPosition
            return
        }

        guard isAnchored, parent != nil else {
            print("Warning: to set the Entities pivot position animated make sure it is already anchored and has a parent set.")
            return
        }

        var translationTransform = transform
        translationTransform.translation = targetPosition
        move(to: translationTransform, relativeTo: parent, duration: 0.3, timingFunction: .easeOut)
    }
}

And the whole thing in action:

        let boxModel = ModelEntity(mesh: .generateBox(size: 0.3))
        let wrappedBoxEntity = boxModel.wrapEntityAndSetPivotPosition(to: .bottom)
        let boxAnchor = AnchorEntity(plane: .horizontal)
        boxAnchor.addChild(wrappedBoxEntity)

        arView.scene.anchors.append(boxAnchor)

I agree though that there should be a dedicated API for this – as we have in SceneKit. I filed feedback a while ago.

That's great, arthurfromberlin. Thank you!

@arthurfromberlin - what is the feedback ID for the pivot API?

Get coordinates of pivot point in ModelEntity
 
 
Q