RealityKit – How to make an Entity and its PBR materials transparent?
Asked Answered
M

1

2

I have an Entity called "Table" that represents a table with a sticker on it. This Entity has Model Entities as children (leg1, leg2, leg3, leg4, plank and sticker). Each ModelEntity has a PBR texture applied to its materials ('lightWood' for the legs, darkWood for the plank and an image for the sticker placed on top of the table).

I would like to create a 'ghost' / transparent version of the Table entity to show before the user places it in the scene.

Is there a simple way to set the opacity of materials before or after they are created?

Is what I am trying possible without having to create a Metal shader (which I don't know how to do)?

Material for the Sticker Model Entity

    // Setup image material
    var pictureMaterial = PhysicallyBasedMaterial()
    var imageTexture: TextureResource? = nil

    if let cgImage = image?.cgImage,
        let resource = try? TextureResource.generate(from: cgImage, options: TextureResource.CreateOptions.init(semantic: nil)) {
        imageTexture = resource
    }
        
    let baseColor = MaterialParameters.Texture(imageTexture ?? StickerEntity.defaultImage)
    pictureMaterial.baseColor = PhysicallyBasedMaterial.BaseColor(texture:baseColor)


self.stickerEntity.components[ModelComponent.self] =
        ModelComponent(mesh: .generateBox(width: width!,
                                          height: self.pictureDepth,
                                          depth: height!,
                                          cornerRadius: 0,
                                          splitFaces: true),
                       materials: [canvasMaterial,
                                       pictureMaterial,
                                       canvasMaterial,
                                       canvasMaterial,
                                       canvasMaterial,
                                       canvasMaterial
                                      ])

Function I use to create PBR materials for the legs and plank

static func generateMaterialFromImages(uiColor: UIColor? = nil,
                                           baseColor: String? = nil,
                                           normal: String? = nil,
                                           roughness: String? = nil,
                                           ambientOcclusion: String? = nil,
                                           metallic: String? = nil,
                                           clearcoat: String? = nil,
                                           emissiveColor: String? = nil) -> PhysicallyBasedMaterial {
        
        var material = PhysicallyBasedMaterial()
        
        if let color = uiColor {
            material.baseColor = PhysicallyBasedMaterial.BaseColor(tint: color)
            
        } else if let resourceFileName = baseColor, let resource = try? TextureResource.load(named: resourceFileName) {
            let baseColor = MaterialParameters.Texture(resource)
            material.baseColor = PhysicallyBasedMaterial.BaseColor(texture: baseColor)
        }
        
        if let resourceFileName = normal, let resource = try? TextureResource.load(named: resourceFileName) {
            let normal = MaterialParameters.Texture(resource)
            material.normal = PhysicallyBasedMaterial.Normal(texture:normal)
        }
        if let resourceFileName = roughness, let resource = try? TextureResource.load(named: resourceFileName) {
            let roughness = MaterialParameters.Texture(resource)
            material.roughness = PhysicallyBasedMaterial.Roughness(texture:roughness)
        }
        if let resourceFileName = ambientOcclusion, let resource = try? TextureResource.load(named: resourceFileName) {
            let ambientOcclusion = MaterialParameters.Texture(resource)
            material.ambientOcclusion = PhysicallyBasedMaterial.AmbientOcclusion(texture:ambientOcclusion)
        }
        if let resourceFileName = metallic, let resource = try? TextureResource.load(named: resourceFileName) {
            let metallic = MaterialParameters.Texture(resource)
            material.metallic = PhysicallyBasedMaterial.Metallic(texture:metallic)
        }
        if let resourceFileName = clearcoat, let resource = try? TextureResource.load(named: resourceFileName) {
            let clearcoat = MaterialParameters.Texture(resource)
            material.clearcoat = PhysicallyBasedMaterial.Clearcoat(texture:clearcoat)
        }
        if let resourceFileName = emissiveColor, let resource = try? TextureResource.load(named: resourceFileName) {
            let emissiveColor = MaterialParameters.Texture(resource)
            material.emissiveColor = PhysicallyBasedMaterial.EmissiveColor(texture:emissiveColor)
        }
        
        return material
    }  

I have looked for documentation or functions that would allow to change the opacity of materials but couldn't find any documentation on the matter.

Marvelous answered 3/2, 2023 at 19:30 Comment(0)
T
2

Setting opacity of PhysicallyBasedMaterial

I used usdz table model found in Reality Composer's Furnishing section (iconic look).

Here's how I changed an opacity of PBR material.

import UIKit
import RealityKit

class ViewController : UIViewController {
    
    @IBOutlet var arView: ARView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let tableScene = try! Experience.loadTable()
        
        if let table = tableScene.findEntity(named: "table_end_base_iconic_lod0") 
                                                              as? ModelEntity {

            table.model?.materials[0] = semiTransparentShader(0.5)

            table.setPosition([0,-0.4, 0], relativeTo: nil)
        }

        arView.scene.anchors.append(tableScene)
    }
    
    func semiTransparentShader(_ value: Float) -> Material {

        var material = PhysicallyBasedMaterial()
        material.baseColor.texture = try! .init(.load(named: "image", in: nil))
        material.blending = .transparent(opacity: .init(floatLiteral: value))

        return material
    }
}

enter image description here


P. S.

In visionOS, to create a semi-transparent material has become even easier than before:

table.components[OpacityComponent.self] = .init(opacity: 0.5)
Tiffin answered 3/2, 2023 at 20:50 Comment(2)
Thanks Andy. The material.blending property was what I was looking for. I looped through the materials for the Table entity and set this property and it works like a charm. I couldn't find this anywhere...even chatGPT was spouting nonsense about this :-D Your rep is very well deserved.Marvelous
ChatGPT is still in its infancy ))Tiffin

© 2022 - 2024 — McMap. All rights reserved.