RealityKit如何使Entity及其PBR材质实现透明(幽灵效果)?
问题
我有一个名为“Table”的Entity,代表带有贴纸的桌子,它包含多个子ModelEntity(leg1、leg2、leg3、leg4、plank和sticker),每个ModelEntity都应用了PBR纹理材质(桌腿为lightWood,桌板为darkWood,贴纸为图片材质)。我希望创建该Table Entity的“幽灵/透明”版本,在用户将其放置到场景前展示。请问是否有简单方法可在材质创建前后设置不透明度?是否无需编写Metal shader(我不会编写)即可实现此需求?
贴纸ModelEntity的材质代码
// 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 ])
用于创建桌腿和桌板PBR材质的函数
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 }
我查找了可更改材质不透明度的文档或函数,但未找到相关内容。
解决方案
完全不需要编写Metal shader就能实现,有两种简单的方式可以给你的Table Entity设置透明效果:
方式一:修改材质的基础颜色透明度
不管是用tint还是纹理创建的PBR材质,都可以通过调整基础颜色的alpha通道来控制透明度:
- 针对纯色基础材质:如果你的材质是用
UIColor创建的,直接创建带alpha的颜色即可:
// 设置50%透明度的木质色 let transparentWoodColor = UIColor(red: 0.7, green: 0.5, blue: 0.3, alpha: 0.5) let legMaterial = generateMaterialFromImages(uiColor: transparentWoodColor)
- 针对纹理基础材质:可以给纹理叠加带透明度的tint,不改变纹理本身颜色的前提下添加透明效果:
// 假设已加载好桌板纹理资源 if let darkWoodResource = try? TextureResource.load(named: "darkWood") { let baseColor = PhysicallyBasedMaterial.BaseColor(texture: darkWoodResource) // 叠加50%透明度的白色tint baseColor.tint = UIColor.white.withAlphaComponent(0.5) var plankMaterial = PhysicallyBasedMaterial() plankMaterial.baseColor = baseColor // 其他PBR属性保持不变 }
对于贴纸材质,同样可以用这个方法:
pictureMaterial.baseColor?.tint = UIColor.white.withAlphaComponent(0.5)
方式二:使用Entity的opacity属性
每个Entity都自带opacity属性,直接设置这个值可以让整个实体(包括所有子Entity)变成半透明,这是最快捷的幽灵效果实现方式:
// 设置整个Table实体为50%透明 tableEntity.opacity = 0.5
这个方法不需要修改任何材质,直接作用于整个实体层级,适合快速创建放置前的预览效果。如果需要部分子实体保持不透明,单独给这些子实体设置opacity = 1.0即可覆盖父实体的设置。
关键注意事项
确保你的ModelComponent的isOpaque属性设为false,否则透明度设置可能不会生效:
// 给贴纸实体设置非透明标记 if var modelComponent = self.stickerEntity.components[ModelComponent.self] { modelComponent.isOpaque = false self.stickerEntity.components[ModelComponent.self] = modelComponent }
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

