1

I have a 3D Model (USDZ) in RealityKit that has one PBR material. I can select the model via UILongPressGestureRecognizer. When I select it I need the 3D Model to change color, so the user knows that is been selected. I have kind of got it to work by appending a UnlitMaterial which is Orange to the model, then assigning it to material[0] and the PBR to material[1]. Once the 3D Model has been selected, the user unselects the model by LongPress again and the 2 materials are swapped and the last is deleted. This works ok first time round, if I start the process again (2 time round) the 'UnlitMaterial' is White. On the 3rd time round its Orange?

I tried to placing the var simpleMat = UnlitMaterial(color: .orange) at different positions in the 'If Statements', because I think when the unlit is white its somehow not correctly assigning the orange color, its just a UnlitMaterial with no color.

@objc func handleLongPress(recognizer: UILongPressGestureRecognizer)  {
    
    
let location = recognizer.location(in: arView)
    
    if let entity = arView.entity(at: location){
     
    
        if let anchorEntity = entity.anchor{
            
            currectAnchorEntity = anchorEntity
          
          
         
            switch recognizer.state {
              case .began:
               
                //if the model/object is not currently selected and nothing assigned to currentModelEntity (when you first start AR session)
                if currentModelEntity != entity && currentModelEntity.children.isEmpty {
                
                  
                    var simpleMat = UnlitMaterial(color: .orange)
      
                    //---   1   making it the current
                    currentModelEntity = entity
                    
                    //---   2  finding the model
                    entModel = (entity.findEntity(named: "model") as? ModelEntity)!
                    
                    //---   3  Adding the unlitmaterial colour materal to material [1]
                    entModel.model?.materials.append(simpleMat)
                
                    //--    4  Assigning Varibles to [0] & [1] for reference
                    let matLastL = entModel.model?.materials.last
                    let matLastF = entModel.model?.materials.first
             
                    //---   5  Swaps the materials on the model, so i can keep the original material
                    entModel.model?.materials[1] = matLastF!
                    entModel.model?.materials[0] = simpleMat
          
                    //---   6  Unhides the menu
                    objectMenu.isHidden = false

                    recognizer.state = .cancelled
                    
                }
                
                
                // not the current model but there is another model that is selcted which is the 'CurrentModelEntity'
                else if currentModelEntity != entity && currentModelEntity.children.count == 1 {
                
               
                    //---   1  finding the model on currently selected model
                    entModel = (currentModelEntity.findEntity(named: "model") as? ModelEntity)!
             
                    //---   2  Assigning Varibles to [0] & [1] for reference
                    let matLastL = entModel.model?.materials.last
                    let matLastF = entModel.model?.materials.first
                    
                    //---   3  Assigning the last material(original) to [0] slot
                    entModel.model?.materials[0] = matLastL!
                     
                    //---   4  Removing the 'UnlitMaterial' from [1]
                    entModel.model?.materials.remove(at: 1)
                    
                    //---   5 Unassigning the currentModel
                    currentModelEntity = Entity()
                    
                    //---   6  Hinding the menu
                    objectMenu.isHidden = true
                    
                    //---   7  stopping the touches
                    recognizer.state = .cancelled
                
                }
                
                
                // is the 'CurrentModelEntity'- at this point the materials are Unlit=[0], Original=[1]
                else if currentModelEntity == entity  && currentModelEntity.children.count == 1{
                  
                    
                    //---    1  finding the model on currently selected model
                    entModel = (entity.findEntity(named: "model") as? ModelEntity)!
                    
                    //---    2  Assigning Varibles to [0] & [1] for reference
                    let matLastL = entModel.model?.materials.last
                    let matLastF = entModel.model?.materials.first
                    
                    //---    3  Swaps the materials on the model
                    entModel.model?.materials[1] = matLastF!
                    entModel.model?.materials[0] = matLastL!
                    
                    //---    4  Remove the simpleMat from slot 1
                    entModel.model?.materials.remove(at: 1)
                  
                    //---    5  Hinding the menu
                    objectMenu.isHidden = true
                    
                    //---    6  Unasigning the current model
                    currentModelEntity = Entity()
                  
                    //---    7  stopping the touches
                    recognizer.state = .cancelled
                    
                }
           
            case .ended, .cancelled: break   
            default: break
               
            }
        }
    } 
}
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
CodeChris
  • 41
  • 4

1 Answers1

1

Use the following strategy to achieve the desired result.

This answer will also be helpful.

import SwiftUI
import RealityKit

struct ARViewContainer : UIViewRepresentable {

    @Binding var index: Int
    let arView = ARView(frame: .zero)
    let teapot = try! Entity.loadModel(named: "teapot.usdz")

    let unlit = UnlitMaterial(color: .systemPink)
    let metal = SimpleMaterial(color: .white, isMetallic: true)
    
    func makeUIView(context: Context) -> ARView {
        let anchor = AnchorEntity()
        anchor.position.z += 1.0
        anchor.position.y = -0.2
        anchor.addChild(teapot)
        arView.scene.anchors.append(anchor)
        return arView
    }
    func updateUIView(_ view: ARView, context: Context) {
        switch index {
            case 0: teapot.model?.materials[0] = metal
            case 1: teapot.model?.materials[0] = unlit
            default: break
        }
    }
}

enter image description here

struct ContentView : View {
    
    @State private var switcher: Bool = false
    @State private var index: Int = 0
    
    var body: some View {
        ARViewContainer(index: $index)
            .ignoresSafeArea()
            .onLongPressGesture {       // Screen Long Press Gesture
                switcher.toggle()
                switcher ? (index = 1) : (index = 0)
            }
    }
}
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220