Home > front end >  How to change model's color on tap and then change it back to original?
How to change model's color on tap and then change it back to original?

Time:12-19

Im trying to create a functionality in ARKit where if the user taps on the modelEntity it changes its colour to lets say blue so it indicates that it's selected. But then if the user taps on another entity, the previously selected entity's material changes back to what it was before it was selected.

So i am able to change its colour with this code:

let selectedMaterial = SimpleMaterial(color: .link, isMetallic: false)
selectedEntity.model?.materials[0] = selectedMaterial

But how do I change it back after I 'deselect' it, when i select another modelEntity?

Because I've been trying to save it's material to a variable, but I'm having a problem with it, because lets say there are two modelEntites, A and B. When I tap the "A" entity it changes colour, then I tap on the "B" entity then "B" entity's colour changes and the "A" entity's material changes back to the original (like how it should be working), but when I tap again on the "A" entity the "B" entity's material goes back to the original but the "A" entity's colour doesn't change.

This is how I'm trying to make it work:

enum EntityState {
    case unselected
    case selected
    case correctName
    case wrongName
}

private var entitiesState: [String: EntityState] = [String: EntityState]()
private var modelEntities: [ModelEntity] = [ModelEntity]()
private var modelEntitiesMaterials: [String: [Material]] = [String: [Material]]()

//This is how i place a modelEntity
@objc private func placeObject() {
        let modelName = self.model.name ?? ""
        
        let entity = try! Entity.load(named: modelName)
        
        let geomChildrens = entity.findEntity(named: "Geom")
        
        if let geomChildrens = geomChildrens {
            for children in geomChildrens.children {
                let childModelEntity = children as! ModelEntity
                childModelEntity.collision = CollisionComponent(shapes: [ShapeResource.generateConvex(from: childModelEntity.model!.mesh)])
                entitiesState[childModelEntity.name] = EntityState.unselected
                modelEntities.append(childModelEntity)
            }
        }

        let modelEntity = ModelEntity()
        modelEntity.addChild(entity)
        
        let anchorEntity = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: .zero))
        anchorEntity.addChild(modelEntity)

        arView.installGestures([.all],for: modelEntity)

        arView.scene.addAnchor(anchorEntity)
    }

private func selectEntity(withSelectedEntity: ModelEntity?) {
        modelInformationView.isHidden = false
        //If we didnt hit any modelEntity
        guard let selectedEntity = withSelectedEntity else {
            //Unselect the selected entity if there is one.
            for entity in modelEntities {
                if(entitiesState[entity.name] == .selected) {
                    entitiesState[entity.name] = .unselected
                }
            }
            colorModelEntities()
            return
        }
                
        if(entitiesState[selectedEntity.name] == .selected) {
            // If its already selected, just unselect
            entitiesState[selectedEntity.name] = .unselected
        } else {
            //First unselect the previously selected entity.
            for entity in modelEntities {
                if(entitiesState[entity.name] == .selected) {
                    entitiesState[entity.name] = .unselected
                }
            }
            //Select the entity.
            entitiesState[selectedEntity.name] = .selected
        }
        
        colorModelEntities()
    }
    
    private func colorModelEntities() {
        let selectedMaterial = SimpleMaterial(color: .link, isMetallic: false) //Blue
        
        for entity in modelEntities {
            
            let keyExists = modelEntitiesMaterials[entity.name] != nil
            
            if keyExists {
                entity.model!.materials = modelEntitiesMaterials[entity.name]!
            }
            
            if(entitiesState[entity.name] == .selected) {
                //Color blue the selected item
                entity.model?.materials[0] = selectedMaterial
            }
        }
    }

    @objc private func handleTap(sender: UITapGestureRecognizer) {
        let tapLocation: CGPoint = sender.location(in: arView)
        let result: [CollisionCastHit] = arView.hitTest(tapLocation)
        
        guard let hitTest: CollisionCastHit = result.first, hitTest.entity.name != "Ground Plane"
        else {
            selectEntity(withSelectedEntity: nil)
            return
        }
        
        let entity: ModelEntity = hitTest.entity as! ModelEntity
        
        let keyExists = modelEntitiesMaterials[entity.name] != nil
        
        if !keyExists {
            modelEntitiesMaterials[entity.name] = entity.model!.materials
        }
        
        selectEntity(withSelectedEntity: entity)
    }

CodePudding user response:

Solution for a single model

  • Related